]> granicus.if.org Git - php/commitdiff
Fixed bug #71154
authorNikita Popov <nikic@php.net>
Thu, 17 Dec 2015 21:11:08 +0000 (22:11 +0100)
committerNikita Popov <nikic@php.net>
Thu, 17 Dec 2015 21:20:29 +0000 (22:20 +0100)
NEWS
Zend/tests/bug71154.phpt [new file with mode: 0644]
Zend/zend_hash.c

diff --git a/NEWS b/NEWS
index 16a91ab5a3845520fb1cb8655ff231b752b137bf..4a1f7f6859f9e9c08c56f6a19671d5f3b238fb1f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,6 +16,8 @@ PHP                                                                        NEWS
   . 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)
diff --git a/Zend/tests/bug71154.phpt b/Zend/tests/bug71154.phpt
new file mode 100644 (file)
index 0000000..6186453
--- /dev/null
@@ -0,0 +1,19 @@
+--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)
index ecfee33e14e98b3721467c5d7d3c6840df35198d..8192221c8ecac4a4063df94b200209d920efc0cc 100644 (file)
@@ -31,6 +31,8 @@
 # define HT_ASSERT(c)
 #endif
 
+#define HT_POISONED_PTR ((HashTable *) (intptr_t) -1)
+
 #if ZEND_DEBUG
 /*
 #define HASH_MASK_CONSISTENCY  0xc0
@@ -371,7 +373,8 @@ ZEND_API HashPosition ZEND_FASTCALL zend_hash_iterator_pos(uint32_t idx, HashTab
        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)) {
@@ -389,7 +392,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
 
        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;
@@ -406,20 +410,13 @@ static zend_never_inline void ZEND_FASTCALL _zend_hash_iterators_remove(HashTabl
 {
        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)