summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-12-18 11:02:44 +0100
committerNikita Popov <nikita.ppv@gmail.com>2019-12-18 11:04:15 +0100
commit897d99c7a4c80f6f638600a92d14cc940473690a (patch)
tree38d49181f515924ed4a24d25ba9c3b01ad50f8e9
parent189f625e2b2a65edf406332bf87c81bab1b463af (diff)
downloadphp-git-897d99c7a4c80f6f638600a92d14cc940473690a.tar.gz
Rethrow generator exception even without active stack frame
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).
-rw-r--r--Zend/tests/generators/exception_during_shutdown.phpt30
-rw-r--r--Zend/zend_generators.c7
2 files changed, 34 insertions, 3 deletions
diff --git a/Zend/tests/generators/exception_during_shutdown.phpt b/Zend/tests/generators/exception_during_shutdown.phpt
new file mode 100644
index 0000000000..d9c8bd0175
--- /dev/null
+++ b/Zend/tests/generators/exception_during_shutdown.phpt
@@ -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
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 316de59489..ee7ae5c463 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -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 {