Commit ab99a29383d for php.net
commit ab99a29383d7434fb6a8d7eac7fe3c16013e6fd9
Author: David Carlier <devnexen@gmail.com>
Date: Sat Jun 27 05:12:03 2026 +0100
Zend: reset typed property default on every unserialize failure path.
GH-22263 follow-up
Close GH-22481
diff --git a/NEWS b/NEWS
index 7a00f15c2ba..de11135f0d3 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ PHP NEWS
- Core:
. Implemented partial function application RFC. (Arnaud)
+ . Fixed bug GH-22263 (reset typed property default on every unserialize
+ failure path). (David Carlier)
- DOM:
. Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD
diff --git a/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt b/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt
new file mode 100644
index 00000000000..2380c8e5550
--- /dev/null
+++ b/Zend/tests/unserialize_typed_prop_reset_on_failure.phpt
@@ -0,0 +1,37 @@
+--TEST--
+unserialize() resets a typed property to its default on every failure path
+--FILE--
+<?php
+/* A typed property whose value fails to unserialize is reset to its default, on
+ * every failure path, so a partially built object can never expose a value that
+ * violates the declared type. */
+
+/* Failure while building the typed "array $trace", exposed through SplHeap's
+ * delayed __unserialize(): the slot is reset, so getTraceAsString() no longer
+ * reinterprets the object as a HashTable. */
+$n = "\x00";
+try {
+ unserialize(
+ 'O:9:"Exception":1:{s:16:"' . $n . 'Exception' . $n . 'trace";' .
+ 'O:8:"stdClass":2:{s:1:"0";O:10:"SplMaxHeap":2:{i:0;a:0:{}i:1;a:2:{' .
+ 's:5:"flags";i:0;s:13:"heap_elements";a:2:{i:0;s:0:"";i:1;R:1;}}}z}}'
+ );
+} catch (\Throwable $e) {
+ for (; $e; $e = $e->getPrevious()) {
+ printf("%s: %s\n", $e::class, $e->getMessage());
+ }
+}
+
+/* By-ref type violation: the slot is reset to its default. */
+class C { public array $a; }
+try {
+ var_dump(unserialize('O:1:"C":1:{s:1:"a";R:1;}'));
+} catch (\Throwable $e) {
+ printf("%s: %s\n", $e::class, $e->getMessage());
+}
+echo "OK\n";
+?>
+--EXPECTF--
+Warning: unserialize(): Error at offset %d of %d bytes in %s on line %d
+TypeError: %s
+OK
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 4a9b278c116..a9f1f96f366 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -689,11 +689,7 @@ second_try:
if (!php_var_unserialize_internal(data, p, max, var_hash)) {
if (info) {
- if (Z_ISREF_P(data)) {
- ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
- } else {
- var_restore_prop_default(var_hash, obj, info, data);
- }
+ var_restore_prop_default(var_hash, obj, info, data);
}
goto failure;
}