Skip to content

Bug: GC of a fiber suspended in a file included from a function - #24200

Open
EdmondDantes wants to merge 1 commit into
php:PHP-8.4from
true-async:fiber-gc-include-symbol-table
Open

EdmondDantes wants to merge 1 commit into
php:PHP-8.4from
true-async:fiber-gc-include-symbol-table

Conversation

@EdmondDantes

Copy link
Copy Markdown
Contributor

A file included from a function, or code eval'd in it, runs in its own frame over the symbol table of that function. zend_fiber_object_gc() walks the suspended fiber's frames and adds the symbol table of each one, so a fiber suspended inside such a file added the same table twice: the collector counted its values twice and decremented their refcounts below zero.

Reproduction (debug build, no extensions):

// inc.php: $local = new stdClass; Fiber::suspend(); echo "kept\n";
function run() { include __DIR__ . '/inc.php'; }
 
$fiber = new Fiber(function () { run(); });
$fiber->start();
 
$holder = new stdClass;
$holder->fiber = $fiber;
$holder->self = $holder;
unset($holder);
 
gc_collect_cycles();
$fiber->resume();

Expected: kept. Actual: zend_gc_delref: Assertion 'p->refcount > 0' failed (debug build).

The fix skips a frame whose symbol table is the one the previous frame already added. No behaviour change otherwise.

Test: Zend/tests/fibers/gc-include-shared-symbol-table.phpt (aborts on PHP-8.4 debug without the fix, passes with it; Zend/tests/fibers 97 of 97 pass). The test relies on the debug assertion, so only debug builds detect the bug.

A file included, or code eval'd, from a function runs in its own frame over
the symbol table of that function. zend_fiber_object_gc() added that table once
for each of the two frames, so the collector counted its values twice and
decremented their refcounts below zero.
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