Summary
A caught exception object is never freed: each throw whose exception is handled by a catch leaks the throwable heap block (~48 bytes), once per catch. In a loop that throws-and-catches, the heap grows without bound.
Verified on
main (macOS ARM64, default EIR backend), via --heap-debug leak summary.
Minimal reproduction
<?php
for ($n = 0; $n < 200; $n++) {
try {
throw new TypeError("x");
} catch (\Throwable $e) {
// handled; $e goes out of scope at the end of the catch
}
}
echo "done\n";
Actual (--heap-debug)
HEAP DEBUG: leak summary: live_blocks=200 live_bytes=9600
live_blocks grows linearly with the number of caught exceptions (N=50 → 50, N=200 → 200): the throwable allocated by throw is never released after the catch handler completes.
Expected
The caught exception object should be released when it leaves the catch scope (like any other scope-local object), leaving the heap flat across iterations.
Notes
General exception-handling ownership gap, independent of the throw source (a user throw new ..., a builtin fatal-to-TypeError, etc. all leak the same block). Not a crash — a steady per-catch leak. Long-running programs that use exceptions for control flow will accumulate memory.
Summary
A caught exception object is never freed: each
throwwhose exception is handled by acatchleaks the throwable heap block (~48 bytes), once per catch. In a loop that throws-and-catches, the heap grows without bound.Verified on
main(macOS ARM64, default EIR backend), via--heap-debugleak summary.Minimal reproduction
Actual (
--heap-debug)live_blocksgrows linearly with the number of caught exceptions (N=50 → 50, N=200 → 200): the throwable allocated bythrowis never released after thecatchhandler completes.Expected
The caught exception object should be released when it leaves the
catchscope (like any other scope-local object), leaving the heap flat across iterations.Notes
General exception-handling ownership gap, independent of the throw source (a user
throw new ..., a builtin fatal-to-TypeError, etc. all leak the same block). Not a crash — a steady per-catch leak. Long-running programs that use exceptions for control flow will accumulate memory.