Skip to content

Commit 1db1c7f

Browse files
khasinskiiluuu1994
authored andcommitted
Fix segfault in Tracing JIT with object reference (phpGH-20818)
When FE_RESET_RW executes, it converts the CV to a reference before checking if the array/object is empty. However, when the JIT creates exit points for FE_RESET_RW in zend_jit_trace_handler(), it wasn't updating the stack type for op1 to reflect this change. This caused side traces compiled from these exit points to have incorrect type information. The side trace's CV cleanup code would see IS_OBJECT and generate a direct call to zend_objects_store_del(), but the actual value was a zend_reference*, causing a segfault. The fix adds ZEND_FE_RESET_RW to the list of opcodes that temporarily set their op1 stack type to IS_UNKNOWN before creating exit points. This follows the same pattern used for ZEND_BIND_INIT_STATIC_OR_JMP. When IS_UNKNOWN, the JIT falls back to SSA type info which correctly includes MAY_BE_REF for FE_RESET_RW's op1_def. Fixes phpGH-20818 Closes phpGH-20948
1 parent 32c0245 commit 1db1c7f

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ PHP NEWS
2525
. Fixed bug GH-20836 (Stack overflow in mb_convert_variables with
2626
recursive array references). (alexandre-daubois)
2727

28+
- Opcache:
29+
. Fixed bug GH-20818 (Segfault in Tracing JIT with object reference).
30+
(khasinski)
31+
2832
- Phar:
2933
. Fixed bug GH-20882 (buildFromIterator breaks with missing base directory).
3034
(ndossche)

ext/opcache/jit/zend_jit_ir.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16938,6 +16938,7 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr
1693816938
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
1693916939
}
1694016940
break;
16941+
case ZEND_FE_RESET_RW:
1694116942
case ZEND_BIND_INIT_STATIC_OR_JMP:
1694216943
if (opline->op1_type == IS_CV) {
1694316944
old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
@@ -16962,6 +16963,7 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr
1696216963
SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
1696316964
}
1696416965
break;
16966+
case ZEND_FE_RESET_RW:
1696516967
case ZEND_BIND_INIT_STATIC_OR_JMP:
1696616968
if (opline->op1_type == IS_CV) {
1696716969
SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);

ext/opcache/tests/jit/gh20818.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-20818 (Segfault in Tracing JIT with Object Reference)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.jit=tracing
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
11+
function process($data) {
12+
foreach ($data as &$v) {}
13+
}
14+
15+
$data = [
16+
(object) ["" => 1],
17+
(object) ["" => 1],
18+
(object) [],
19+
];
20+
21+
for ($i = 0; $i < 200; $i += 1) {
22+
foreach ($data as $entry) {
23+
process($entry);
24+
}
25+
}
26+
27+
echo "Done\n";
28+
?>
29+
--EXPECT--
30+
Done

0 commit comments

Comments
 (0)