diff --git a/Zend/tests/lazy_objects/gh20657-001.phpt b/Zend/tests/lazy_objects/gh20657-001.phpt new file mode 100644 index 0000000000000..ca3c70febca63 --- /dev/null +++ b/Zend/tests/lazy_objects/gh20657-001.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-20657: GC during zend_lazy_object_realize() +--CREDITS-- +vi3tL0u1s +--FILE-- +newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff --git a/Zend/tests/lazy_objects/gh20657-002.phpt b/Zend/tests/lazy_objects/gh20657-002.phpt new file mode 100644 index 0000000000000..daf9b767ba978 --- /dev/null +++ b/Zend/tests/lazy_objects/gh20657-002.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-20657 002: GC during zend_lazy_object_realize() - reset as lazy during realize() +--FILE-- +self = $this; + } + public function __destruct() { + global $obj, $reflector; + $reflector->resetAsLazyGhost($obj, function () {}); + } +} + +new D(); + +$reflector = new ReflectionClass(C::class); + +for ($i = 0; $i < 10000; $i++) { + $obj = $reflector->newLazyGhost(function ($obj) {}); + + // Add to roots + $obj2 = $obj; + unset($obj2); + + // Initialize all props to mark object non-lazy. Also create a cycle. + $reflector->getProperty('a')->setRawValueWithoutLazyInitialization($obj, $obj); +} + +var_dump($obj); + +?> +--EXPECTF-- +object(C)#%d (1) { + ["a"]=> + *RECURSION* +} diff --git a/Zend/zend_lazy_objects.c b/Zend/zend_lazy_objects.c index bf76f6e88fe7d..59c8ec36a9b80 100644 --- a/Zend/zend_lazy_objects.c +++ b/Zend/zend_lazy_objects.c @@ -678,8 +678,6 @@ void zend_lazy_object_realize(zend_object *obj) ZEND_ASSERT(zend_object_is_lazy(obj)); ZEND_ASSERT(!zend_lazy_object_initialized(obj)); - zend_lazy_object_del_info(obj); - #if ZEND_DEBUG for (int i = 0; i < obj->ce->default_properties_count; i++) { ZEND_ASSERT(!(Z_PROP_FLAG_P(&obj->properties_table[i]) & IS_PROP_LAZY)); @@ -687,6 +685,7 @@ void zend_lazy_object_realize(zend_object *obj) #endif OBJ_EXTRA_FLAGS(obj) &= ~(IS_OBJ_LAZY_UNINITIALIZED | IS_OBJ_LAZY_PROXY); + zend_lazy_object_del_info(obj); } ZEND_API HashTable *zend_lazy_object_get_properties(zend_object *object)