summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2016-04-07 12:25:42 +0200
committerNikita Popov <nikic@php.net>2016-04-07 12:29:59 +0200
commitaad4ecebf83568f41f5b27b274f988710ce53646 (patch)
treeffa9300a58f21f468728a0f9720db9038302b3b3
parent079239a7cececfca9344b24f5bb1cca127d4bcc9 (diff)
downloadphp-git-aad4ecebf83568f41f5b27b274f988710ce53646.tar.gz
Fixed bug #71980
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug71980.phpt43
-rw-r--r--Zend/zend_generators.c12
3 files changed, 53 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 56629821b2..777918212a 100644
--- 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
index 0000000000..cd98f6567d
--- /dev/null
+++ b/Zend/tests/bug71980.phpt
@@ -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
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 646e46b676..89b919a48c 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -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;