. Fixed bug #71089 (No check to duplicate zend_extension). (Remi)
. Fixed bug #71086 (Invalid numeric literal parse error within
highlight_string() function). (Nikita)
+ . Fixed bug #71154 (Incorrect HT iterator invalidation causes iterator reuse).
+ (Nikita)
- DBA:
. Fixed key leak with invalid resource. (Laruence)
--- /dev/null
+--TEST--
+Bug #71154: Incorrect HT iterator invalidation causes iterator reuse
+--FILE--
+<?php
+
+$array = [1, 2, 3];
+foreach ($array as &$ref) {
+ /* Free array, causing free of iterator */
+ $array = [];
+ /* Reuse the iterator.
+ * However it will also be reused on next foreach iteration */
+ $it = new ArrayIterator([1, 2, 3]);
+ $it->rewind();
+}
+var_dump($it->current());
+
+?>
+--EXPECT--
+int(1)
# define HT_ASSERT(c)
#endif
+#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
+
#if ZEND_DEBUG
/*
#define HASH_MASK_CONSISTENCY 0xc0
if (iter->pos == HT_INVALID_IDX) {
return HT_INVALID_IDX;
} else if (UNEXPECTED(iter->ht != ht)) {
- if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
+ if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
+ && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
iter->ht->u.v.nIteratorsCount--;
}
if (EXPECTED(ht->u.v.nIteratorsCount != 255)) {
ZEND_ASSERT(idx != (uint32_t)-1);
- if (EXPECTED(iter->ht) && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
+ if (EXPECTED(iter->ht) && EXPECTED(iter->ht != HT_POISONED_PTR)
+ && EXPECTED(iter->ht->u.v.nIteratorsCount != 255)) {
iter->ht->u.v.nIteratorsCount--;
}
iter->ht = NULL;
{
HashTableIterator *iter = EG(ht_iterators);
HashTableIterator *end = iter + EG(ht_iterators_used);
- uint32_t idx;
while (iter != end) {
if (iter->ht == ht) {
- iter->ht = NULL;
+ iter->ht = HT_POISONED_PTR;
}
iter++;
}
-
- idx = EG(ht_iterators_used);
- while (idx > 0 && EG(ht_iterators)[idx - 1].ht == NULL) {
- idx--;
- }
- EG(ht_iterators_used) = idx;
}
static zend_always_inline void zend_hash_iterators_remove(HashTable *ht)