Skip to content

Fix GH-24715: Lazy ghost reset by a destructor while releasing its initializer - #24718

Open
lazerg wants to merge 2 commits into
php:PHP-8.4from
lazerg:fix/gh-24715-lazy-ghost-gc
Open

lazerg wants to merge 2 commits into
php:PHP-8.4from
lazerg:fix/gh-24715-lazy-ghost-gc

Conversation

@lazerg

@lazerg lazerg commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

When a lazy ghost finishes initializing, zend_lazy_object_init() deletes its info entry, and that is where the initializer gets released. The hash removes the entry before running its destructor, so any destructor fired by releasing the initializer (here a gc_collect_cycles() in the initializer's __destruct) no longer sees the stale info and is allowed to call resetAsLazyGhost() on the object. zend_lazy_object_init() then returns an object that is lazy again, and zend_lazy_object_get_properties() asserts. ReflectionClass::markLazyObjectAsInitialized() has the same problem and ends up returning without a value or an exception.

The fix releases the initializer before the info entry is deleted in both places, so a reset at that point throws "Can not reset an object while it is being initialized", the same as during the initializer call. Lazy proxies already release their initializer this way.

Fixes #24715

@lazerg

lazerg commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

The LINUX_X32_DEBUG_ZTS failure is a timeout in ext/pcntl/tests/002.phpt, which this change does not touch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant