Skip to content

Commit 6afeab7

Browse files
committed
Fix uncatchable exception thrown in generator
This procedure may be called during i_free_compiled_variables(), when EG(current_execute_data) is unfortunately already reset to the parent frame. EG(opline_before_exception) does not actually belong to this frame. Furthermore, setting opline to EG(exception_op) early will miss a later zend_rethrow_exception(), which will also miss installation of the correct EG(opline_before_exception). Fixes GH-20714
1 parent 85cb6e4 commit 6afeab7

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

Zend/tests/gh20714.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-20714: Uncatchable exception thrown in generator
3+
--FILE--
4+
<?php
5+
6+
function gen(): Generator
7+
{
8+
try {
9+
yield 1;
10+
} finally {}
11+
}
12+
13+
function process(): void
14+
{
15+
$g = gen();
16+
foreach ($g as $_) {
17+
throw new Exception('ERROR');
18+
}
19+
}
20+
21+
try {
22+
process();
23+
} catch (Exception $e) {
24+
echo "Caught\n";
25+
}
26+
27+
?>
28+
--EXPECT--
29+
Caught

Zend/zend_generators.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
321321
zend_object *old_exception = NULL;
322322
const zend_op *old_opline_before_exception = NULL;
323323
if (EG(exception)) {
324-
if (EG(current_execute_data)) {
324+
if (EG(current_execute_data)
325+
&& EG(current_execute_data)->opline
326+
&& EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) {
325327
EG(current_execute_data)->opline = EG(opline_before_exception);
326328
old_opline_before_exception = EG(opline_before_exception);
327329
}
@@ -337,7 +339,7 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
337339
zend_generator_resume(generator);
338340

339341
if (old_exception) {
340-
if (EG(current_execute_data)) {
342+
if (old_opline_before_exception) {
341343
EG(current_execute_data)->opline = EG(exception_op);
342344
EG(opline_before_exception) = old_opline_before_exception;
343345
}

0 commit comments

Comments
 (0)