From 2de8915dead83fbefcb50288f5ff1c20c9967510 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Wed, 25 Nov 2015 23:09:44 +0100 Subject: [PATCH] Fixed bug causing exception not being thrown immediately into a generator yielding from an array --- NEWS | 2 + .../throw_into_yield_from_array.phpt | 43 +++++++++++++++++++ Zend/zend_generators.c | 6 +++ 3 files changed, 51 insertions(+) create mode 100644 Zend/tests/generators/throw_into_yield_from_array.phpt diff --git a/NEWS b/NEWS index 496037b808..bd6f283b1f 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,8 @@ PHP NEWS to not be accepted as type name. (Bob) . Fixed bug #70904 (yield from incorrectly marks valid generator as finished). (Bob) + . Fixed exception not being thrown immediately into a generator yielding + from an array. (Bob) - Mysqlnd: . Fixed bug #68077 (LOAD DATA LOCAL INFILE / open_basedir restriction). diff --git a/Zend/tests/generators/throw_into_yield_from_array.phpt b/Zend/tests/generators/throw_into_yield_from_array.phpt new file mode 100644 index 0000000000..b1571f6639 --- /dev/null +++ b/Zend/tests/generators/throw_into_yield_from_array.phpt @@ -0,0 +1,43 @@ +--TEST-- +Throwing into a generator yielding from an array/iterator +--FILE-- +current()); + try { + $g->throw(new Exception("Exception!")); + } catch (Exception $e) { + echo "{$e->getMessage()}\n"; + } + var_dump($g->current()); +} + +$yfiter = yf($data); +$yfgen = yf(yielditer($data)); + +test(yf($data)); +echo "\n"; +test(yf(yielditer($data))); + +?> +--EXPECT-- +int(1) +Exception! +NULL + +int(1) +Exception! +NULL diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 9ef63df8d6..eb7d40e7fc 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -287,6 +287,12 @@ ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_ static void zend_generator_throw_exception(zend_generator *generator, zval *exception) { + /* if we don't stop an array/iterator yield from, the exception will only reach the generator after the values were all iterated over */ + if (UNEXPECTED(Z_TYPE(generator->values) != IS_UNDEF)) { + zval_ptr_dtor(&generator->values); + ZVAL_UNDEF(&generator->values); + } + /* Throw the exception in the context of the generator. Decrementing the opline * to pretend the exception happened during the YIELD opcode. */ zend_execute_data *original_execute_data = EG(current_execute_data); -- 2.40.0