Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Zend/tests/weakrefs/gh20404_weakmap_dtor_reentrancy.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-20404: Crash when adding object to WeakMap during destruction
--FILE--
<?php

$w = new WeakMap;

$o = new stdClass;
$w[$o] = new class($r) {
function __construct(public &$r) {}
function __destruct() {
global $refs;
$o = $this->r->get();
for ($i = 0; $i < 8; ++$i) {
$r = new WeakMap;
$r[$o] = 1;
$refs[] = $r;
}
}
};
$r = WeakReference::create($o);

echo "END OF SCRIPT\n";
?>
--EXPECT--
END OF SCRIPT
13 changes: 10 additions & 3 deletions Zend/zend_weakrefs.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,13 @@ static void zend_weakref_register(zend_object *object, void *payload) {
static void zend_weakref_unregister(zend_object *object, void *payload, bool weakref_free) {
zend_ulong obj_key = zend_object_to_weakref_key(object);
void *tagged_ptr = zend_hash_index_find_ptr(&EG(weakrefs), obj_key);
ZEND_ASSERT(tagged_ptr && "Weakref not registered?");

if (!tagged_ptr) {
#if ZEND_DEBUG
ZEND_ASSERT("Weakref not registered?");
#endif
return;
}

void *ptr = ZEND_WEAKREF_GET_PTR(tagged_ptr);
uintptr_t tag = ZEND_WEAKREF_GET_TAG(tagged_ptr);
Expand Down Expand Up @@ -217,9 +223,10 @@ void zend_weakrefs_notify(zend_object *object) {
#if ZEND_DEBUG
ZEND_ASSERT(tagged_ptr && "Tracking of the IS_OBJ_WEAKLY_REFERENCE flag should be precise");
#endif
if (tagged_ptr) {
zend_weakref_unref(object, tagged_ptr);
while (tagged_ptr) {
zend_hash_index_del(&EG(weakrefs), obj_key);
zend_weakref_unref(object, tagged_ptr);
tagged_ptr = zend_hash_index_find_ptr(&EG(weakrefs), obj_key);
}
}

Expand Down
Loading