summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-04-16 10:38:20 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-04-16 10:38:20 +0200
commit9a9eed472b05292f8e8aa82129ea5d1da4b0e0c2 (patch)
treec77cc08d5cac1c0203f173ac6e40e28ace35f38a
parente1b4cabbd6d5ce72bb73ec4988b91c1e62c71335 (diff)
downloadphp-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--NEWS4
-rw-r--r--Zend/tests/foreach_by_ref_repacking_insert.phpt18
-rw-r--r--Zend/zend_hash.c7
-rw-r--r--ext/spl/tests/bug77903.phpt8
4 files changed, 33 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 58df7fb784..eef56ef2aa 100644
--- a/NEWS
+++ b/NEWS
@@ -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)