]> granicus.if.org Git - php/commitdiff
Fix bug #64979: Wrong behavior of static variables in closure generators
authorNikita Popov <nikic@php.net>
Sun, 29 Sep 2013 18:18:12 +0000 (20:18 +0200)
committerNikita Popov <nikic@php.net>
Sun, 29 Sep 2013 18:18:12 +0000 (20:18 +0200)
NEWS
Zend/tests/bug64979.phpt
Zend/zend_generators.c

diff --git a/NEWS b/NEWS
index 45b264746d7c6ccc30b209ceb3f1024158270b21..1b1f9c4bdf54338f002addb1bde7dd92116ba8bf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2013, PHP 5.5.5
 
+- Core:
+  . Fixed bug #64979 (Wrong behavior of static variables in closure generators).
+    (Nikita)
+
 - CLI server:
   . Fixed bug #65633 (built-in server treat some http headers as
     case-sensitive). (Adam)
index 09de5555464204a915424418b4f1cd18a1e6a82b..5bc8e5a6ab2a4b8c297183d571f99c2711632886 100644 (file)
@@ -1,15 +1,13 @@
 --TEST--\r
-Bug #64578 (Closures with static variables can be generators)\r
---XFAIL--\r
-Bug #64979 not fixed yet.\r
+Bug #64979 (Wrong behavior of static variables in closure generators)\r
 --FILE--\r
 <?php\r
 \r
 function new_closure_gen() {\r
-       return function() { \r
-               static $foo = 0; \r
-               yield ++$foo; \r
-       };\r
+    return function() {\r
+        static $foo = 0;\r
+        yield ++$foo;\r
+    };\r
 }\r
 \r
 $closure1 = new_closure_gen();\r
@@ -20,9 +18,9 @@ $gen2 = $closure1();
 $gen3 = $closure2();\r
 \r
 foreach (array($gen1, $gen2, $gen3) as $gen) {\r
-  foreach ($gen as $val) {\r
-    print "$val\n";\r
-  }\r
+    foreach ($gen as $val) {\r
+        var_dump($val);\r
+    }\r
 }\r
 \r
 ?>\r
index 1a805bbd6d61cd4b985c6eb9c49632de56c9d156..0af20f4593fcb615ac2b572c9f808a2ca3065ebf 100644 (file)
@@ -226,6 +226,16 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
 }
 /* }}} */
 
+static void copy_closure_static_var(zval **var TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
+{
+       HashTable *target = va_arg(args, HashTable *);
+
+       SEPARATE_ZVAL_TO_MAKE_IS_REF(var);
+       Z_ADDREF_PP(var);
+       zend_hash_quick_update(target, key->arKey, key->nKeyLength, key->h, var, sizeof(zval *), NULL);
+}
+/* }}} */
+
 /* Requires globals EG(scope), EG(current_scope), EG(This),
  * EG(active_symbol_table) and EG(current_execute_data). */
 ZEND_API zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
@@ -242,7 +252,23 @@ ZEND_API zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /*
        if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
                zend_op_array *op_array_copy = (zend_op_array*)emalloc(sizeof(zend_op_array));
                *op_array_copy = *op_array;
-               function_add_ref((zend_function *) op_array_copy);
+
+               (*op_array->refcount)++;
+               op_array->run_time_cache = NULL;
+               if (op_array->static_variables) {
+                       ALLOC_HASHTABLE(op_array_copy->static_variables);
+                       zend_hash_init(
+                               op_array_copy->static_variables, 
+                               zend_hash_num_elements(op_array->static_variables),
+                               NULL, ZVAL_PTR_DTOR, 0
+                       );
+                       zend_hash_apply_with_arguments(
+                               op_array->static_variables TSRMLS_CC,
+                               (apply_func_args_t) copy_closure_static_var,
+                               1, op_array_copy->static_variables
+                       );
+               }
+
                op_array = op_array_copy;
        }