]> granicus.if.org Git - php/commitdiff
Fixed bug #71980
authorNikita Popov <nikic@php.net>
Thu, 7 Apr 2016 10:25:42 +0000 (12:25 +0200)
committerNikita Popov <nikic@php.net>
Thu, 7 Apr 2016 10:29:59 +0000 (12:29 +0200)
NEWS
Zend/tests/bug71980.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/NEWS b/NEWS
index 56629821b267599fff4faea7917ae27938b9ffa1..777918212afc35b44f58c4a1d00dee5c3f342064 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,8 @@ PHP                                                                        NEWS
   . Fixed bug #69537 (__debugInfo with empty string for key gives error).
     (krakjoe)
   . Fixed bug #62059 (ArrayObject and isset are not friends). (Nikita)
+  . Fixed bug #71980 (Decorated/Nested Generator is Uncloseable in Finally).
+    (Nikita)
 
 - Curl:
   . Fixed bug #71831 (CURLOPT_NOPROXY applied as long instead of string).
diff --git a/Zend/tests/bug71980.phpt b/Zend/tests/bug71980.phpt
new file mode 100644 (file)
index 0000000..cd98f65
--- /dev/null
@@ -0,0 +1,43 @@
+--TEST--
+Bug #71980: Decorated/Nested Generator is Uncloseable in Finally
+--FILE--
+<?php
+
+class Dtor {
+    public function __destruct() {
+        echo "Dtor\n";
+    }
+}
+
+function gen1() {
+    try {
+        foreach ([42, new Dtor] as $value) {
+            yield $value;
+        }
+    } finally {
+        echo "Finally\n";
+    }
+}
+
+function gen2() {
+    try {
+        var_dump(new Dtor, yield);
+    } finally {
+        echo "Finally\n";
+    }
+}
+
+$gen = gen1();
+$gen->rewind();
+unset($gen);
+
+$gen = gen2();
+$gen->rewind();
+unset($gen);
+
+?>
+--EXPECT--
+Dtor
+Finally
+Dtor
+Finally
index 646e46b6764c2d2d62429e4848358dcffedcc0f7..89b919a48c2d10a334804ce746eaae74d92c8fd0 100644 (file)
@@ -31,7 +31,8 @@ static zend_object_handlers zend_generator_handlers;
 
 static zend_object *zend_generator_create(zend_class_entry *class_type);
 
-static void zend_generator_cleanup_unfinished_execution(zend_generator *generator) /* {{{ */
+static void zend_generator_cleanup_unfinished_execution(
+               zend_generator *generator, uint32_t catch_op_num) /* {{{ */
 {
        zend_execute_data *execute_data = generator->execute_data;
 
@@ -47,7 +48,7 @@ static void zend_generator_cleanup_unfinished_execution(zend_generator *generato
                EG(vm_stack_end) = generator->stack->end;
                EG(vm_stack) = generator->stack;
 
-               zend_cleanup_unfinished_execution(execute_data, op_num, 0);
+               zend_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
 
                generator->stack = EG(vm_stack);
                generator->stack->top = EG(vm_stack_top);
@@ -85,7 +86,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished
                /* Some cleanups are only necessary if the generator was closed
                 * before it could finish execution (reach a return statement). */
                if (UNEXPECTED(!finished_execution)) {
-                       zend_generator_cleanup_unfinished_execution(generator);
+                       zend_generator_cleanup_unfinished_execution(generator, 0);
                }
 
                /* Free closure object */
@@ -151,8 +152,11 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
        /* If a finally block was found we jump directly to it and
         * resume the generator. */
        if (finally_op_num) {
-               zval *fast_call = ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
+               zval *fast_call;
 
+               zend_generator_cleanup_unfinished_execution(generator, finally_op_num);
+
+               fast_call = ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[finally_op_end].op1.var);
                Z_OBJ_P(fast_call) = EG(exception);
                EG(exception) = NULL;
                fast_call->u2.lineno = (uint32_t)-1;