]> granicus.if.org Git - php/commitdiff
Fixed bug #62991 (Segfault with generator and closure)
authorDmitry Stogov <dmitry@zend.com>
Wed, 5 Sep 2012 05:50:55 +0000 (09:50 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 5 Sep 2012 05:50:55 +0000 (09:50 +0400)
Zend/tests/bug62991.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/Zend/tests/bug62991.phpt b/Zend/tests/bug62991.phpt
new file mode 100644 (file)
index 0000000..cb4ff93
--- /dev/null
@@ -0,0 +1,50 @@
+--TEST--
+Bug #62991 (Segfault with generator and closure)
+--FILE--
+<?php
+
+function test( array $array )
+{
+    $closure = function() use ( $array ) {
+        print_r( $array );
+        yield "hi";
+    };
+    return $closure();
+}
+
+function test2( array $array )
+{
+    $closure = function() use ( $array ) {
+        print_r( $array );
+        yield "hi";
+    };
+    return $closure; // if you return the $closure and call it outside this function it works.
+}
+
+$generator = test(array( 1, 2, 3 ) );
+foreach($generator as $something) {
+}
+
+$generator = test2(array( 1, 2, 3 ) );
+foreach($generator() as $something) {
+}
+
+
+$generator = test2(array( 1, 2, 3 ) );
+
+echo "okey\n";
+?>
+--EXPECT--
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+)
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+)
+okey
index c22d745bc362d471d40a40ee0016b5f3c5cada9d..3d4fdd2c5ff1c95b50dc2d8c48a25ed52a06a921 100644 (file)
@@ -154,6 +154,12 @@ void zend_generator_close(zend_generator *generator, zend_bool finished_executio
                        efree(prev_execute_data);
                }
 
+               /* Free a clone of closure */
+               if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
+                       destroy_op_array(op_array TSRMLS_CC);
+                       efree(op_array);
+               }
+
                efree(execute_data);
                generator->execute_data = NULL;
        }
@@ -358,6 +364,14 @@ zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
        zval *return_value;
        zend_generator *generator;
 
+       /* Create a clone of closure, because it may be destroyed */
+       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(op_array_copy);
+               op_array = op_array_copy;
+       }
+       
        /* Create new execution context. We have to back up and restore
         * EG(current_execute_data) and EG(opline_ptr) here because the function
         * modifies it. */