From fdd6ba62bb9cc88352ba6f3f56d663593bb689e1 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:51:14 +0200 Subject: [PATCH] Fix GH-16054: Segmentation fault when resizing hash table iterator list while adding zend_array_dup_ht_iterators() loops over the hash table iterators and can call zend_hash_iterator_add(). zend_hash_iterator_add() can resize the array causing a crash in zend_array_dup_ht_iterators(). We solve this by refetching the iter pointer after an add happened. Closes GH-16060. --- NEWS | 4 ++++ Zend/zend_hash.c | 11 +++++++---- ext/spl/tests/gh16054.phpt | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 ext/spl/tests/gh16054.phpt diff --git a/NEWS b/NEWS index bf7551b2372..6c47f256772 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.13 +- Core: + . Fixed bug GH-16054 (Segmentation fault when resizing hash table iterator + list while adding). (nielsdos) + - DOM: . Fixed bug GH-16039 (Segmentation fault (access null pointer) in ext/dom/parentnode/tree.c). (nielsdos) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 6668c4c17c6..ea1bfa3afc0 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -2346,17 +2346,20 @@ static zend_always_inline bool zend_array_dup_element(HashTable *source, HashTab // We need to duplicate iterators to be able to search through all copy-on-write copies to find the actually iterated HashTable and position back static void zend_array_dup_ht_iterators(HashTable *source, HashTable *target) { - HashTableIterator *iter = EG(ht_iterators); - HashTableIterator *end = iter + EG(ht_iterators_used); + uint32_t iter_index = 0; + uint32_t end_index = EG(ht_iterators_used); - while (iter != end) { + while (iter_index != end_index) { + HashTableIterator *iter = &EG(ht_iterators)[iter_index]; if (iter->ht == source) { uint32_t copy_idx = zend_hash_iterator_add(target, iter->pos); + /* Refetch iter because the memory may be reallocated. */ + iter = &EG(ht_iterators)[iter_index]; HashTableIterator *copy_iter = EG(ht_iterators) + copy_idx; copy_iter->next_copy = iter->next_copy; iter->next_copy = copy_idx; } - iter++; + iter_index++; } } diff --git a/ext/spl/tests/gh16054.phpt b/ext/spl/tests/gh16054.phpt new file mode 100644 index 00000000000..cef6e547afb --- /dev/null +++ b/ext/spl/tests/gh16054.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-16054 (Segmentation fault when resizing hash table iterator list while adding) +--FILE-- + $v) { + if (++$counter > 200) break; +} +echo "ok\n"; +?> +--EXPECT-- +ok