Skip to content

Commit 7de8923

Browse files
committed
Fix GH-18847: save EX(opline) before extending the VM stack on all VMs
db7193f sets EX(opline) before zend_vm_stack_extend() so that a fatal error raised while a call frame is pushed can walk the backtrace, but the wrappers doing it were compiled only for global-register CALL/HYBRID builds. Elsewhere the save is skipped, and a frame entered by the tracing JIT still holds a NULL opline when its first INIT_FCALL hits the memory limit. Thread execute_data and opline into the wrappers so that every VM kind performs the save. Fixes GH-18847 Closes GH-22542
1 parent 16da1f5 commit 7de8923

5 files changed

Lines changed: 42 additions & 20 deletions

File tree

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ PHP NEWS
88
failure path). (David Carlier)
99
. Fixed bug GH-18985 (Wrong line numbers for match with constant arms).
1010
(ilutov)
11+
. Fixed bug GH-18847 (SEGV in zend_fetch_debug_backtrace() when the memory
12+
limit is reached while the tracing JIT enters a call frame). (Arnaud,
13+
iliaal)
1114

1215
- DOM:
1316
. Fixed bug GH-22825 (DOMElement::setAttribute() fails silently when the DTD

Zend/zend_execute.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5729,9 +5729,8 @@ ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named
57295729
zend_array_release(extra_named_params);
57305730
}
57315731

5732-
#if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
57335732
/* Special versions of functions that sets EX(opline) before calling zend_vm_stack_extend() */
5734-
static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope) /* {{{ */
5733+
static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope EXECUTE_DATA_DC OPLINE_DC) /* {{{ */
57355734
{
57365735
zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);
57375736

@@ -5750,17 +5749,13 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(u
57505749
}
57515750
} /* }}} */
57525751

5753-
static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope) /* {{{ */
5752+
static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, void *object_or_called_scope EXECUTE_DATA_DC OPLINE_DC) /* {{{ */
57545753
{
57555754
uint32_t used_stack = zend_vm_calc_used_stack(num_args, func);
57565755

57575756
return _zend_vm_stack_push_call_frame_ex(used_stack, call_info,
5758-
func, num_args, object_or_called_scope);
5757+
func, num_args, object_or_called_scope EXECUTE_DATA_CC OPLINE_CC);
57595758
} /* }}} */
5760-
#else
5761-
# define _zend_vm_stack_push_call_frame_ex zend_vm_stack_push_call_frame_ex
5762-
# define _zend_vm_stack_push_call_frame zend_vm_stack_push_call_frame
5763-
#endif
57645759

57655760
#ifdef ZEND_VM_TRACE_HANDLERS
57665761
# include "zend_vm_trace_handlers.h"

Zend/zend_vm_def.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3912,7 +3912,7 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
39123912
CACHE_PTR(opline->result.num, fbc);
39133913
}
39143914
call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
3915-
fbc, opline->extended_value, NULL);
3915+
fbc, opline->extended_value, NULL EXECUTE_DATA_CC OPLINE_CC);
39163916
call->prev_execute_data = EX(call);
39173917
EX(call) = call;
39183918

@@ -4070,7 +4070,7 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT)
40704070
}
40714071

40724072
call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION,
4073-
fbc, opline->extended_value, NULL);
4073+
fbc, opline->extended_value, NULL EXECUTE_DATA_CC OPLINE_CC);
40744074
call->prev_execute_data = EX(call);
40754075
EX(call) = call;
40764076

@@ -4099,7 +4099,7 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
40994099

41004100
call = _zend_vm_stack_push_call_frame_ex(
41014101
opline->op1.num, ZEND_CALL_NESTED_FUNCTION,
4102-
fbc, opline->extended_value, NULL);
4102+
fbc, opline->extended_value, NULL EXECUTE_DATA_CC OPLINE_CC);
41034103
call->prev_execute_data = EX(call);
41044104
EX(call) = call;
41054105

@@ -4118,7 +4118,7 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_INIT_FCALL, Z_EXTRA_P(RT_CONSTANT(op, op->op2
41184118
}
41194119
call = _zend_vm_stack_push_call_frame_ex(
41204120
opline->op1.num, ZEND_CALL_NESTED_FUNCTION,
4121-
fbc, opline->extended_value, NULL);
4121+
fbc, opline->extended_value, NULL EXECUTE_DATA_CC OPLINE_CC);
41224122
call->prev_execute_data = EX(call);
41234123
EX(call) = call;
41244124
ZEND_VM_NEXT_OPCODE();

Zend/zend_vm_execute.h

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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)