]> granicus.if.org Git - php/commitdiff
Avoid op_num = -1 in unfinished generator cleanup
authorNikita Popov <nikic@php.net>
Tue, 23 Jun 2015 18:13:25 +0000 (20:13 +0200)
committerNikita Popov <nikic@php.net>
Tue, 23 Jun 2015 18:17:30 +0000 (20:17 +0200)
Also add two tests showing that the -1 substraction in the
computation of op_num is really necessary.

Zend/tests/generators/aborted_yield_during_nested_fcalls.phpt [new file with mode: 0644]
Zend/tests/generators/aborted_yield_during_switch.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/Zend/tests/generators/aborted_yield_during_nested_fcalls.phpt b/Zend/tests/generators/aborted_yield_during_nested_fcalls.phpt
new file mode 100644 (file)
index 0000000..9d3bea3
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+Aborted yield during nested calls
+--FILE--
+<?php
+
+function func() {}
+
+function gen($x) {
+    func(func($x, $x, func($x, yield)));
+}
+
+$gen = gen("x");
+$gen->rewind();
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/tests/generators/aborted_yield_during_switch.phpt b/Zend/tests/generators/aborted_yield_during_switch.phpt
new file mode 100644 (file)
index 0000000..1b1d6a1
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+Aborted yield during switch
+--FILE--
+<?php
+
+function gen($x) {
+    switch ($x."y") {
+        default:
+            yield;
+    }
+}
+
+$gen = gen("x");
+$gen->rewind();
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
index 6a04ebd123b8fd0cf12c3f5046f2e57582956d4f..96592fa95d5d4c090c304f2e4051b24e9bcf12fb 100644 (file)
@@ -34,15 +34,16 @@ static zend_object *zend_generator_create(zend_class_entry *class_type);
 static void zend_generator_cleanup_unfinished_execution(zend_generator *generator) /* {{{ */
 {
        zend_execute_data *execute_data = generator->execute_data;
-       /* -1 required because we want the last run opcode, not the next to-be-run one. */
-       uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1;
 
        if (generator->send_target) {
-               if (Z_REFCOUNTED_P(generator->send_target)) Z_DELREF_P(generator->send_target);
+               Z_TRY_DELREF_P(generator->send_target);
                generator->send_target = NULL;
        }
 
-       {
+       if (execute_data->opline != execute_data->func->op_array.opcodes) {
+               /* -1 required because we want the last run opcode, not the next to-be-run one. */
+               uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1;
+
                /* There may be calls to zend_vm_stack_free_call_frame(), which modifies the VM stack
                 * globals, so need to load/restore those. */
                zend_vm_stack original_stack = EG(vm_stack);