diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-04-16 10:38:20 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-04-16 10:38:20 +0200 |
commit | 9a9eed472b05292f8e8aa82129ea5d1da4b0e0c2 (patch) | |
tree | c77cc08d5cac1c0203f173ac6e40e28ace35f38a | |
parent | e1b4cabbd6d5ce72bb73ec4988b91c1e62c71335 (diff) | |
download | php-git-9a9eed472b05292f8e8aa82129ea5d1da4b0e0c2.tar.gz |
Fix second part of bug #77903
When a HT iterator is one past the end and we rehash, we need to make
sure that it is move to the new one past the end position, to make
sure that newly inserted elements are picked up.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | Zend/tests/foreach_by_ref_repacking_insert.phpt | 18 | ||||
-rw-r--r-- | Zend/zend_hash.c | 7 | ||||
-rw-r--r-- | ext/spl/tests/bug77903.phpt | 8 |
4 files changed, 33 insertions, 4 deletions
@@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 7.3.5 +- Core: + . Fixed bug #77903 (ArrayIterator stops iterating after offsetSet call). + (Nikita) + - CLI: . Fixed bug #77794 (Incorrect Date header format in built-in server). (kelunik) diff --git a/Zend/tests/foreach_by_ref_repacking_insert.phpt b/Zend/tests/foreach_by_ref_repacking_insert.phpt new file mode 100644 index 0000000000..1a2f9c7068 --- /dev/null +++ b/Zend/tests/foreach_by_ref_repacking_insert.phpt @@ -0,0 +1,18 @@ +--TEST-- +Perform a packed to hash insert when the iterator is at the end of the array +--FILE-- + +<?php +$a = []; +$a[1] = 1; +foreach ($a as $k => &$v) { + var_dump($v); + if ($k == 1) $a[4] = 4; + if ($k == 4) $a[2] = 2; +} + +?> +--EXPECT-- +int(1) +int(4) +int(2) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 5568b23af9..e26ebd7594 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1070,6 +1070,7 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht) p++; } while (++i < ht->nNumUsed); } else { + uint32_t old_num_used = ht->nNumUsed; do { if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) { uint32_t j = i; @@ -1126,6 +1127,12 @@ ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht) HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(i); p++; } while (++i < ht->nNumUsed); + + /* Migrate pointer to one past the end of the array to the new one past the end, so that + * newly inserted elements are picked up correctly. */ + if (UNEXPECTED(HT_HAS_ITERATORS(ht))) { + _zend_hash_iterators_update(ht, old_num_used, ht->nNumUsed); + } } return SUCCESS; } diff --git a/ext/spl/tests/bug77903.phpt b/ext/spl/tests/bug77903.phpt index eb1c579b8f..842de9cca2 100644 --- a/ext/spl/tests/bug77903.phpt +++ b/ext/spl/tests/bug77903.phpt @@ -22,8 +22,8 @@ $a->next(); var_dump($a->valid()); // false var_dump($a->current()); // null $a->offsetSet(2,2); -var_dump($a->valid()); // should: true; got: false -var_dump($a->current()); // should: 2; got: null +var_dump($a->valid()); // true +var_dump($a->current()); // 2 $a->next(); var_dump($a->valid()); // false var_dump($a->current()); // null @@ -44,8 +44,8 @@ bool(false) NULL bool(false) NULL -bool(false) -NULL +bool(true) +int(2) bool(false) NULL bool(false) |