Fix GH-23088: Stack overflow when comparing deeply nested arrays - #23090
Fix GH-23088: Stack overflow when comparing deeply nested arrays#23090lazerg wants to merge 2 commits into
Conversation
aa11ff5 to
983de1f
Compare
983de1f to
e0c17b3
Compare
| #ifdef ZEND_CHECK_STACK_LIMIT | ||
| if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { | ||
| zend_throw_error(NULL, "Maximum call stack size reached during array comparison"); | ||
| return 0; | ||
| } | ||
| #endif |
There was a problem hiding this comment.
Is this one required, if zend_compare_arrays() checks it too?
There was a problem hiding this comment.
It was, yes. === goes zend_is_identical() -> zend_hash_compare() -> hash_zval_identical_function() -> zend_is_identical(), so it never passes through zend_compare_arrays(). Moot now anyway, both checks are gone and the one in zend_hash_compare() covers each path.
| #ifdef ZEND_CHECK_STACK_LIMIT | ||
| if (UNEXPECTED(zend_call_stack_overflowed(EG(stack_limit)))) { | ||
| zend_throw_error(NULL, "Maximum call stack size reached during array comparison"); | ||
| return ZEND_UNCOMPARABLE; | ||
| } | ||
| #endif |
There was a problem hiding this comment.
Since zend_hash_compare() does the nesting level check, I would prefer if the stack check was moved there as well. WDYT?
There was a problem hiding this comment.
Done, it now sits right next to the recursion guard in zend_hash_compare() and both copies are gone. One side effect: that function also handles object property tables and SplObjectStorage, so the message had to become generic ("Maximum call stack size reached during comparison"), which meant adjusting the regex in gh18572.phpt.
Comparing two deeply nested arrays recurses through
zend_compare_arrays->zend_compare_symbol_tables->zend_hash_compareonce per nesting level, and nothing bounds that recursion.zend_hash_compare()only guards against cycles, so a non-cyclic array a few tens of thousands of levels deep runs the C stack out and the process dies with a segfault.===crashes the same way throughzend_is_identical().Both now check the stack limit before descending and throw an
Errorinstead, the same wayzend_std_compare_objects()already handles the object case.Fixes GH-23088