Skip to content

Commit 7b4798f

Browse files
committed
Fix GH-18847: set EX(opline) when the tracing JIT enters a call frame
The tracing JIT enters a callee frame without writing EX(opline) to memory; it keeps the opline in the IP register and writes it back lazily. When a fatal error is raised before that first store, such as an out-of-memory while the callee's first opcode pushes its own call frame, zend_fetch_debug_backtrace() dereferences the NULL EX(opline). Materialize it at entry, as the observer path already did behind ZEND_OBSERVER_ENABLED. Fixes GH-18847
1 parent 7c9fcfd commit 7b4798f

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

ext/opcache/jit/zend_jit_ir.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10436,6 +10436,13 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1043610436
ir_MERGE_WITH_EMPTY_FALSE(if_need);
1043710437
}
1043810438

10439+
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10440+
ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10441+
ir_STORE(jit_EX(opline), ir_CONST_ADDR(trace[1].opline));
10442+
} else {
10443+
ir_STORE(jit_EX(opline), jit_IP(jit));
10444+
}
10445+
1043910446
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
1044010447
ir_ref observer_handler;
1044110448
ir_ref rx = jit_FP(jit);

ext/opcache/tests/jit/gh18847.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-18847 (SEGV in zend_fetch_debug_backtrace when the tracing JIT enters a frame and the memory limit is hit before opline is set)
3+
--EXTENSIONS--
4+
opcache
5+
--SKIPIF--
6+
<?php
7+
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
8+
?>
9+
--INI--
10+
opcache.enable=1
11+
opcache.enable_cli=1
12+
opcache.jit=tracing
13+
opcache.jit_buffer_size=8M
14+
fatal_error_backtraces=1
15+
memory_limit=8M
16+
--FILE--
17+
<?php
18+
function f() {
19+
static $x = f();
20+
}
21+
f();
22+
?>
23+
--EXPECTREGEX--
24+
Fatal error: Allowed memory size of \d+ bytes exhausted.*#\d+ \{main\}

0 commit comments

Comments
 (0)