]> granicus.if.org Git - php/commitdiff
Fix OSS Fuzz issue: yielding from an aborted generator
authorBob Weinand <bobwei9@hotmail.com>
Tue, 15 Sep 2020 18:07:25 +0000 (20:07 +0200)
committerBob Weinand <bobwei9@hotmail.com>
Tue, 15 Sep 2020 18:07:33 +0000 (20:07 +0200)
Zend/tests/generators/yield_from_aborted_generator_with_children.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/generators/yield_from_aborted_generator_with_children.phpt b/Zend/tests/generators/yield_from_aborted_generator_with_children.phpt
new file mode 100644 (file)
index 0000000..7074e40
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+Impossible to yield from a generator which already failed, nested version
+--FILE--
+<?php
+
+function from() {
+    yield 0;
+    throw new Exception();
+}
+function gen($gen) {
+    yield from $gen;
+}
+
+$gen1 = from();
+$gen2 = gen($gen1);
+$gen3 = gen($gen1);
+try {
+    $gen2->next();
+} catch (Exception $e) {
+    unset($gen2);
+}
+$gen3->next();
+
+?>
+--EXPECTF--
+Fatal error: Uncaught Error: Generator passed to yield from was aborted without proper return and is unable to continue in %s:%d
+Stack trace:
+#0 [internal function]: gen(Object(Generator))
+#1 %s(%d): Generator->next()
+#2 {main}
+  thrown in %s on line %d
index 02a5e2c96348b4d16cb398fcf2a23d1cbe1c8e8f..59a49cb4131ab67e6a7bf09839dd14dc07ef241a 100644 (file)
@@ -8033,7 +8033,12 @@ ZEND_VM_C_LABEL(yield_from_try_again):
                        Z_ADDREF_P(val);
                        FREE_OP1();
 
-                       if (Z_ISUNDEF(new_gen->retval)) {
+                       if (UNEXPECTED(new_gen->execute_data == NULL)) {
+                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
+                               zval_ptr_dtor(val);
+                               UNDEF_RESULT();
+                               HANDLE_EXCEPTION();
+                       } else if (Z_ISUNDEF(new_gen->retval)) {
                                if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
                                        zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
                                        zval_ptr_dtor(val);
@@ -8042,11 +8047,6 @@ ZEND_VM_C_LABEL(yield_from_try_again):
                                } else {
                                        zend_generator_yield_from(generator, new_gen);
                                }
-                       } else if (UNEXPECTED(new_gen->execute_data == NULL)) {
-                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
-                               zval_ptr_dtor(val);
-                               UNDEF_RESULT();
-                               HANDLE_EXCEPTION();
                        } else {
                                if (RETURN_VALUE_USED(opline)) {
                                        ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);
index e03712f86828cf4da138a8afe2fc395442ed9262..0b1795f3eee3064a5cf9bd1f3ae40f97cb83c90b 100644 (file)
@@ -5376,7 +5376,12 @@ yield_from_try_again:
 
                        Z_ADDREF_P(val);
 
-                       if (Z_ISUNDEF(new_gen->retval)) {
+                       if (UNEXPECTED(new_gen->execute_data == NULL)) {
+                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
+                               zval_ptr_dtor(val);
+                               UNDEF_RESULT();
+                               HANDLE_EXCEPTION();
+                       } else if (Z_ISUNDEF(new_gen->retval)) {
                                if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
                                        zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
                                        zval_ptr_dtor(val);
@@ -5385,11 +5390,6 @@ yield_from_try_again:
                                } else {
                                        zend_generator_yield_from(generator, new_gen);
                                }
-                       } else if (UNEXPECTED(new_gen->execute_data == NULL)) {
-                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
-                               zval_ptr_dtor(val);
-                               UNDEF_RESULT();
-                               HANDLE_EXCEPTION();
                        } else {
                                if (RETURN_VALUE_USED(opline)) {
                                        ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);
@@ -14615,7 +14615,12 @@ yield_from_try_again:
                        Z_ADDREF_P(val);
                        zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
 
-                       if (Z_ISUNDEF(new_gen->retval)) {
+                       if (UNEXPECTED(new_gen->execute_data == NULL)) {
+                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
+                               zval_ptr_dtor(val);
+                               UNDEF_RESULT();
+                               HANDLE_EXCEPTION();
+                       } else if (Z_ISUNDEF(new_gen->retval)) {
                                if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
                                        zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
                                        zval_ptr_dtor(val);
@@ -14624,11 +14629,6 @@ yield_from_try_again:
                                } else {
                                        zend_generator_yield_from(generator, new_gen);
                                }
-                       } else if (UNEXPECTED(new_gen->execute_data == NULL)) {
-                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
-                               zval_ptr_dtor(val);
-                               UNDEF_RESULT();
-                               HANDLE_EXCEPTION();
                        } else {
                                if (RETURN_VALUE_USED(opline)) {
                                        ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);
@@ -39261,7 +39261,12 @@ yield_from_try_again:
 
                        Z_ADDREF_P(val);
 
-                       if (Z_ISUNDEF(new_gen->retval)) {
+                       if (UNEXPECTED(new_gen->execute_data == NULL)) {
+                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
+                               zval_ptr_dtor(val);
+                               UNDEF_RESULT();
+                               HANDLE_EXCEPTION();
+                       } else if (Z_ISUNDEF(new_gen->retval)) {
                                if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
                                        zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
                                        zval_ptr_dtor(val);
@@ -39270,11 +39275,6 @@ yield_from_try_again:
                                } else {
                                        zend_generator_yield_from(generator, new_gen);
                                }
-                       } else if (UNEXPECTED(new_gen->execute_data == NULL)) {
-                               zend_throw_error(NULL, "Generator passed to yield from was aborted without proper return and is unable to continue");
-                               zval_ptr_dtor(val);
-                               UNDEF_RESULT();
-                               HANDLE_EXCEPTION();
                        } else {
                                if (RETURN_VALUE_USED(opline)) {
                                        ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);