[php-src] PR #24620: Fix GH-24615: ArrayObject backing storage cycle causes unbounded recursion

From: Date: Fri, 23 Oct 2026 18:31:37 +0000
Subject: [php-src] PR #24620: Fix GH-24615: ArrayObject backing storage cycle causes unbounded recursion
Groups: php.git-pulls 
Request: Send a blank email to git-pulls+get-39784@lists.php.net to get a copy of this message
Pull Request: https://github.com/php/php-src/pull/24620 Author: Marti2203 spl_array_set_array() accepts another ArrayObject/ArrayIterator as storage (SPL_ARRAY_USE_OTHER) and only special-cases an object that uses itself (SPL_ARRAY_IS_SELF). Two objects that use each other as storage are accepted, and the next access to the storage recurses in spl_array_get_hash_table_ptr() until the stack overflows: ```php $a = new ArrayObject([1]); $b = new ArrayObject($a); // $b uses $a's storage $a->exchangeArray($b); // $a now uses $b's storage: a cycle var_dump(count($a)); // stack overflow ``` The same cycle can be built through __construct(), __unserialize()/unserialize(), with ArrayIterator, and over longer chains. ### Fix Before accepting another ArrayObject/ArrayIterator as storage, follow its chain of SPL_ARRAY_USE_OTHER objects and throw an InvalidArgumentException ("Cannot use ArrayObject as storage of ArrayObject, as it would create a cycle") if the chain leads back to the object. This is done before anything is changed, so the object keeps its previous storage. Every path that sets the storage goes through spl_array_set_array(), so all of the above are covered. The walk needs no bound: each object has at most one storage object, and with this check the chains stay acyclic. Using an object as its own storage and sharing storage without a cycle still work. ### Test ext/spl/tests/gh24615.phpt builds two-object and three-object cycles (through exchangeArray(), __construct() and __unserialize(), with an ArrayIterator in the chain). It checks that each attempt throws and leaves the objects usable, and that self storage and acyclic sharing still work. - Without the fix: the test crashes (Termsig=11, stack overflow in spl_array_get_hash_table_ptr()). - With the fix: passes. - ext/spl/tests (debug build): 768 passed, 9 skipped, 0 failed. The branch also merges cleanly into PHP-8.5 and master. On master, object storage for ArrayObject is deprecated, so the test will need the deprecation notices in its expected output (or E_DEPRECATED turned off) after merging up. Fixes GH-24615 This issue was found by an LLM-Enhanced Static Analysis Engine and verified manually; the patch was manually reviewed. 🤖 Generated with [Claude Code](https://claude.com/claude-code)

« previous php.git-pulls (#39784) next »