[php-src] Issue #8079: Recent patch to SplFixedArray causes array_walk + json encode to hang

From: Date: Fri, 11 Feb 2022 13:55:46 +0000
Subject: [php-src] Issue #8079: Recent patch to SplFixedArray causes array_walk + json encode to hang
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-239671@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8079 Author: TysonAndre ### Description I believe that a lot of code in php-src/pecls relies on the fact that the pointer of Z_OBJPROP_P doesn't change, for non-empty properties tables. There's may be more examples than just array_walk but I'm still trying to create one for var_export - The issues affect 52ae6417ca3e62eff796bf3e3b5662fe6a9ee085 and newer after the fix to GH-8044 - Because the properties table was getting cloned, I assume the iterator is getting affected. - Z_OBJPROP_P calls get_properties, which now replaces the original properties table with a clone and returns the original property table to the caller. - array_walk's implementation calls Z_OBJPROP_P in a loop. The following code: ```php <?php call_user_func(function () { $x = new SplFixedArray(2); $x[0] = $x; $x[1] = strtoupper('foo'); echo "Calling array_walk\n"; array_walk($x, function ($value, $index) use($x) { printf("Value=%s index=%s\n", json_encode($value), json_encode($index)); echo "Calling json_encode\n"; echo json_encode($x, JSON_PARTIAL_OUTPUT_ON_ERROR), "\n"; }); }); ?> --EXPECTF-- ``` Resulted in this output: ```c // PHP hangs in an infinite loop. // Adding debug statements to spl_fixedarray_object_get_properties indicates it is repeatedly called and cloning the array in 52ae6417ca3e62eff796bf3e3b5662fe6a9ee085 ``` But I expected this output instead: ```c Calling array_walk Value= index=0 Calling json_encode [null,"FOO"] Value="FOO" index=1 Calling json_encode [null,"FOO"] ``` ----- Relevant parts of the code - zend_hash_iterator_pos probably resets to the start if Z_OBJPROP is a different ht from when starting. ``` // Zend/zend_hash.c ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTable *ht) { HashTableIterator *iter = EG(ht_iterators) + idx; ZEND_ASSERT(idx != (uint32_t)-1); if (UNEXPECTED(iter->ht != ht)) { ``` ``` // ext/standard/array.c static int php_array_walk(zval *array, zval *userdata, int recursive) /* {{{ */ // ... } else if (Z_TYPE_P(array) == IS_OBJECT) { target_hash = Z_OBJPROP_P(array); pos = zend_hash_iterator_pos(ht_iter, target_hash); ``` ### PHP Version PHP 8.0.17-dev(52ae6417c or newer) ### Operating System _No response_

« previous php.bugs (#239671) next »