Skip to content

Commit 706bcdb

Browse files
committed
Fix printing backtrace of fake generator frame
Fixes GH-15851 Closes GH-15952
1 parent c4c45da commit 706bcdb

File tree

4 files changed

+40
-0
lines changed

4 files changed

+40
-0
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ PHP NEWS
88
. Fixed bug GH-15905 (Assertion failure for TRACK_VARS_SERVER). (cmb)
99
. Fixed bug GH-15907 (Failed assertion when promoting Serialize deprecation to
1010
exception). (ilutov)
11+
. Fixed bug GH-15851 (Segfault when printing backtrace during cleanup of
12+
nested generator frame). (ilutov)
1113

1214
- Date:
1315
. Fixed bug GH-15582: Crash when not calling parent constructor of

Zend/tests/generators/gh15851.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
GH-15851: Access on NULL when printing backtrace with freed generator
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __destruct() {
8+
debug_print_backtrace();
9+
}
10+
}
11+
12+
function bar() {
13+
yield from foo();
14+
}
15+
16+
function foo() {
17+
$foo = new Foo();
18+
yield;
19+
}
20+
21+
$gen = bar();
22+
foreach ($gen as $dummy);
23+
24+
?>
25+
--EXPECTF--
26+
#0 %s(%d): Foo->__destruct()
27+
#1 %s(%d): bar()

Zend/zend_builtin_functions.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,16 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
17251725
}
17261726

17271727
while (call && (limit == 0 || frameno < limit)) {
1728+
if (UNEXPECTED(!call->func)) {
1729+
/* This is the fake frame inserted for nested generators. Normally,
1730+
* this frame is preceded by the actual generator frame and then
1731+
* replaced by zend_generator_check_placeholder_frame() below.
1732+
* However, the frame is popped before cleaning the stack frame,
1733+
* which is observable by destructors. */
1734+
call = zend_generator_check_placeholder_frame(call);
1735+
ZEND_ASSERT(call->func);
1736+
}
1737+
17281738
zend_execute_data *prev = call->prev_execute_data;
17291739

17301740
if (!prev) {

sapi/cli/php_cli.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,7 @@ static int do_cli(int argc, char **argv) /* {{{ */
10751075
object_init_ex(&ref, pce);
10761076

10771077
memset(&execute_data, 0, sizeof(zend_execute_data));
1078+
execute_data.func = (zend_function *) &zend_pass_function;
10781079
EG(current_execute_data) = &execute_data;
10791080
zend_call_known_instance_method_with_1_params(
10801081
pce->constructor, Z_OBJ(ref), NULL, &arg);

0 commit comments

Comments
 (0)