summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-12-17 22:11:08 +0100
committerNikita Popov <nikic@php.net>2015-12-17 22:20:29 +0100
commit6a4c02e107e86a0ff700b79f5a9da0f383c06430 (patch)
treea4c9d7d7e14bbf530a9c9dd441776db4248b7a78
parent0a1a4dc033aca454c6d9a3668b5d0e5bb5ec367e (diff)
downloadphp-git-6a4c02e107e86a0ff700b79f5a9da0f383c06430.tar.gz
Fixed bug #71154
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug71154.phpt19
-rw-r--r--Zend/zend_hash.c17
3 files changed, 28 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 16a91ab5a3..4a1f7f6859 100644
--- 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
index 0000000000..6186453816
--- /dev/null
+++ b/Zend/tests/bug71154.phpt
@@ -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)
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
index ecfee33e14..8192221c8e 100644
--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@ -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)