]> granicus.if.org Git - php/commitdiff
Rethrow generator exception even without active stack frame
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 18 Dec 2019 10:02:44 +0000 (11:02 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 18 Dec 2019 10:04:15 +0000 (11:04 +0100)
Finally blocks in generators may be invoked during shutdown, in
which case we don't have a stack frame. Similar to what
zend_call_function does, we still need to rethrow these exceptions,
otherwise they will be hidden (and leak).

Zend/tests/generators/exception_during_shutdown.phpt [new file with mode: 0644]
Zend/zend_generators.c

diff --git a/Zend/tests/generators/exception_during_shutdown.phpt b/Zend/tests/generators/exception_during_shutdown.phpt
new file mode 100644 (file)
index 0000000..d9c8bd0
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Generator exceptions during shutdown should not be swallowed
+--FILE--
+<?php
+
+function gen() {
+    try {
+        echo "before yield\n";
+        yield;
+        echo "after yield\n";
+    } finally {
+        echo "before yield in finally\n";
+        yield;
+        echo "after yield in finally\n";
+    }
+    echo "after finally\n";
+}
+
+$gen = gen();
+$gen->rewind();
+
+?>
+--EXPECTF--
+before yield
+before yield in finally
+
+Fatal error: Uncaught Error: Cannot yield from finally in a force-closed generator in %s:%d
+Stack trace:
+#0 {main}
+  thrown in %s on line %d
index 316de594895e0d60a5956689369962d449b51ae9..ee7ae5c4637da73bb81e2f76133935c0073b7cab 100644 (file)
@@ -827,9 +827,10 @@ try_again:
                if (UNEXPECTED(EG(exception) != NULL)) {
                        if (generator == orig_generator) {
                                zend_generator_close(generator, 0);
-                               if (EG(current_execute_data) &&
-                                   EG(current_execute_data)->func &&
-                                   ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
+                               if (!EG(current_execute_data)) {
+                                       zend_throw_exception_internal(NULL);
+                               } else if (EG(current_execute_data)->func &&
+                                               ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
                                        zend_rethrow_exception(EG(current_execute_data));
                                }
                        } else {