Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Zend/tests/gh19326.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
GH-19326: Calling Generator::throw() on a running generator with a non-Generator delegate crashes
--FILE--
<?php

class It implements IteratorAggregate {
public function getIterator(): Generator {
yield "";
Fiber::suspend();
}
}

function g() {
yield from new It();
}

$b = g();
$b->rewind();

$fiber = new Fiber(function () use ($b) {
$b->next();
});

$fiber->start();

try {
$b->throw(new Exception('test'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

$fiber->resume();

?>
--EXPECT--
Cannot resume an already running generator
14 changes: 12 additions & 2 deletions Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,14 @@ ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_
return ptr;
}

static void zend_generator_throw_exception(zend_generator *generator, zval *exception)
static zend_result zend_generator_throw_exception(zend_generator *generator, zval *exception)
{
if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
zval_ptr_dtor(exception);
zend_throw_error(NULL, "Cannot resume an already running generator");
return FAILURE;
}

zend_execute_data *original_execute_data = EG(current_execute_data);

/* Throw the exception in the context of the generator. Decrementing the opline
Expand All @@ -519,6 +525,8 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce
}

EG(current_execute_data) = original_execute_data;

return SUCCESS;
}

static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
Expand Down Expand Up @@ -1026,7 +1034,9 @@ ZEND_METHOD(Generator, throw)
if (generator->execute_data) {
zend_generator *root = zend_generator_get_current(generator);

zend_generator_throw_exception(root, exception);
if (zend_generator_throw_exception(root, exception) == FAILURE) {
return;
}

zend_generator_resume(generator);

Expand Down
Loading