summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/generators/throw_into_yield_from_array.phpt43
-rw-r--r--Zend/zend_generators.c6
3 files changed, 51 insertions, 0 deletions
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--
+<?php
+
+$data = [1, 2, 3];
+
+function yielditer($arr) {
+ foreach($arr as $val) {
+ yield $val;
+ }
+}
+
+function yf($in) {
+ yield from $in;
+}
+
+function test($g) {
+ var_dump($g->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);