Fix #18542: unserialize() respects class_alias for private properties#21875
Fix #18542: unserialize() respects class_alias for private properties#21875HakanIST wants to merge 1 commit into
Conversation
|
CI Note: All test failures across every platform are the same pre-existing |
|
This bug also manifests in MediaWiki when using APCU cache with |
|
Please rebase on the latest master to fix CI. |
60737b3 to
a6aaf3a
Compare
3b92419 to
687ad19
Compare
TimWolla
left a comment
There was a problem hiding this comment.
I don't see @IMSoP's remark being accounted for in the tests: #18542 (comment)
When a class with private properties is serialized, the property names are mangled as \0ClassName\0propName. If the class is later aliased via class_alias(), unserialize() fails to match the mangled class name against the actual class entry, causing properties to be treated as dynamic instead of declared. This adds a fallback check in is_property_visibility_changed() that uses zend_hash_str_find_ptr_lc() to look up the mangled class name in EG(class_table) and verify it resolves to the same zend_class_entry. This is only triggered when the direct name comparison fails, so there is zero overhead on the normal (non-alias) path. Closes phpGH-18542
687ad19 to
b9b2df8
Compare
|
Added tests to cover @IMSoP's concern from #18542: Test 7: Shadowed private properties at different inheritance levels with alias. Test 8: Single class (no inheritance) with both canonical and alias mangled names:
The fix only triggers |
Problem
When a class with private properties is serialized, the property names are mangled as
\0ClassName\0propName. If the class is later aliased viaclass_alias(),unserialize()fails to match the mangled class name against the actual class entry, causing properties to be treated as dynamic instead of declared.This results in:
Creation of dynamic property is deprecatedwarning (PHP 8.2+)Typed property must not be accessed before initializationfatal errorRoot Cause
In
is_property_visibility_changed()(ext/standard/var_unserializer.re), the mangled class name is only compared againstce->nameviastrcasecmp(). Whenclass_alias()is used, the mangled string contains the alias name whilece->nameholds the canonical class name — these don't match, so the property is not recognized as declared.Fix
Added a fallback check that uses
zend_hash_str_find_ptr_lc(EG(class_table), ...)to verify whether the mangled class name resolves to the samezend_class_entry. This:zend_hash_str_find_ptr_lcuses stack-allocateddo_allocainternally)Test
Added
ext/standard/tests/serialize/unserialize_class_alias_private_props.phptcovering private, protected, and public properties withclass_alias().All existing serialization tests (164) and class_alias tests (26) pass with zero regressions.
Closes #18542