Skip to content

Fix GH-15869: Stack overflow in zend_array_destroy with deeply nested arrays#21494

Open
iliaal wants to merge 1 commit intophp:masterfrom
iliaal:fix/gh-15869-array-destroy-stack-overflow
Open

Fix GH-15869: Stack overflow in zend_array_destroy with deeply nested arrays#21494
iliaal wants to merge 1 commit intophp:masterfrom
iliaal:fix/gh-15869-array-destroy-stack-overflow

Conversation

@iliaal
Copy link
Contributor

@iliaal iliaal commented Mar 23, 2026

Summary

  • zend_array_destroy() recurses via i_zval_ptr_dtor for each element, overflowing the C stack at ~40-50k nesting levels
  • Applies a tail-call optimization: when an element is an array with refcount reaching zero, defer its destruction and loop back instead of recursing
  • Linear chains (the crash scenario, e.g. $a = [$a] in a loop) now use zero stack depth regardless of nesting
  • Arrays with multiple nested children recurse per-branch, each independently benefiting from the same optimization

Fixes #15869

…ted arrays

zend_array_destroy() recurses through i_zval_ptr_dtor for each element,
which overflows the C stack when arrays are nested deeply enough
(~40-50k levels on a typical 8MB stack).

Apply a tail-call optimization: when an element is an array whose
refcount reaches zero, defer its destruction instead of recursing.
After freeing the current hash table, loop back to destroy the deferred
child. This eliminates recursion entirely for linear chains (the common
crash scenario) while arrays with multiple nested children still recurse
per-branch, each independently benefiting from the same optimization.

Closes phpGH-15869
Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would fix the stack overflow only for a single particular case.
The problem might be simple re-reproduced with $a=[$a,$a] or with objects.
Also the fix may change the order of object destructors (probably this is not critical for master branch), and may interfere with GC.

I'm not sure if we should accept this incomplete fix.

The complete fix would require maintaining a separate destruction queue, but this may introduce different troubles.

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.

Segmentation fault (stack overflow) in Zend

2 participants