Skip to content

Commit e19d671

Browse files
committed
Release the initializer before deleting the info in markLazyObjectAsInitialized() too
1 parent 3a21b1f commit e19d671

3 files changed

Lines changed: 49 additions & 8 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-24715 002: Object reset as lazy by a destructor triggered when releasing the initializer in markLazyObjectAsInitialized()
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public $a;
8+
}
9+
10+
class D {
11+
public function __destruct() {
12+
global $obj, $reflector;
13+
try {
14+
$reflector->resetAsLazyGhost($obj, function () {});
15+
} catch (Error $e) {
16+
printf("%s: %s\n", $e::class, $e->getMessage());
17+
}
18+
}
19+
}
20+
21+
$reflector = new ReflectionClass(C::class);
22+
$d = new D();
23+
$obj = $reflector->newLazyGhost(function ($obj) use ($d) {});
24+
unset($d);
25+
26+
var_dump($reflector->markLazyObjectAsInitialized($obj) === $obj);
27+
var_dump($reflector->isUninitializedLazyObject($obj));
28+
29+
?>
30+
--EXPECT--
31+
Error: Can not reset an object while it is being initialized
32+
bool(true)
33+
bool(false)

‎Zend/zend_lazy_objects.c‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,20 @@ zend_lazy_object_flags_t zend_lazy_object_get_flags(zend_object *obj)
161161
return zend_lazy_object_get_info(obj)->flags;
162162
}
163163

164+
/* Release the initializer while the info is still registered, so that
165+
* destructors triggered by this can not reset the object */
166+
static void zend_lazy_object_release_initializer(zend_object *obj)
167+
{
168+
zend_lazy_object_info *info = zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle);
169+
ZEND_ASSERT(info && !(info->flags & ZEND_LAZY_OBJECT_INITIALIZED));
170+
171+
zval initializer_zv;
172+
ZVAL_COPY_VALUE(&initializer_zv, &info->u.initializer.zv);
173+
ZVAL_UNDEF(&info->u.initializer.zv);
174+
zend_fcc_dtor(&info->u.initializer.fcc);
175+
zval_ptr_dtor(&initializer_zv);
176+
}
177+
164178
void zend_lazy_object_del_info(zend_object *obj)
165179
{
166180
zend_result res = zend_hash_index_del(&EG(lazy_objects_store).infos, obj->handle);
@@ -412,6 +426,7 @@ ZEND_API zend_object *zend_lazy_object_mark_as_initialized(zend_object *obj)
412426
}
413427
}
414428

429+
zend_lazy_object_release_initializer(obj);
415430
zend_lazy_object_del_info(obj);
416431

417432
return obj;
@@ -672,14 +687,7 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj)
672687
zend_release_properties(properties_snapshot);
673688
}
674689

675-
/* Release the initializer while the info is still registered, so that
676-
* destructors triggered by this can not reset the object */
677-
zend_lazy_object_info *info = zend_hash_index_find_ptr(&EG(lazy_objects_store).infos, obj->handle);
678-
zval initializer_zv;
679-
ZVAL_COPY_VALUE(&initializer_zv, &info->u.initializer.zv);
680-
ZVAL_UNDEF(&info->u.initializer.zv);
681-
zend_fcc_dtor(&info->u.initializer.fcc);
682-
zval_ptr_dtor(&initializer_zv);
690+
zend_lazy_object_release_initializer(obj);
683691

684692
/* Must be very last in this function, for the
685693
* zend_lazy_object_has_stale_info() check */

0 commit comments

Comments
 (0)