Fix OSS Fuzz issue: yielding from an aborted generator

This commit is contained in:
Bob Weinand 2020-09-15 20:07:25 +02:00
parent 7a95e943d6
commit 6d538e83aa
3 changed files with 55 additions and 24 deletions

View file

@ -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

View file

@ -8033,7 +8033,12 @@ ZEND_VM_C_LABEL(yield_from_try_again):
Z_ADDREF_P(val); Z_ADDREF_P(val);
FREE_OP1(); 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)) { if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
zend_throw_error(NULL, "Impossible to yield from the Generator being currently run"); zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
zval_ptr_dtor(val); zval_ptr_dtor(val);
@ -8042,11 +8047,6 @@ ZEND_VM_C_LABEL(yield_from_try_again):
} else { } else {
zend_generator_yield_from(generator, new_gen); 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 { } else {
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval); ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);

View file

@ -5376,7 +5376,12 @@ yield_from_try_again:
Z_ADDREF_P(val); 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)) { if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
zend_throw_error(NULL, "Impossible to yield from the Generator being currently run"); zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
zval_ptr_dtor(val); zval_ptr_dtor(val);
@ -5385,11 +5390,6 @@ yield_from_try_again:
} else { } else {
zend_generator_yield_from(generator, new_gen); 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 { } else {
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval); ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);
@ -14615,7 +14615,12 @@ yield_from_try_again:
Z_ADDREF_P(val); Z_ADDREF_P(val);
zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); 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)) { if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
zend_throw_error(NULL, "Impossible to yield from the Generator being currently run"); zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
zval_ptr_dtor(val); zval_ptr_dtor(val);
@ -14624,11 +14629,6 @@ yield_from_try_again:
} else { } else {
zend_generator_yield_from(generator, new_gen); 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 { } else {
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval); ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);
@ -39261,7 +39261,12 @@ yield_from_try_again:
Z_ADDREF_P(val); 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)) { if (UNEXPECTED(zend_generator_get_current(new_gen) == generator)) {
zend_throw_error(NULL, "Impossible to yield from the Generator being currently run"); zend_throw_error(NULL, "Impossible to yield from the Generator being currently run");
zval_ptr_dtor(val); zval_ptr_dtor(val);
@ -39270,11 +39275,6 @@ yield_from_try_again:
} else { } else {
zend_generator_yield_from(generator, new_gen); 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 { } else {
if (RETURN_VALUE_USED(opline)) { if (RETURN_VALUE_USED(opline)) {
ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval); ZVAL_COPY(EX_VAR(opline->result.var), &new_gen->retval);