]> granicus.if.org Git - php/commitdiff
Fix ref source management during unserialization
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 25 Nov 2020 11:25:07 +0000 (12:25 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 25 Nov 2020 11:25:07 +0000 (12:25 +0100)
Only register the slot for adding ref sources later if we didn't
immediately register one. Also avoids leaking a ref source if
it is added early and the assignment fails.

Fixes oss-fuzz #27628.

ext/standard/tests/serialize/typed_property_ref_assignment_failure.phpt [new file with mode: 0644]
ext/standard/var_unserializer.re

diff --git a/ext/standard/tests/serialize/typed_property_ref_assignment_failure.phpt b/ext/standard/tests/serialize/typed_property_ref_assignment_failure.phpt
new file mode 100644 (file)
index 0000000..2e4b576
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+Failure to assign ref to typed property
+--FILE--
+<?php
+
+class Test {
+    public int $prop;
+}
+
+$s = <<<'STR'
+O:4:"Test":1:{s:4:"prop";O:8:"stdClass":1:{s:1:"y";R:2;}}
+STR;
+try {
+    var_dump(unserialize($s));
+} catch (Error $e) {
+    echo $e->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Cannot assign stdClass to property Test::$prop of type int
index 6680e00645a4df179ea4eef092a30fa8010d70cc..0143d94c704805dbd79f12c514bcb758b486ac0f 100644 (file)
@@ -560,17 +560,6 @@ string_key:
                                                Z_TRY_DELREF_P(old_data);
                                                ZVAL_COPY_VALUE(old_data, &d);
                                                data = old_data;
-
-                                               if (UNEXPECTED(info)) {
-                                                       /* Remember to which property this slot belongs, so we can add a
-                                                        * type source if it is turned into a reference lateron. */
-                                                       if (!(*var_hash)->ref_props) {
-                                                               (*var_hash)->ref_props = emalloc(sizeof(HashTable));
-                                                               zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
-                                                       }
-                                                       zend_hash_index_update_ptr(
-                                                               (*var_hash)->ref_props, (zend_uintptr_t) data, info);
-                                               }
                                        } else {
                                                var_push_dtor(var_hash, old_data);
                                                data = zend_hash_update_ind(ht, Z_STR(key), &d);
@@ -600,8 +589,18 @@ string_key:
                                zval_ptr_dtor_nogc(&key);
                                goto failure;
                        }
+
                        if (Z_ISREF_P(data)) {
                                ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
+                       } else {
+                               /* Remember to which property this slot belongs, so we can add a
+                                * type source if it is turned into a reference lateron. */
+                               if (!(*var_hash)->ref_props) {
+                                       (*var_hash)->ref_props = emalloc(sizeof(HashTable));
+                                       zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
+                               }
+                               zend_hash_index_update_ptr(
+                                       (*var_hash)->ref_props, (zend_uintptr_t) data, info);
                        }
                }