[php-src] PR #24062: Fix refcount corruption when GC runs while a WeakMap key is freed

From: Date: Fri, 02 Oct 2026 01:00:23 +0000
Subject: [php-src] PR #24062: Fix refcount corruption when GC runs while a WeakMap key is freed
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39061@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24062 Author: rlorenzo AI disclosure: I used an LLM (Claude) to investigate, fix and test this bug, and to write this description. Per CONTRIBUTING.md, everything below this line is LLM-written and is quoted. > When an object that is a key in two or more WeakMaps is freed, > zend_weakrefs_notify() releases each map's value in turn. If > releasing one value runs the GC, the dying object > (IS_OBJ_FREE_CALLED, so not scanned) is still a key in the remaining > maps. gc_scan_black() leaves those entries for the key to blacken, > which never happens, so their refcount stays decremented. The value then gets freed while still in > use, which shows up as zend_mm_heap corrupted in release builds and > as Assertion failed: (idx) in > gc_remove_from_buffer in debug builds. > > ```php > class CollectOnDestruct { function __destruct() { gc_collect_cycles(); } } > $wm1 = new WeakMap; $wm2 = new WeakMap; > $key = new stdClass; > $wm1[$key] = new CollectOnDestruct; > $keep = new stdClass; > $wm2[$key] = $keep; > $tmp = $wm2; unset($tmp); // make $wm2 a GC root > $tmp = $key; unset($tmp); // make $key a GC root > unset($key); // crashes / asserts > ``` > > Fix: remove the object from every map first (with pDestructor > set to NULL, so nothing runs), then release the values. > zend_weakmap_free_obj() already does it in this order. > > - The new test fails without the fix and passes with it on a debug + ASAN build. > Zend/tests has no new failures. > - Affects 8.3+ (since cbf67e4feee). This targets PHP-8.4 and merges up cleanly. > - Side effect: WeakReferences to the object are now cleared > before any value destructor runs. > - Not tested: ZTS, Windows, JIT.

« previous php.git-pulls (#39061) next »