Skip to content

Commit f4fb77e

Browse files
committed
Fix GH-17257: UBSAN warning in ext/opcache/jit/zend_jit_vm_helpers.c
EX(opline) / opline can be stale if the IP is not stored, like in this case on a trace enter. We always need to make sure that the opline is up to date to make sure we don't use stale data. Closes GH-17260.
1 parent 956576b commit f4fb77e

File tree

5 files changed

+47
-4
lines changed

5 files changed

+47
-4
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ PHP NEWS
7474
. Fixed bug GH-17151 (Incorrect RC inference of op1 of FETCH_OBJ and
7575
INIT_METHOD_CALL). (Dmitry, ilutov)
7676
. Fixed bug GH-17246 (GC during SCCP causes segfault). (Dmitry)
77+
. Fixed bug GH-17257 (UBSAN warning in ext/opcache/jit/zend_jit_vm_helpers.c).
78+
(nielsdos, Dmitry)
7779

7880
- PCNTL:
7981
. Fix memory leak in cleanup code of pcntl_exec() when a non stringable

ext/opcache/jit/zend_jit_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_H
231231
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS);
232232

233233
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D);
234+
void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D);
234235
bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D);
235236
void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D);
236237
void ZEND_FASTCALL zend_jit_undefined_long_key_ex(zend_long key EXECUTE_DATA_DC);

ext/opcache/jit/zend_jit_ir.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,6 +3050,7 @@ static void zend_jit_setup_disasm(void)
30503050
REGISTER_HELPER(zend_jit_undefined_long_key_ex);
30513051
REGISTER_HELPER(zend_jit_undefined_string_key);
30523052
REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3053+
REGISTER_HELPER(zend_jit_copy_extra_args_helper_no_skip_recv);
30533054
REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
30543055
REGISTER_HELPER(zend_free_extra_named_params);
30553056
REGISTER_HELPER(zend_jit_free_call_frame);
@@ -10110,6 +10111,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1011010111
}
1011110112
}
1011210113
} else {
10114+
ir_ref helper;
1011310115
if (!trace || (trace->op == ZEND_JIT_TRACE_END
1011410116
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1011510117
ir_ref ip;
@@ -10123,11 +10125,14 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1012310125
ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
1012410126
}
1012510127
jit_LOAD_IP(jit, ip);
10128+
helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper);
10129+
} else {
10130+
helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper_no_skip_recv);
1012610131
}
1012710132
if (GCC_GLOBAL_REGS) {
10128-
ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10133+
ir_CALL(IR_VOID, helper);
1012910134
} else {
10130-
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit));
10135+
ir_CALL_1(IR_VOID, helper, jit_FP(jit));
1013110136
}
1013210137
}
1013310138
} else {

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D)
120120
}
121121
}
122122

123-
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
123+
static void ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(bool skip_recv EXECUTE_DATA_DC)
124124
{
125125
zend_op_array *op_array = &EX(func)->op_array;
126126

@@ -130,7 +130,7 @@ void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
130130
zval *end, *src, *dst;
131131
uint32_t type_flags = 0;
132132

133-
if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
133+
if (skip_recv && EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
134134
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
135135
#ifdef HAVE_GCC_GLOBAL_REGS
136136
opline += first_extra_arg;
@@ -166,6 +166,16 @@ void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
166166
}
167167
}
168168

169+
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
170+
{
171+
zend_jit_copy_extra_args_helper_ex(true EXECUTE_DATA_CC);
172+
}
173+
174+
void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D)
175+
{
176+
zend_jit_copy_extra_args_helper_ex(false EXECUTE_DATA_CC);
177+
}
178+
169179
bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D)
170180
{
171181
zend_execute_data *call = (zend_execute_data *) opline;

ext/opcache/tests/jit/gh17257.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-17257 (SEGV ext/opcache/jit/zend_jit_vm_helpers.c)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.jit_buffer_size=32M
7+
opcache.jit=1254
8+
opcache.jit_hot_func=1
9+
--FILE--
10+
<?php
11+
function get_const() {
12+
}
13+
function test() {
14+
call_user_func('get_const', 1); // need an extra arg to trigger the issue
15+
}
16+
function main(){
17+
for ($i = 0; $i < 10; $i++) {
18+
test();
19+
}
20+
echo "Done\n";
21+
}
22+
main();
23+
?>
24+
--EXPECT--
25+
Done

0 commit comments

Comments
 (0)