summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Weinand <bobwei9@hotmail.com>2020-09-15 20:07:25 +0200
committerBob Weinand <bobwei9@hotmail.com>2020-09-15 20:07:33 +0200
commit6d538e83aa1e98694402eea5433e38d387f8729a (patch)
treed4d89d3cd6aa0fc412d389ef1d036eaf30167dff
parent7a95e943d642e05532979a06221c476183eac7e4 (diff)
downloadphp-git-6d538e83aa1e98694402eea5433e38d387f8729a.tar.gz
Fix OSS Fuzz issue: yielding from an aborted generator
-rw-r--r--Zend/tests/generators/yield_from_aborted_generator_with_children.phpt31
-rw-r--r--Zend/zend_vm_def.h12
-rw-r--r--Zend/zend_vm_execute.h36
3 files changed, 55 insertions, 24 deletions
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
index 0000000000..7074e40ab6
--- /dev/null
+++ b/Zend/tests/generators/yield_from_aborted_generator_with_children.phpt
@@ -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
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 02a5e2c963..59a49cb413 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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);
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index e03712f868..0b1795f3ee 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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);