]> granicus.if.org Git - php/commitdiff
Fixed bug #68215 (Behavior of foreach has changed)
authorDmitry Stogov <dmitry@zend.com>
Wed, 15 Oct 2014 13:02:54 +0000 (17:02 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 15 Oct 2014 13:02:54 +0000 (17:02 +0400)
Zend/tests/bug68215.phpt [new file with mode: 0644]
Zend/zend_hash.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/bug68215.phpt b/Zend/tests/bug68215.phpt
new file mode 100644 (file)
index 0000000..c4e8da8
--- /dev/null
@@ -0,0 +1,91 @@
+--TEST--
+Bug #68215 (Behavior of foreach has changed)
+--FILE--
+<?php
+$arr = array(
+       'a' => array(
+               'a' => 'apple',
+               'b' => 'banana',
+               'c' => 'cranberry',
+               'd' => 'mango',
+               'e' => 'pineapple'
+       ),
+       'b' => array(
+               'a' => 'apple',
+               'b' => 'banana',
+               'c' => 'cranberry',
+               'd' => 'mango',
+               'e' => 'pineapple'
+       ),
+       'c' => 'cranberry',
+       'd' => 'mango',
+       'e' => 'pineapple'
+);
+
+function test(&$child, $entry)
+{
+       $i = 1;
+
+       foreach ($child AS $key => $fruit)
+       {
+               if (!is_numeric($key))
+               {
+                       $child[$i] = $fruit;
+                       unset($child[$key]);
+                       $i++;
+               }
+       }
+}
+
+$i = 1;
+
+foreach ($arr AS $key => $fruit)
+{
+       $arr[$i] = $fruit;
+
+       if (is_array($fruit))
+       {
+               test($arr[$i], $fruit);
+       }
+
+       unset($arr[$key]);
+       $i++;
+}
+
+var_dump($arr);
+?>
+--EXPECT--
+array(5) {
+  [1]=>
+  array(5) {
+    [1]=>
+    string(5) "apple"
+    [2]=>
+    string(6) "banana"
+    [3]=>
+    string(9) "cranberry"
+    [4]=>
+    string(5) "mango"
+    [5]=>
+    string(9) "pineapple"
+  }
+  [2]=>
+  array(5) {
+    [1]=>
+    string(5) "apple"
+    [2]=>
+    string(6) "banana"
+    [3]=>
+    string(9) "cranberry"
+    [4]=>
+    string(5) "mango"
+    [5]=>
+    string(9) "pineapple"
+  }
+  [3]=>
+  string(9) "cranberry"
+  [4]=>
+  string(5) "mango"
+  [5]=>
+  string(9) "pineapple"
+}
index aaa677943d48b1ab302b5949e61ab1c1abc5f117..5a36ddf28fc0537b3544d7da025bf3fba28d9240 100644 (file)
@@ -170,9 +170,10 @@ ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *p
 ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
 
 typedef struct _HashPointer {
-       HashPosition pos;
-       HashTable *ht;
-       zend_ulong h;
+       HashPosition  pos;
+       HashTable    *ht;
+       zend_ulong    h;
+       zend_string  *key;
 } HashPointer;
 
 #define zend_hash_has_more_elements(ht) \
index af532e88e40dd3f838ebda41bcc9d8874a55edb2..ae2f0e716140bb088e5788dcd96ff16c740480ab 100644 (file)
@@ -4576,6 +4576,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
                ptr->pos = pos;
                ptr->ht = fe_ht;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                is_empty = 0;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
@@ -4630,8 +4631,11 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
                                pos = ptr->h;
                        } else {
                                pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
-                               while (pos != INVALID_IDX) {
-                                       if (fe_ht->arData[pos].h == ptr->h && pos == ptr->pos) {
+                               while (1) {
+                                       if (pos == INVALID_IDX) {
+                                               pos = fe_ht->nInternalPointer;
+                                               break;
+                                       } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
                                                break;
                                        }
                                        pos = Z_NEXT(fe_ht->arData[pos].val);
@@ -4684,6 +4688,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
                              Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
                fe_ht->nInternalPointer = ptr->pos = pos;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                ZEND_VM_INC_OPCODE();
                ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -4707,8 +4712,11 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
                                        pos = ptr->h;
                                } else {
                                        pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
-                                       while (pos != INVALID_IDX) {
-                                               if (fe_ht->arData[pos].h == ptr->h && pos == ptr->pos) {
+                                       while (1) {
+                                               if (pos == INVALID_IDX) {
+                                                       pos = fe_ht->nInternalPointer;
+                                                       break;
+                                               } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
                                                        break;
                                                }
                                                pos = Z_NEXT(fe_ht->arData[pos].val);
@@ -4777,6 +4785,7 @@ ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY)
                                      zend_check_property_access(zobj, p->key TSRMLS_CC) == FAILURE));
                        fe_ht->nInternalPointer = ptr->pos = pos;
                        ptr->h = fe_ht->arData[pos].h;
+                       ptr->key = fe_ht->arData[pos].key;
                        ZEND_VM_INC_OPCODE();
                        ZEND_VM_NEXT_OPCODE();
                } else {
index 0768aa6df27beb3e746e6fcb4a7e71cd0afbbaab..5d448c34d48bfdda3a973af4a3bc6b2aff900f85 100644 (file)
@@ -3222,6 +3222,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
                ptr->pos = pos;
                ptr->ht = fe_ht;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                is_empty = 0;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
@@ -10032,6 +10033,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ptr->pos = pos;
                ptr->ht = fe_ht;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                is_empty = 0;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
@@ -16747,6 +16749,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ptr->pos = pos;
                ptr->ht = fe_ht;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                is_empty = 0;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");
@@ -16801,8 +16804,11 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                                pos = ptr->h;
                        } else {
                                pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
-                               while (pos != INVALID_IDX) {
-                                       if (fe_ht->arData[pos].h == ptr->h && pos == ptr->pos) {
+                               while (1) {
+                                       if (pos == INVALID_IDX) {
+                                               pos = fe_ht->nInternalPointer;
+                                               break;
+                                       } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
                                                break;
                                        }
                                        pos = Z_NEXT(fe_ht->arData[pos].val);
@@ -16855,6 +16861,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                              Z_TYPE_P(Z_INDIRECT(p->val)) == IS_UNDEF));
                fe_ht->nInternalPointer = ptr->pos = pos;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                ZEND_VM_INC_OPCODE();
                ZEND_VM_NEXT_OPCODE();
        } else if (EXPECTED(Z_TYPE_P(array) == IS_OBJECT)) {
@@ -16878,8 +16885,11 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                                        pos = ptr->h;
                                } else {
                                        pos = fe_ht->arHash[ptr->h & fe_ht->nTableMask];
-                                       while (pos != INVALID_IDX) {
-                                               if (fe_ht->arData[pos].h == ptr->h && pos == ptr->pos) {
+                                       while (1) {
+                                               if (pos == INVALID_IDX) {
+                                                       pos = fe_ht->nInternalPointer;
+                                                       break;
+                                               } else if (fe_ht->arData[pos].h == ptr->h && fe_ht->arData[pos].key == ptr->key) {
                                                        break;
                                                }
                                                pos = Z_NEXT(fe_ht->arData[pos].val);
@@ -16948,6 +16958,7 @@ static int ZEND_FASTCALL  ZEND_FE_FETCH_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                                      zend_check_property_access(zobj, p->key TSRMLS_CC) == FAILURE));
                        fe_ht->nInternalPointer = ptr->pos = pos;
                        ptr->h = fe_ht->arData[pos].h;
+                       ptr->key = fe_ht->arData[pos].key;
                        ZEND_VM_INC_OPCODE();
                        ZEND_VM_NEXT_OPCODE();
                } else {
@@ -34388,6 +34399,7 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                ptr->pos = pos;
                ptr->ht = fe_ht;
                ptr->h = fe_ht->arData[pos].h;
+               ptr->key = fe_ht->arData[pos].key;
                is_empty = 0;
        } else {
                zend_error(E_WARNING, "Invalid argument supplied for foreach()");