-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Description
There is a bug in the repeat 2 logic caused by an incorrect goto inside a zend_try block. This bug does not manifest in most cases, but I encountered it in tests with the async core.
zend_try { // 619 — SETJMP + EG(bailout) = &__bailout
// ...
do_repeat: // 871 — goto jumps HERE
// ...
php_execute_script(); // has its own zend_try inside
// ...
} zend_end_try(); // 1149 — EG(bailout) = __orig_bailout
out:
php_request_shutdown(); // 1156
goto do_repeat; // 1171 — jumps to 871
After Round 1:
1. zend_end_try() (1149) — restores EG(bailout) = __orig_bailout
2. php_request_shutdown() — OK
3. goto do_repeat — jumps to 871
Round 2 — the problem:
- SETJMP at line 619 is NOT called again
- EG(bailout) points to __orig_bailout (the outer handler), not &__bailout
- When php_execute_script does its own zend_try, it saves __orig_bailout as its parent
- When zend_bailout() at scheduler.c:1216 fires → it jumps past do_cli() entirely → php_request_shutdown() is NOT called on Round 2!
The flow goes straight to main() → php_module_shutdown() → executor_globals_dtor() → ...
This is the root cause! The bug is in php_cli.c itself — goto do_repeat jumps into the middle of a zend_try block without reinitializing SETJMP.
That is, when the CLI runs in repeat mode twice, it is not cleaned up correctly the second time. The request shutdown is not called.
PHP Version
PHP 8.6.0-dev (cli) (built: Mar 12 2026 06:51:37) (ZTS TrueAsync ABI v0.9.0)
Copyright (c) The PHP Group
Zend Engine v4.6.0-dev, Copyright (c) Zend Technologies
with Zend OPcache v8.6.0-dev, Copyright (c), by Zend Technologies
Operating System
No response