From 6d66a7afd5a722cd6a5ad6bcbcddd6779b188cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 17 Aug 2022 11:47:37 +0200 Subject: [PATCH 01/11] Fix GH-9186 @strict-properties can be bypassed using unserialization Co-Authored-By: Tyson Andre --- Zend/tests/gc_043.phpt | 3 +- .../readonly_class_unserialize_error.phpt | 16 ++++++++ Zend/zend_API.c | 40 +++++++++++++++++++ Zend/zend_API.h | 2 + Zend/zend_object_handlers.c | 24 ----------- ext/random/engine_mt19937.c | 3 ++ ext/random/randomizer.c | 7 +++- .../03_randomizer/gh_9186_unserialize.phpt | 14 +++++++ ext/spl/spl_array.c | 3 ++ ext/standard/basic_functions.stub.php | 1 + ext/standard/basic_functions_arginfo.h | 8 +++- ext/standard/tests/serialize/bug49649.phpt | 7 +++- ext/standard/tests/serialize/bug49649_1.phpt | 7 +++- ext/standard/tests/serialize/bug49649_2.phpt | 7 +++- ext/standard/tests/serialize/bug62836_1.phpt | 2 +- ext/standard/tests/serialize/bug62836_2.phpt | 2 +- ext/standard/tests/serialize/bug72663.phpt | 2 + .../serialization_objects_incomplete.phpt | 15 +++++++ ...ialize_overwrite_undeclared_protected.phpt | 3 +- ext/standard/var_unserializer.re | 9 +++++ 20 files changed, 140 insertions(+), 35 deletions(-) create mode 100644 Zend/tests/readonly_classes/readonly_class_unserialize_error.phpt create mode 100644 ext/random/tests/03_randomizer/gh_9186_unserialize.phpt create mode 100644 ext/standard/tests/serialize/serialization_objects_incomplete.phpt diff --git a/Zend/tests/gc_043.phpt b/Zend/tests/gc_043.phpt index 06b64de39acf9..37906a025145f 100644 --- a/Zend/tests/gc_043.phpt +++ b/Zend/tests/gc_043.phpt @@ -8,7 +8,8 @@ STR; var_dump(unserialize($s)); gc_collect_cycles(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Creation of dynamic property RegexIterator::$5 is deprecated in %s on line %d object(stdClass)#1 (2) { ["5"]=> object(SplStack)#2 (2) { diff --git a/Zend/tests/readonly_classes/readonly_class_unserialize_error.phpt b/Zend/tests/readonly_classes/readonly_class_unserialize_error.phpt new file mode 100644 index 0000000000000..e0672e4d97f80 --- /dev/null +++ b/Zend/tests/readonly_classes/readonly_class_unserialize_error.phpt @@ -0,0 +1,16 @@ +--TEST-- +Fix GH-9186 Readonly classes can have dynamic properties created by unserialize() +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot create dynamic property C::$x diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 56db031102095..b4b0fa0ffdf6e 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1587,6 +1587,28 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti } /* }}} */ +ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member) { + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(ce->name), ZSTR_VAL(member)); +} + +ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member) { + GC_ADDREF(obj); + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_class_entry *ce = obj->ce; + zend_objects_store_del(obj); + if (!EG(exception)) { + /* We cannot continue execution and have to throw an exception */ + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(ce->name), ZSTR_VAL(member)); + } + return 0; + } + return 1; +} + ZEND_API void object_properties_load(zend_object *object, HashTable *properties) /* {{{ */ { zval *prop, tmp; @@ -1628,6 +1650,15 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) zend_hash_update(object->properties, key, &tmp); } } else { + if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { + zend_forbidden_dynamic_property(object->ce, key); + return; + } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + if (!zend_deprecated_dynamic_property(object, key)) { + return; + } + } + if (!object->properties) { rebuild_object_properties(object); } @@ -1635,6 +1666,15 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) zval_add_ref(prop); } } else { + if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { + zend_forbidden_dynamic_property(object->ce, key); + return; + } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + if (!zend_deprecated_dynamic_property(object, key)) { + return; + } + } + if (!object->properties) { rebuild_object_properties(object); } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index fa8c1162788f1..e86c260146673 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -522,6 +522,8 @@ ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type); ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties); +ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member); +ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member); ZEND_API void object_properties_load(zend_object *object, HashTable *properties); ZEND_API void zend_merge_properties(zval *obj, HashTable *properties); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index d0677f0fe4e96..a11b5578bb57d 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -275,30 +275,6 @@ static ZEND_COLD zend_never_inline void zend_bad_property_name(void) /* {{{ */ } /* }}} */ -static ZEND_COLD zend_never_inline void zend_forbidden_dynamic_property( - zend_class_entry *ce, zend_string *member) { - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(ce->name), ZSTR_VAL(member)); -} - -static ZEND_COLD zend_never_inline bool zend_deprecated_dynamic_property( - zend_object *obj, zend_string *member) { - GC_ADDREF(obj); - zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_class_entry *ce = obj->ce; - zend_objects_store_del(obj); - if (!EG(exception)) { - /* We cannot continue execution and have to throw an exception */ - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(ce->name), ZSTR_VAL(member)); - } - return 0; - } - return 1; -} - static ZEND_COLD zend_never_inline void zend_readonly_property_modification_scope_error( zend_class_entry *ce, zend_string *member, zend_class_entry *scope, const char *operation) { zend_throw_error(NULL, "Cannot %s readonly property %s::$%s from %s%s", diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index 266ec5ea11c24..11f97d35291a2 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -365,6 +365,9 @@ PHP_METHOD(Random_Engine_Mt19937, __unserialize) RETURN_THROWS(); } object_properties_load(&engine->std, Z_ARRVAL_P(t)); + if (EG(exception)) { + RETURN_THROWS(); + } /* state */ t = zend_hash_index_find(d, 1); diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index c94c9449db93d..074fbc5020556 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -90,7 +90,7 @@ PHP_METHOD(Random_Randomizer, __construct) /* {{{ Generate positive random number */ PHP_METHOD(Random_Randomizer, nextInt) -{ +{ php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS); uint64_t result; @@ -104,7 +104,7 @@ PHP_METHOD(Random_Randomizer, nextInt) zend_throw_exception(random_ce_Random_RandomException, "Generated value exceeds size of int", 0); RETURN_THROWS(); } - + RETURN_LONG((zend_long) (result >> 1)); } /* }}} */ @@ -278,6 +278,9 @@ PHP_METHOD(Random_Randomizer, __unserialize) RETURN_THROWS(); } object_properties_load(&randomizer->std, Z_ARRVAL_P(members_zv)); + if (EG(exception)) { + RETURN_THROWS(); + } zengine = zend_read_property(randomizer->std.ce, &randomizer->std, "engine", strlen("engine"), 1, NULL); if (Z_TYPE_P(zengine) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(zengine), random_ce_Random_Engine)) { diff --git a/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt new file mode 100644 index 0000000000000..e11d4d33a45c0 --- /dev/null +++ b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt @@ -0,0 +1,14 @@ +--TEST-- +Fix GH-9186 @strict-properties can be bypassed using unserialization +--FILE-- +getMessage() . "\n"; +} + +?> +--EXPECT-- +Cannot create dynamic property Random\Randomizer::$foo diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 64721ab42effd..991fa88ded64a 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1740,6 +1740,9 @@ PHP_METHOD(ArrayObject, __unserialize) } object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); + if (EG(exception)) { + RETURN_THROWS(); + } if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) { zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv)); diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6166cf6587bb6..7a6ee00d8e49c 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -343,6 +343,7 @@ */ const PHP_ROUND_HALF_ODD = UNKNOWN; +#[AllowDynamicProperties] final class __PHP_Incomplete_Class { } diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index d3dd087e83a83..4469a5b07ee08 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 0411f358f211eb9173272c6f296899d349ab5971 */ + * Stub hash: 4df5576b4e03b18896abf58e6c70d9fd6ae76687 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3578,7 +3578,11 @@ static zend_class_entry *register_class___PHP_Incomplete_Class(void) INIT_CLASS_ENTRY(ce, "__PHP_Incomplete_Class", class___PHP_Incomplete_Class_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); - class_entry->ce_flags |= ZEND_ACC_FINAL; + class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES; + + zend_string *attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class = zend_string_init_interned("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1); + zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class, 0); + zend_string_release(attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class); return class_entry; } diff --git a/ext/standard/tests/serialize/bug49649.phpt b/ext/standard/tests/serialize/bug49649.phpt index 7bbba03c1492e..46e303e82415c 100644 --- a/ext/standard/tests/serialize/bug49649.phpt +++ b/ext/standard/tests/serialize/bug49649.phpt @@ -33,7 +33,12 @@ class Foo $class = unserialize(base64_decode($serialized)); var_dump($class); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public"]=> int(3) diff --git a/ext/standard/tests/serialize/bug49649_1.phpt b/ext/standard/tests/serialize/bug49649_1.phpt index e4f01d3039d5a..6b9c2552451c8 100644 --- a/ext/standard/tests/serialize/bug49649_1.phpt +++ b/ext/standard/tests/serialize/bug49649_1.phpt @@ -33,7 +33,12 @@ class Foo $class = unserialize(base64_decode($serialized)); var_dump($class); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public":protected]=> int(3) diff --git a/ext/standard/tests/serialize/bug49649_2.phpt b/ext/standard/tests/serialize/bug49649_2.phpt index 93b5e298f993e..6efcedae050b1 100644 --- a/ext/standard/tests/serialize/bug49649_2.phpt +++ b/ext/standard/tests/serialize/bug49649_2.phpt @@ -33,7 +33,12 @@ class Foo $class = unserialize(base64_decode($serialized)); var_dump($class); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d + +Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public":"Foo":private]=> int(3) diff --git a/ext/standard/tests/serialize/bug62836_1.phpt b/ext/standard/tests/serialize/bug62836_1.phpt index 7d03e9fd187bd..480dbab1df127 100644 --- a/ext/standard/tests/serialize/bug62836_1.phpt +++ b/ext/standard/tests/serialize/bug62836_1.phpt @@ -5,7 +5,7 @@ Bug #62836 (Seg fault or broken object references on unserialize()) $serialized_object='O:1:"A":4:{s:1:"b";O:1:"B":0:{}s:2:"b1";r:2;s:1:"c";O:1:"B":0:{}s:2:"c1";r:4;}'; spl_autoload_register(function ($name) { unserialize("i:4;"); - eval("class $name {} "); + eval("#[AllowDynamicProperties] class $name {} "); }); print_r(unserialize($serialized_object)); diff --git a/ext/standard/tests/serialize/bug62836_2.phpt b/ext/standard/tests/serialize/bug62836_2.phpt index 0634b1dac135b..95bd75bb6fb87 100644 --- a/ext/standard/tests/serialize/bug62836_2.phpt +++ b/ext/standard/tests/serialize/bug62836_2.phpt @@ -8,7 +8,7 @@ ini_set('unserialize_callback_func','mycallback'); function mycallback($classname) { unserialize("i:4;"); - eval ("class $classname {} "); + eval ("#[AllowDynamicProperties] class $classname {} "); } print_r(unserialize($serialized_object)); diff --git a/ext/standard/tests/serialize/bug72663.phpt b/ext/standard/tests/serialize/bug72663.phpt index c50591ca963f4..9c006d50d80ba 100644 --- a/ext/standard/tests/serialize/bug72663.phpt +++ b/ext/standard/tests/serialize/bug72663.phpt @@ -3,6 +3,7 @@ Bug #72663 (1): Don't call __destruct if __wakeup not called or fails --FILE-- +--EXPECT-- +object(__PHP_Incomplete_Class)#1 (2) { + ["__PHP_Incomplete_Class_Name"]=> + string(1) "C" + ["p"]=> + int(1) +} diff --git a/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt b/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt index b442c922c4153..ee9bfab62fe45 100644 --- a/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt +++ b/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt @@ -12,7 +12,8 @@ O:4:"Test":2:{s:4:"\0*\0x";N;s:4:"\0*\0x";N;} STR; var_dump(unserialize($str)); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Creation of dynamic property Test::$ is deprecated in %s on line %d object(Test)#1 (2) { ["foo"]=> NULL diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 0556d5522ce5d..c9dd715f08da2 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -638,6 +638,15 @@ declared_property: } } } else { + if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { + zend_forbidden_dynamic_property(obj->ce, Z_STR_P(&key)); + goto failure; + } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + if (!zend_deprecated_dynamic_property(obj, Z_STR_P(&key))) { + goto failure; + } + } + int ret = is_property_visibility_changed(obj->ce, &key); if (EXPECTED(!ret)) { From 08698825f2ba8c0eda4310839d493c7d98c63007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Thu, 18 Aug 2022 13:48:20 +0200 Subject: [PATCH 02/11] Fix tests and review suggestions --- Zend/zend_API.c | 38 ++++--------------- Zend/zend_API.h | 2 - Zend/zend_object_handlers.c | 22 +++++++++++ ext/gmp/tests/serialize.phpt | 2 + ext/session/tests/003.phpt | 1 + ext/session/tests/004.phpt | 1 + ext/session/tests/005.phpt | 1 + ext/session/tests/023.phpt | 1 + ext/session/tests/024.phpt | 1 + ext/session/tests/025.phpt | 1 + ext/soap/tests/bug70388.phpt | 2 + ext/soap/tests/bugs/bug69085.phpt | 1 + ext/standard/tests/serialize/bug49649.phpt | 4 +- ext/standard/tests/serialize/bug49649_1.phpt | 2 +- ext/standard/tests/serialize/bug49649_2.phpt | 2 +- ...ialize_overwrite_undeclared_protected.phpt | 2 +- ...lize_ref_to_overwritten_declared_prop.phpt | 4 +- ext/standard/var_unserializer.re | 8 ++-- 18 files changed, 52 insertions(+), 43 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index b4b0fa0ffdf6e..f986c3455e1f2 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1587,28 +1587,6 @@ ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properti } /* }}} */ -ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member) { - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(ce->name), ZSTR_VAL(member)); -} - -ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member) { - GC_ADDREF(obj); - zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_class_entry *ce = obj->ce; - zend_objects_store_del(obj); - if (!EG(exception)) { - /* We cannot continue execution and have to throw an exception */ - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(ce->name), ZSTR_VAL(member)); - } - return 0; - } - return 1; -} - ZEND_API void object_properties_load(zend_object *object, HashTable *properties) /* {{{ */ { zval *prop, tmp; @@ -1651,12 +1629,12 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) } } else { if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_forbidden_dynamic_property(object->ce, key); + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); return; } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - if (!zend_deprecated_dynamic_property(object, key)) { - return; - } + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); } if (!object->properties) { @@ -1667,12 +1645,12 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) } } else { if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_forbidden_dynamic_property(object->ce, key); + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); return; } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - if (!zend_deprecated_dynamic_property(object, key)) { - return; - } + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); } if (!object->properties) { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index e86c260146673..fa8c1162788f1 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -522,8 +522,6 @@ ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce); ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties); ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type); ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties); -ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member); -ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member); ZEND_API void object_properties_load(zend_object *object, HashTable *properties); ZEND_API void zend_merge_properties(zval *obj, HashTable *properties); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index a11b5578bb57d..1a76f35d6689e 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -275,6 +275,28 @@ static ZEND_COLD zend_never_inline void zend_bad_property_name(void) /* {{{ */ } /* }}} */ +ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member) { + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(ce->name), ZSTR_VAL(member)); +} + +ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member) { + GC_ADDREF(obj); + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_class_entry *ce = obj->ce; + zend_objects_store_del(obj); + if (!EG(exception)) { + /* We cannot continue execution and have to throw an exception */ + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(ce->name), ZSTR_VAL(member)); + } + return 0; + } + return 1; +} + static ZEND_COLD zend_never_inline void zend_readonly_property_modification_scope_error( zend_class_entry *ce, zend_string *member, zend_class_entry *scope, const char *operation) { zend_throw_error(NULL, "Cannot %s readonly property %s::$%s from %s%s", diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt index 65c2f34e13d17..84877459a9bc0 100644 --- a/ext/gmp/tests/serialize.phpt +++ b/ext/gmp/tests/serialize.phpt @@ -54,6 +54,8 @@ object(GMP)#%d (1) { Deprecated: Creation of dynamic property GMP::$foo is deprecated in %s on line %d string(56) "O:3:"GMP":2:{i:0;s:1:"d";i:1;a:1:{s:3:"foo";s:3:"bar";}}" + +Deprecated: Creation of dynamic property GMP::$foo is deprecated in %s on line %d object(GMP)#%d (2) { ["foo"]=> string(3) "bar" diff --git a/ext/session/tests/003.phpt b/ext/session/tests/003.phpt index c0628e28abdd9..ab1739edf6b76 100644 --- a/ext/session/tests/003.phpt +++ b/ext/session/tests/003.phpt @@ -16,6 +16,7 @@ error_reporting(E_ALL); class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/session/tests/004.phpt b/ext/session/tests/004.phpt index 0901286001808..d6b53072c1633 100644 --- a/ext/session/tests/004.phpt +++ b/ext/session/tests/004.phpt @@ -52,6 +52,7 @@ $hnd = new handler; class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/session/tests/005.phpt b/ext/session/tests/005.phpt index 6c7f246a3630a..c4083557866e3 100644 --- a/ext/session/tests/005.phpt +++ b/ext/session/tests/005.phpt @@ -53,6 +53,7 @@ $hnd = new handler; class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/session/tests/023.phpt b/ext/session/tests/023.phpt index 78f6e41c7e790..092f8db64b790 100644 --- a/ext/session/tests/023.phpt +++ b/ext/session/tests/023.phpt @@ -16,6 +16,7 @@ error_reporting(E_ALL); class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/session/tests/024.phpt b/ext/session/tests/024.phpt index b0f819b9d0d2f..c307d79a6873b 100644 --- a/ext/session/tests/024.phpt +++ b/ext/session/tests/024.phpt @@ -53,6 +53,7 @@ $hnd = new handler; class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/session/tests/025.phpt b/ext/session/tests/025.phpt index b18715af36651..5f9a5ad591c7d 100644 --- a/ext/session/tests/025.phpt +++ b/ext/session/tests/025.phpt @@ -54,6 +54,7 @@ $hnd = new handler; class foo { public $bar = "ok"; + public $yes; function method() { $this->yes++; } } diff --git a/ext/soap/tests/bug70388.phpt b/ext/soap/tests/bug70388.phpt index 87259bf45d50a..8f3e8be766ea1 100644 --- a/ext/soap/tests/bug70388.phpt +++ b/ext/soap/tests/bug70388.phpt @@ -4,6 +4,8 @@ Bug #70388 (SOAP serialize_function_call() type confusion / RCE) soap --FILE-- --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d +Deprecated: Creation of dynamic property Foo::$private is deprecated in %s on line %d -Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d +Deprecated: Creation of dynamic property Foo::$protected is deprecated in %s on line %d Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { diff --git a/ext/standard/tests/serialize/bug49649_1.phpt b/ext/standard/tests/serialize/bug49649_1.phpt index 6b9c2552451c8..731d794c70010 100644 --- a/ext/standard/tests/serialize/bug49649_1.phpt +++ b/ext/standard/tests/serialize/bug49649_1.phpt @@ -34,7 +34,7 @@ $class = unserialize(base64_decode($serialized)); var_dump($class); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d +Deprecated: Creation of dynamic property Foo::$private is deprecated in %s on line %d Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d diff --git a/ext/standard/tests/serialize/bug49649_2.phpt b/ext/standard/tests/serialize/bug49649_2.phpt index 6efcedae050b1..7c96c7bd28b8e 100644 --- a/ext/standard/tests/serialize/bug49649_2.phpt +++ b/ext/standard/tests/serialize/bug49649_2.phpt @@ -34,7 +34,7 @@ $class = unserialize(base64_decode($serialized)); var_dump($class); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$ is deprecated in %s on line %d +Deprecated: Creation of dynamic property Foo::$protected is deprecated in %s on line %d Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d diff --git a/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt b/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt index ee9bfab62fe45..d9f44c37a1560 100644 --- a/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt +++ b/ext/standard/tests/serialize/unserialize_overwrite_undeclared_protected.phpt @@ -13,7 +13,7 @@ STR; var_dump(unserialize($str)); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Test::$ is deprecated in %s on line %d +Deprecated: Creation of dynamic property Test::$x is deprecated in %s on line %d object(Test)#1 (2) { ["foo"]=> NULL diff --git a/ext/standard/tests/serialize/unserialize_ref_to_overwritten_declared_prop.phpt b/ext/standard/tests/serialize/unserialize_ref_to_overwritten_declared_prop.phpt index f32b0c12e2f26..c4c3c957d3ee8 100644 --- a/ext/standard/tests/serialize/unserialize_ref_to_overwritten_declared_prop.phpt +++ b/ext/standard/tests/serialize/unserialize_ref_to_overwritten_declared_prop.phpt @@ -3,10 +3,10 @@ Trying to create a reference to an overwritten declared property --FILE-- --EXPECTF-- -Notice: unserialize(): Error at offset 51 of 52 bytes in %s on line %d +Notice: unserialize(): Error at offset 36 of 52 bytes in %s on line %d bool(false) diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index c9dd715f08da2..ab0a13afe9038 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -639,12 +639,12 @@ declared_property: } } else { if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_forbidden_dynamic_property(obj->ce, Z_STR_P(&key)); + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); goto failure; } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - if (!zend_deprecated_dynamic_property(obj, Z_STR_P(&key))) { - goto failure; - } + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); } int ret = is_property_visibility_changed(obj->ce, &key); From ebafb2545328c4ed9435df593e337252053f9627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Mon, 22 Aug 2022 23:03:51 +0200 Subject: [PATCH 03/11] Fix another round of review comments --- Zend/zend_API.c | 11 +++++------ ext/gmp/tests/gmp_dynamic_property.phpt | 24 ++++++++++++++++++++++++ ext/random/randomizer.c | 1 + ext/standard/var_unserializer.re | 3 +++ 4 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 ext/gmp/tests/gmp_dynamic_property.phpt diff --git a/Zend/zend_API.c b/Zend/zend_API.c index f986c3455e1f2..54bcad825a501 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1630,11 +1630,11 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) } else { if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); + ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): ""); return; } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); + ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): ""); } if (!object->properties) { @@ -1645,12 +1645,11 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) } } else { if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); + zend_throw_error(NULL, "Cannot create dynamic property %s::$" ZEND_LONG_FMT, ZSTR_VAL(object->ce->name), h); return; } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(object->ce->name), zend_get_unmangled_property_name(key)); + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$" ZEND_LONG_FMT " is deprecated", + ZSTR_VAL(object->ce->name), h); } if (!object->properties) { diff --git a/ext/gmp/tests/gmp_dynamic_property.phpt b/ext/gmp/tests/gmp_dynamic_property.phpt new file mode 100644 index 0000000000000..547fe51a7f6a3 --- /dev/null +++ b/ext/gmp/tests/gmp_dynamic_property.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-9186 Dynamic property unserialization should trigger a deprecated notice +--EXTENSIONS-- +gmp +--FILE-- +{1} = 123; + +$serialized = serialize($g); +var_dump(unserialize($serialized)); + +?> +--EXPECTF-- +Deprecated: Creation of dynamic property GMP::$1 is deprecated in %s on line %d + +Deprecated: Creation of dynamic property GMP::$1 is deprecated in %s on line %d +object(GMP)#%d (%d) { + [1]=> + int(123) + ["num"]=> + string(1) "0" +} diff --git a/ext/random/randomizer.c b/ext/random/randomizer.c index 074fbc5020556..f26231b997722 100644 --- a/ext/random/randomizer.c +++ b/ext/random/randomizer.c @@ -279,6 +279,7 @@ PHP_METHOD(Random_Randomizer, __unserialize) } object_properties_load(&randomizer->std, Z_ARRVAL_P(members_zv)); if (EG(exception)) { + zend_throw_exception(NULL, "Invalid serialization data for Random\\Randomizer object", 0); RETURN_THROWS(); } diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index ab0a13afe9038..87f4f7a869cc1 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -645,6 +645,9 @@ declared_property: } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); + if (EG(exception)) { + goto failure; + } } int ret = is_property_visibility_changed(obj->ce, &key); From a8515c77470588defe5d5567d25080ef5d0ca7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Thu, 25 Aug 2022 15:00:12 +0200 Subject: [PATCH 04/11] Add new serialization methods for SplFixedArray --- ext/spl/spl_fixedarray.c | 74 ++++++++++++++++++++-- ext/spl/spl_fixedarray.stub.php | 4 ++ ext/spl/spl_fixedarray_arginfo.h | 16 ++++- ext/spl/tests/SplFixedArray_serialize.phpt | 32 +++++++++- 4 files changed, 117 insertions(+), 9 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index fd18c3d86c378..f9806f7a7412a 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -102,13 +102,18 @@ static void spl_fixedarray_init_elems(spl_fixedarray *array, zend_long from, zen } } +static void spl_fixedarray_init_non_empty_struct(spl_fixedarray *array, zend_long size) +{ + array->size = 0; /* reset size in case ecalloc() fails */ + array->elements = safe_emalloc(size, sizeof(zval), 0); + array->size = size; + array->should_rebuild_properties = true; +} + static void spl_fixedarray_init(spl_fixedarray *array, zend_long size) { if (size > 0) { - array->size = 0; /* reset size in case ecalloc() fails */ - array->elements = safe_emalloc(size, sizeof(zval), 0); - array->size = size; - array->should_rebuild_properties = true; + spl_fixedarray_init_non_empty_struct(array, size); spl_fixedarray_init_elems(array, 0, size); } else { spl_fixedarray_default_ctor(array); @@ -582,6 +587,67 @@ PHP_METHOD(SplFixedArray, __wakeup) } } +PHP_METHOD(SplFixedArray, __serialize) +{ + spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); + zval *current, tmp; + + if (zend_parse_parameters_none() == FAILURE) { + RETURN_THROWS(); + } + + array_init(return_value); + + /* elements */ + array_init_size(&tmp, intern->array.size); + + for (zend_long i = 0; i < intern->array.size; i++) { + current = &intern->array.elements[i]; + zend_hash_next_index_insert(Z_ARRVAL(tmp), current); + Z_TRY_ADDREF_P(current); + } + + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + + /* members */ + ZVAL_ARR(&tmp, zend_proptable_to_symtable( + zend_std_get_properties(&intern->std), /* always_duplicate */ 1)); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); +} + +PHP_METHOD(SplFixedArray, __unserialize) +{ + spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); + HashTable *data; + zval *storage_zv, *members_zv, *elem; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { + RETURN_THROWS(); + } + + if (intern->array.size == 0) { + storage_zv = zend_hash_index_find(data, 0); + members_zv = zend_hash_index_find(data, 1); + if (!storage_zv || !members_zv || + Z_TYPE_P(storage_zv) != IS_ARRAY || Z_TYPE_P(members_zv) != IS_ARRAY + ) { + zend_throw_exception(spl_ce_UnexpectedValueException, + "Incomplete or ill-typed serialization data", 0); + RETURN_THROWS(); + } + + zend_long size = zend_hash_num_elements(Z_ARRVAL_P(storage_zv)); + spl_fixedarray_init_non_empty_struct(&intern->array, size); + + zend_long i = 0; + ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) { + ZVAL_COPY(&intern->array.elements[i++], elem); + } ZEND_HASH_FOREACH_END(); + + object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); + } +} + PHP_METHOD(SplFixedArray, count) { zval *object = ZEND_THIS; diff --git a/ext/spl/spl_fixedarray.stub.php b/ext/spl/spl_fixedarray.stub.php index 7fa9b2730cf59..13f29b7a109db 100644 --- a/ext/spl/spl_fixedarray.stub.php +++ b/ext/spl/spl_fixedarray.stub.php @@ -9,6 +9,10 @@ public function __construct(int $size = 0) {} /** @tentative-return-type */ public function __wakeup(): void {} + public function __serialize(): array {} + + public function __unserialize(array $data): void {} + /** @tentative-return-type */ public function count(): int {} diff --git a/ext/spl/spl_fixedarray_arginfo.h b/ext/spl/spl_fixedarray_arginfo.h index 10c3fdb29c3bc..11ea1fdb30164 100644 --- a/ext/spl/spl_fixedarray_arginfo.h +++ b/ext/spl/spl_fixedarray_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 79a13a549d91f0e79c78a125de65fbac4795339f */ + * Stub hash: 0b508ad6499b70c92bf25960b30fefa913532a3c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFixedArray___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 0, "0") @@ -8,6 +8,13 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___wakeup, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___serialize, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___unserialize, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray_count, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -45,12 +52,13 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_SplFixedArray_getIterator, 0, 0, Iterator, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray_jsonSerialize, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_SplFixedArray_jsonSerialize arginfo_class_SplFixedArray___serialize ZEND_METHOD(SplFixedArray, __construct); ZEND_METHOD(SplFixedArray, __wakeup); +ZEND_METHOD(SplFixedArray, __serialize); +ZEND_METHOD(SplFixedArray, __unserialize); ZEND_METHOD(SplFixedArray, count); ZEND_METHOD(SplFixedArray, toArray); ZEND_METHOD(SplFixedArray, fromArray); @@ -67,6 +75,8 @@ ZEND_METHOD(SplFixedArray, jsonSerialize); static const zend_function_entry class_SplFixedArray_methods[] = { ZEND_ME(SplFixedArray, __construct, arginfo_class_SplFixedArray___construct, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, __wakeup, arginfo_class_SplFixedArray___wakeup, ZEND_ACC_PUBLIC) + ZEND_ME(SplFixedArray, __serialize, arginfo_class_SplFixedArray___serialize, ZEND_ACC_PUBLIC) + ZEND_ME(SplFixedArray, __unserialize, arginfo_class_SplFixedArray___unserialize, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, count, arginfo_class_SplFixedArray_count, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, toArray, arginfo_class_SplFixedArray_toArray, ZEND_ACC_PUBLIC) ZEND_ME(SplFixedArray, fromArray, arginfo_class_SplFixedArray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) diff --git a/ext/spl/tests/SplFixedArray_serialize.phpt b/ext/spl/tests/SplFixedArray_serialize.phpt index f99812ecceb70..77d98a7de84da 100644 --- a/ext/spl/tests/SplFixedArray_serialize.phpt +++ b/ext/spl/tests/SplFixedArray_serialize.phpt @@ -13,6 +13,8 @@ $array[2] = 42; $array[3] = $obj; $array[4] = range(1, 5); +$array->foo = "bar"; + $ser = serialize($array); echo "$ser\n"; $unser = unserialize($ser); @@ -24,10 +26,23 @@ var_dump($unser[0], $unser[1], $unser[2], $unser[3], $unser[4]); $unser[4] = 'quux'; var_dump($unser[4]); +var_dump($unser->foo); + +$array = new SplFixedArray(5); +$array->__unserialize([ + [null], + [ + "foo" => "bar", + ], +]); +var_dump($array); ?> ---EXPECT-- -O:13:"SplFixedArray":5:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}} +--EXPECTF-- +Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d +O:13:"SplFixedArray":2:{i:0;a:5:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}}i:1;a:1:{s:3:"foo";s:3:"bar";}} + +Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d count: 5 getSize(): 5 string(3) "foo" @@ -50,3 +65,16 @@ array(5) { int(5) } string(4) "quux" +string(3) "bar" +object(SplFixedArray)#5 (5) { + [0]=> + NULL + [1]=> + NULL + [2]=> + NULL + [3]=> + NULL + [4]=> + NULL +} From b1f1abc052b8919c46b3a9560d8246b3c8a95a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Fri, 26 Aug 2022 10:33:38 +0200 Subject: [PATCH 05/11] Fix tests --- ext/random/engine_mt19937.c | 1 + ext/random/tests/03_randomizer/gh_9186_unserialize.phpt | 4 ++-- ext/spl/tests/bug70155.phpt | 2 ++ ext/spl/tests/bug74669.phpt | 2 ++ 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ext/random/engine_mt19937.c b/ext/random/engine_mt19937.c index 11f97d35291a2..a2aed76a39d76 100644 --- a/ext/random/engine_mt19937.c +++ b/ext/random/engine_mt19937.c @@ -366,6 +366,7 @@ PHP_METHOD(Random_Engine_Mt19937, __unserialize) } object_properties_load(&engine->std, Z_ARRVAL_P(t)); if (EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name)); RETURN_THROWS(); } diff --git a/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt index e11d4d33a45c0..fe1acb2f74be4 100644 --- a/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt +++ b/ext/random/tests/03_randomizer/gh_9186_unserialize.phpt @@ -5,10 +5,10 @@ Fix GH-9186 @strict-properties can be bypassed using unserialization try { unserialize('O:17:"Random\Randomizer":1:{i:0;a:2:{s:3:"foo";N;s:6:"engine";O:32:"Random\Engine\Xoshiro256StarStar":2:{i:0;a:0:{}i:1;a:4:{i:0;s:16:"7520fbc2d6f8de46";i:1;s:16:"84d2d2b9d7ba0a34";i:2;s:16:"d975f36db6490b32";i:3;s:16:"c19991ee16785b94";}}}}'); -} catch (Error $error) { +} catch (Exception $error) { echo $error->getMessage() . "\n"; } ?> --EXPECT-- -Cannot create dynamic property Random\Randomizer::$foo +Invalid serialization data for Random\Randomizer object diff --git a/ext/spl/tests/bug70155.phpt b/ext/spl/tests/bug70155.phpt index 0aa246cc2388f..a609205aca279 100644 --- a/ext/spl/tests/bug70155.phpt +++ b/ext/spl/tests/bug70155.phpt @@ -9,6 +9,8 @@ $data = unserialize($exploit); var_dump($data); ?> --EXPECTF-- +Deprecated: Creation of dynamic property ArrayObject::$0 is deprecated in %s on line %d + Fatal error: Uncaught InvalidArgumentException: Overloaded object of type DateInterval is not compatible with ArrayObject in %s Stack trace: %s diff --git a/ext/spl/tests/bug74669.phpt b/ext/spl/tests/bug74669.phpt index 0966a4cf27e15..597e694296d26 100644 --- a/ext/spl/tests/bug74669.phpt +++ b/ext/spl/tests/bug74669.phpt @@ -105,6 +105,8 @@ object(SelfArray)#9 (1) { string(3) "bar" } string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}" + +Deprecated: Creation of dynamic property SelfArray::$foo is deprecated in %s on line %d object(SelfArray)#9 (1) { ["foo"]=> string(3) "bar" From 8c8ff84d5a43a2abc5d1c2f53b108569d220ca0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Mon, 29 Aug 2022 22:54:10 +0200 Subject: [PATCH 06/11] Another round of review fixes --- ext/spl/spl_fixedarray.c | 59 ++++++++++---------- ext/spl/tests/SplFixedArray_serialize.phpt | 17 ++---- ext/standard/tests/serialize/bug49649.phpt | 4 -- ext/standard/tests/serialize/bug49649_1.phpt | 4 -- ext/standard/tests/serialize/bug49649_2.phpt | 4 -- ext/standard/var_unserializer.re | 24 ++++---- 6 files changed, 48 insertions(+), 64 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index f9806f7a7412a..534f538236d84 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -105,7 +105,7 @@ static void spl_fixedarray_init_elems(spl_fixedarray *array, zend_long from, zen static void spl_fixedarray_init_non_empty_struct(spl_fixedarray *array, zend_long size) { array->size = 0; /* reset size in case ecalloc() fails */ - array->elements = safe_emalloc(size, sizeof(zval), 0); + array->elements = size ? safe_emalloc(size, sizeof(zval), 0) : NULL; array->size = size; array->should_rebuild_properties = true; } @@ -590,61 +590,64 @@ PHP_METHOD(SplFixedArray, __wakeup) PHP_METHOD(SplFixedArray, __serialize) { spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); - zval *current, tmp; + zval *current; + zend_string *key; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } - array_init(return_value); + uint32_t property_num = zend_hash_num_elements(intern->std.properties); + array_init_size(return_value, intern->array.size + property_num); /* elements */ - array_init_size(&tmp, intern->array.size); - for (zend_long i = 0; i < intern->array.size; i++) { current = &intern->array.elements[i]; - zend_hash_next_index_insert(Z_ARRVAL(tmp), current); + zend_hash_next_index_insert(Z_ARRVAL_P(return_value), current); Z_TRY_ADDREF_P(current); } - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); - /* members */ - ZVAL_ARR(&tmp, zend_proptable_to_symtable( - zend_std_get_properties(&intern->std), /* always_duplicate */ 1)); - zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &tmp); + ZEND_HASH_FOREACH_STR_KEY_VAL(intern->std.properties, key, current) { + zend_hash_str_add(Z_ARRVAL_P(return_value), ZSTR_VAL(key), ZSTR_LEN(key), current); + Z_TRY_ADDREF_P(current); + } ZEND_HASH_FOREACH_END(); } PHP_METHOD(SplFixedArray, __unserialize) { spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS); HashTable *data; - zval *storage_zv, *members_zv, *elem; + zval members_zv, *elem; + zend_string *key; + zend_long idx, size, array_size; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { RETURN_THROWS(); } if (intern->array.size == 0) { - storage_zv = zend_hash_index_find(data, 0); - members_zv = zend_hash_index_find(data, 1); - if (!storage_zv || !members_zv || - Z_TYPE_P(storage_zv) != IS_ARRAY || Z_TYPE_P(members_zv) != IS_ARRAY - ) { - zend_throw_exception(spl_ce_UnexpectedValueException, - "Incomplete or ill-typed serialization data", 0); - RETURN_THROWS(); - } - - zend_long size = zend_hash_num_elements(Z_ARRVAL_P(storage_zv)); + size = zend_hash_num_elements(data); spl_fixedarray_init_non_empty_struct(&intern->array, size); - - zend_long i = 0; - ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), elem) { - ZVAL_COPY(&intern->array.elements[i++], elem); + array_init(&members_zv); + + array_size = 0; + ZEND_HASH_FOREACH_KEY_VAL(data, idx, key, elem) { + if (key == NULL) { + ZVAL_COPY(&intern->array.elements[idx], elem); + array_size++; + } else { + zval tmp; + ZVAL_COPY(&tmp, elem); + zend_hash_add(Z_ARRVAL(members_zv), key, &tmp); + } } ZEND_HASH_FOREACH_END(); - object_properties_load(&intern->std, Z_ARRVAL_P(members_zv)); + intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * array_size); + intern->array.size = array_size; + + object_properties_load(&intern->std, Z_ARRVAL(members_zv)); + zval_ptr_dtor(&members_zv); } } diff --git a/ext/spl/tests/SplFixedArray_serialize.phpt b/ext/spl/tests/SplFixedArray_serialize.phpt index 77d98a7de84da..da7c212109ecd 100644 --- a/ext/spl/tests/SplFixedArray_serialize.phpt +++ b/ext/spl/tests/SplFixedArray_serialize.phpt @@ -28,9 +28,10 @@ $unser[4] = 'quux'; var_dump($unser[4]); var_dump($unser->foo); -$array = new SplFixedArray(5); +// __unserialize is a no-op on a non-empty SplFixedArray +$array = new SplFixedArray(1); $array->__unserialize([ - [null], + [1], [ "foo" => "bar", ], @@ -40,7 +41,7 @@ var_dump($array); ?> --EXPECTF-- Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d -O:13:"SplFixedArray":2:{i:0;a:5:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}}i:1;a:1:{s:3:"foo";s:3:"bar";}} +O:13:"SplFixedArray":6:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}s:3:"foo";s:3:"bar";} Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d count: 5 @@ -66,15 +67,7 @@ array(5) { } string(4) "quux" string(3) "bar" -object(SplFixedArray)#5 (5) { +object(SplFixedArray)#5 (1) { [0]=> NULL - [1]=> - NULL - [2]=> - NULL - [3]=> - NULL - [4]=> - NULL } diff --git a/ext/standard/tests/serialize/bug49649.phpt b/ext/standard/tests/serialize/bug49649.phpt index 5d0e24ccbf948..310cd5b8881e3 100644 --- a/ext/standard/tests/serialize/bug49649.phpt +++ b/ext/standard/tests/serialize/bug49649.phpt @@ -34,10 +34,6 @@ $class = unserialize(base64_decode($serialized)); var_dump($class); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$private is deprecated in %s on line %d - -Deprecated: Creation of dynamic property Foo::$protected is deprecated in %s on line %d - Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public"]=> diff --git a/ext/standard/tests/serialize/bug49649_1.phpt b/ext/standard/tests/serialize/bug49649_1.phpt index 731d794c70010..ddaff1e960c4f 100644 --- a/ext/standard/tests/serialize/bug49649_1.phpt +++ b/ext/standard/tests/serialize/bug49649_1.phpt @@ -34,10 +34,6 @@ $class = unserialize(base64_decode($serialized)); var_dump($class); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$private is deprecated in %s on line %d - -Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d - Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public":protected]=> diff --git a/ext/standard/tests/serialize/bug49649_2.phpt b/ext/standard/tests/serialize/bug49649_2.phpt index 7c96c7bd28b8e..16a9b4d7c722e 100644 --- a/ext/standard/tests/serialize/bug49649_2.phpt +++ b/ext/standard/tests/serialize/bug49649_2.phpt @@ -34,10 +34,6 @@ $class = unserialize(base64_decode($serialized)); var_dump($class); ?> --EXPECTF-- -Deprecated: Creation of dynamic property Foo::$protected is deprecated in %s on line %d - -Deprecated: Creation of dynamic property Foo::$public is deprecated in %s on line %d - Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d object(Foo)#1 (4) { ["public":"Foo":private]=> diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 87f4f7a869cc1..8d49cb75a7446 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -638,18 +638,6 @@ declared_property: } } } else { - if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); - goto failure; - } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); - if (EG(exception)) { - goto failure; - } - } - int ret = is_property_visibility_changed(obj->ce, &key); if (EXPECTED(!ret)) { @@ -666,6 +654,18 @@ second_try: ZVAL_NULL(data); } } + + if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); + goto failure; + } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); + if (EG(exception)) { + goto failure; + } + } } zval_ptr_dtor_str(&key); } else if (Z_TYPE(key) == IS_LONG) { From f1a6837961eee4d4130a7bd0970155290d3e5118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Aug 2022 00:17:27 +0200 Subject: [PATCH 07/11] Fixes --- ext/spl/spl_fixedarray.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 534f538236d84..14b8e9ab467de 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -609,7 +609,7 @@ PHP_METHOD(SplFixedArray, __serialize) /* members */ ZEND_HASH_FOREACH_STR_KEY_VAL(intern->std.properties, key, current) { - zend_hash_str_add(Z_ARRVAL_P(return_value), ZSTR_VAL(key), ZSTR_LEN(key), current); + zend_hash_add(Z_ARRVAL_P(return_value), key, current); Z_TRY_ADDREF_P(current); } ZEND_HASH_FOREACH_END(); } @@ -620,7 +620,7 @@ PHP_METHOD(SplFixedArray, __unserialize) HashTable *data; zval members_zv, *elem; zend_string *key; - zend_long idx, size, array_size; + zend_long idx, size; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { RETURN_THROWS(); @@ -631,20 +631,23 @@ PHP_METHOD(SplFixedArray, __unserialize) spl_fixedarray_init_non_empty_struct(&intern->array, size); array_init(&members_zv); - array_size = 0; + intern->array.size = 0; ZEND_HASH_FOREACH_KEY_VAL(data, idx, key, elem) { if (key == NULL) { - ZVAL_COPY(&intern->array.elements[idx], elem); - array_size++; + ZVAL_COPY(&intern->array.elements[intern->array.size], elem); + intern->array.size++; } else { - zval tmp; - ZVAL_COPY(&tmp, elem); - zend_hash_add(Z_ARRVAL(members_zv), key, &tmp); + Z_TRY_ADDREF_P(elem); + zend_hash_add(Z_ARRVAL(members_zv), key, elem); } } ZEND_HASH_FOREACH_END(); - intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * array_size); - intern->array.size = array_size; + if (intern->array.size) { + intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * intern->array.size); + } else { + efree(intern->array.elements); + intern->array.elements = NULL; + } object_properties_load(&intern->std, Z_ARRVAL(members_zv)); zval_ptr_dtor(&members_zv); From 817adf5bfccedaa70267127c6981c142c82243b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Aug 2022 00:37:30 +0200 Subject: [PATCH 08/11] Fix order of dynamic/readonly property checks --- ext/spl/spl_fixedarray.c | 3 +++ ext/standard/var_unserializer.re | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 14b8e9ab467de..472759338270a 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -629,6 +629,9 @@ PHP_METHOD(SplFixedArray, __unserialize) if (intern->array.size == 0) { size = zend_hash_num_elements(data); spl_fixedarray_init_non_empty_struct(&intern->array, size); + if (!size) { + return; + } array_init(&members_zv); intern->array.size = 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 8d49cb75a7446..72d50c190e653 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -641,6 +641,18 @@ declared_property: int ret = is_property_visibility_changed(obj->ce, &key); if (EXPECTED(!ret)) { + if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { + zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); + goto failure; + } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { + zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", + ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); + if (EG(exception)) { + goto failure; + } + } + data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval)); } else if (ret < 0) { goto failure; @@ -654,18 +666,6 @@ second_try: ZVAL_NULL(data); } } - - if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) { - zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", - ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); - goto failure; - } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) { - zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", - ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key))); - if (EG(exception)) { - goto failure; - } - } } zval_ptr_dtor_str(&key); } else if (Z_TYPE(key) == IS_LONG) { From d730db938273ea771b260ad92bb32729066b2882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Aug 2022 00:59:02 +0200 Subject: [PATCH 09/11] Optimization + warning fix --- ext/spl/spl_fixedarray.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ext/spl/spl_fixedarray.c b/ext/spl/spl_fixedarray.c index 472759338270a..a00bb8965af65 100644 --- a/ext/spl/spl_fixedarray.c +++ b/ext/spl/spl_fixedarray.c @@ -620,7 +620,7 @@ PHP_METHOD(SplFixedArray, __unserialize) HashTable *data; zval members_zv, *elem; zend_string *key; - zend_long idx, size; + zend_long size; if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) { RETURN_THROWS(); @@ -635,7 +635,7 @@ PHP_METHOD(SplFixedArray, __unserialize) array_init(&members_zv); intern->array.size = 0; - ZEND_HASH_FOREACH_KEY_VAL(data, idx, key, elem) { + ZEND_HASH_FOREACH_STR_KEY_VAL(data, key, elem) { if (key == NULL) { ZVAL_COPY(&intern->array.elements[intern->array.size], elem); intern->array.size++; @@ -645,11 +645,13 @@ PHP_METHOD(SplFixedArray, __unserialize) } } ZEND_HASH_FOREACH_END(); - if (intern->array.size) { - intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * intern->array.size); - } else { - efree(intern->array.elements); - intern->array.elements = NULL; + if (intern->array.size != size) { + if (intern->array.size) { + intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * intern->array.size); + } else { + efree(intern->array.elements); + intern->array.elements = NULL; + } } object_properties_load(&intern->std, Z_ARRVAL(members_zv)); From 90bef0fb4026e5abc225b8bcce64dac640eb9859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Aug 2022 09:19:21 +0200 Subject: [PATCH 10/11] Minor review fixes --- Zend/zend_object_handlers.c | 6 ++++-- .../tests/serialize/serialization_objects_incomplete.phpt | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 1a76f35d6689e..d0677f0fe4e96 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -275,12 +275,14 @@ static ZEND_COLD zend_never_inline void zend_bad_property_name(void) /* {{{ */ } /* }}} */ -ZEND_API zend_never_inline void zend_forbidden_dynamic_property(zend_class_entry *ce, zend_string *member) { +static ZEND_COLD zend_never_inline void zend_forbidden_dynamic_property( + zend_class_entry *ce, zend_string *member) { zend_throw_error(NULL, "Cannot create dynamic property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(member)); } -ZEND_API zend_never_inline bool zend_deprecated_dynamic_property(zend_object *obj, zend_string *member) { +static ZEND_COLD zend_never_inline bool zend_deprecated_dynamic_property( + zend_object *obj, zend_string *member) { GC_ADDREF(obj); zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated", ZSTR_VAL(obj->ce->name), ZSTR_VAL(member)); diff --git a/ext/standard/tests/serialize/serialization_objects_incomplete.phpt b/ext/standard/tests/serialize/serialization_objects_incomplete.phpt index f8d8ff9a99aec..1a2b2563022cf 100644 --- a/ext/standard/tests/serialize/serialization_objects_incomplete.phpt +++ b/ext/standard/tests/serialize/serialization_objects_incomplete.phpt @@ -4,7 +4,6 @@ Check behaviour of incomplete class --EXPECT-- object(__PHP_Incomplete_Class)#1 (2) { From 25863e128c37f3bca6787f480f78065b1b553c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 30 Aug 2022 11:14:23 +0200 Subject: [PATCH 11/11] Add news entry --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index d499246c542a3..94d1193e0a39e 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,8 @@ PHP NEWS (cmb) . Fixed bug GH-9285 (Traits cannot be used in readonly classes). (kocsismate) + . Fixed bug GH-9186 (@strict-properties can be bypassed using + unserialization). (kocsismate) - Date: . Fixed bug GH-9431 (DateTime::getLastErrors() not returning false when no