Skip to content

Commit fdd6ba6

Browse files
committed
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.
1 parent 68d494d commit fdd6ba6

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.3.13
44

5+
- Core:
6+
. Fixed bug GH-16054 (Segmentation fault when resizing hash table iterator
7+
list while adding). (nielsdos)
8+
59
- DOM:
610
. Fixed bug GH-16039 (Segmentation fault (access null pointer) in
711
ext/dom/parentnode/tree.c). (nielsdos)

Zend/zend_hash.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,17 +2346,20 @@ static zend_always_inline bool zend_array_dup_element(HashTable *source, HashTab
23462346

23472347
// 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
23482348
static void zend_array_dup_ht_iterators(HashTable *source, HashTable *target) {
2349-
HashTableIterator *iter = EG(ht_iterators);
2350-
HashTableIterator *end = iter + EG(ht_iterators_used);
2349+
uint32_t iter_index = 0;
2350+
uint32_t end_index = EG(ht_iterators_used);
23512351

2352-
while (iter != end) {
2352+
while (iter_index != end_index) {
2353+
HashTableIterator *iter = &EG(ht_iterators)[iter_index];
23532354
if (iter->ht == source) {
23542355
uint32_t copy_idx = zend_hash_iterator_add(target, iter->pos);
2356+
/* Refetch iter because the memory may be reallocated. */
2357+
iter = &EG(ht_iterators)[iter_index];
23552358
HashTableIterator *copy_iter = EG(ht_iterators) + copy_idx;
23562359
copy_iter->next_copy = iter->next_copy;
23572360
iter->next_copy = copy_idx;
23582361
}
2359-
iter++;
2362+
iter_index++;
23602363
}
23612364
}
23622365

ext/spl/tests/gh16054.phpt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
GH-16054 (Segmentation fault when resizing hash table iterator list while adding)
3+
--FILE--
4+
<?php
5+
$multi_array = ['zero'];
6+
$multi_array[] =& $multi_array;
7+
$it = new RecursiveTreeIterator(new RecursiveArrayIterator($multi_array), 0);
8+
$counter = 0;
9+
foreach ($it as $k => $v) {
10+
if (++$counter > 200) break;
11+
}
12+
echo "ok\n";
13+
?>
14+
--EXPECT--
15+
ok

0 commit comments

Comments
 (0)