[php-src] PR #24487: Fix temporaries leaking when a VM interrupt throws at the op that fre…
| From: | cscott | Date: | Wed, 21 Oct 2026 17:30:45 +0000 |
| Subject: | [php-src] PR #24487: Fix temporaries leaking when a VM interrupt throws at the op that fre… | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39664@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24487
Author: cscott
The VM checks for interrupts after setting
opline to the next op, such as a jump target
(and, in the CALL VM, the op after a call to a user function); the JIT checks at loop headers and in
side-exit stubs. If the interrupt function throws (async pcntl signal handler, Excimer timeout,
...), the exception is attributed to that op, which has not run. Live ranges end at the op that
consumes a var, so ZEND_HANDLE_EXCEPTION does not free vars that this op was about to
consume:
```php
function gen() { yield 1; release(); } // interrupt pending as release() returns
foreach (gen() as $v) {} // FE_FETCH jumps to FE_FREE: generator leaks
```
The same happens with switch on a string, and with ternary/match results
assigned after the jump.
The interrupt helpers already undefine the result of the interrupted op. This PR moves that to
zend_cleanup_interrupted_op(), which also frees vars whose live range ends at the
interrupted op, and the operand defined by the op just before it (which has no live range).
Interrupt timing is unchanged.
Tests use zend_test.observer.set_vm_interrupt_on_end (also added by the fix for
GH-24480), which makes an interrupt pending and throwing as an observed function returns.
Tested on debug builds of the hybrid and CALL VMs, without opcache and with opcache with JIT off,
function JIT and tracing JIT.