Skip to content

Commit 5ab2c02

Browse files
authored
Fix GH-9011: Assertion failure with tracing JIT (#17042)
* Fix GH-9011: Assertion failure with tracing JIT * Temporay SKIP the test on 64-bit Windows because of GH-15709
1 parent 7eb7f62 commit 5ab2c02

File tree

3 files changed

+79
-59
lines changed

3 files changed

+79
-59
lines changed

Zend/tests/traits/bugs/gh13177.phpt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
--TEST--
22
GH-13177 (PHP 8.3.2: final private constructor not allowed when used in trait)
3+
--SKIPIF--
4+
<?php
5+
$tracing = extension_loaded("Zend OPcache")
6+
&& ($conf = opcache_get_configuration()["directives"])
7+
&& array_key_exists("opcache.jit", $conf)
8+
&& $conf["opcache.jit"] === "tracing";
9+
if (PHP_OS_FAMILY === "Windows" && PHP_INT_SIZE == 8 && $tracing) {
10+
$url = "https://github.com/php/php-src/issues/15709";
11+
die("xfail Test fails on Windows x64 (VS17) and tracing JIT; see $url");
12+
}
13+
?>
314
--FILE--
415
<?php
516

ext/opcache/jit/zend_jit_ir.c

Lines changed: 41 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8638,24 +8638,47 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
86388638
return 1;
86398639
}
86408640

8641+
static int zend_jit_func_guard(zend_jit_ctx *jit, ir_ref func_ref, const zend_function *func, const void *exit_addr)
8642+
{
8643+
if (func->type == ZEND_USER_FUNCTION &&
8644+
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8645+
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8646+
!func->common.function_name)) {
8647+
const zend_op *opcodes = func->op_array.opcodes;
8648+
8649+
// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8650+
ir_GUARD(
8651+
ir_EQ(
8652+
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8653+
ir_CONST_ADDR(opcodes)),
8654+
ir_CONST_ADDR(exit_addr));
8655+
#ifdef ZEND_WIN32
8656+
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
8657+
// ASLR may cause different addresses in different workers. Check for the internal function handler.
8658+
// JIT: if (call->func.internal_function.handler != handler) goto exit_addr;
8659+
ir_GUARD(
8660+
ir_EQ(
8661+
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler))),
8662+
ir_CONST_FC_FUNC(func->internal_function.handler)),
8663+
ir_CONST_ADDR(exit_addr));
8664+
#endif
8665+
} else {
8666+
// JIT: if (call->func != func) goto exit_addr;
8667+
ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8668+
}
8669+
8670+
return 1;
8671+
}
8672+
86418673
static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
86428674
{
86438675
int32_t exit_point;
86448676
const void *exit_addr;
86458677
ir_ref call;
86468678

8647-
if (func->type == ZEND_INTERNAL_FUNCTION) {
8648-
#ifdef ZEND_WIN32
8649-
// TODO: ASLR may cause different addresses in different workers ???
8650-
return 0;
8651-
#endif
8652-
} else if (func->type == ZEND_USER_FUNCTION) {
8653-
if (!zend_accel_in_shm(func->op_array.opcodes)) {
8654-
/* op_array and op_array->opcodes are not persistent. We can't link. */
8655-
return 0;
8656-
}
8657-
} else {
8658-
ZEND_UNREACHABLE();
8679+
if (func->type == ZEND_USER_FUNCTION
8680+
&& !zend_accel_in_shm(func->op_array.opcodes)) {
8681+
/* op_array and op_array->opcodes are not persistent. We can't link. */
86598682
return 0;
86608683
}
86618684

@@ -8673,24 +8696,7 @@ static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const ze
86738696
level--;
86748697
}
86758698

8676-
if (func->type == ZEND_USER_FUNCTION &&
8677-
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8678-
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8679-
!func->common.function_name)) {
8680-
const zend_op *opcodes = func->op_array.opcodes;
8681-
8682-
// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8683-
ir_GUARD(
8684-
ir_EQ(
8685-
ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8686-
ir_CONST_ADDR(opcodes)),
8687-
ir_CONST_ADDR(exit_addr));
8688-
} else {
8689-
// JIT: if (call->func != func) goto exit_addr;
8690-
ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8691-
}
8692-
8693-
return 1;
8699+
return zend_jit_func_guard(jit, ir_LOAD_A(jit_CALL(call, func)), func, exit_addr);
86948700
}
86958701

86968702
static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack)
@@ -8797,17 +8803,8 @@ static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_
87978803
}
87988804
if (!func || opline->opcode == ZEND_INIT_FCALL) {
87998805
ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8800-
} else if (func->type == ZEND_USER_FUNCTION
8801-
&& !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8802-
const zend_op *opcodes = func->op_array.opcodes;
8803-
8804-
ir_GUARD(
8805-
ir_EQ(
8806-
ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8807-
ir_CONST_ADDR(opcodes)),
8808-
ir_CONST_ADDR(exit_addr));
8809-
} else {
8810-
ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8806+
} else if (!zend_jit_func_guard(jit, ref, func, exit_addr)) {
8807+
return 0;
88118808
}
88128809
} else {
88138810
jit_SET_EX_OPLINE(jit, opline);
@@ -9013,11 +9010,7 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
90139010
if ((!func || zend_jit_may_be_modified(func, op_array))
90149011
&& trace
90159012
&& trace->op == ZEND_JIT_TRACE_INIT_CALL
9016-
&& trace->func
9017-
#ifdef _WIN32
9018-
&& trace->func->type != ZEND_INTERNAL_FUNCTION
9019-
#endif
9020-
) {
9013+
&& trace->func) {
90219014
int32_t exit_point;
90229015
const void *exit_addr;
90239016

@@ -9032,19 +9025,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
90329025

90339026
func = (zend_function*)trace->func;
90349027

9035-
if (func->type == ZEND_USER_FUNCTION &&
9036-
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9037-
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9038-
!func->common.function_name)) {
9039-
const zend_op *opcodes = func->op_array.opcodes;
9040-
9041-
ir_GUARD(
9042-
ir_EQ(
9043-
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9044-
ir_CONST_ADDR(opcodes)),
9045-
ir_CONST_ADDR(exit_addr));
9046-
} else {
9047-
ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9028+
if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9029+
return 0;
90489030
}
90499031
}
90509032

ext/opcache/tests/jit/gh9011.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
GH-9011: Assertion failure with tracing JIT
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
--FILE--
8+
<?php
9+
$foo = [];
10+
$foo[] = new \Exception(); /* Native interface implemented Native instance */
11+
$foo[] = new class () implements \Stringable /* Native interface implemented User instance */
12+
{
13+
public function __toString(): string
14+
{
15+
return "bar";
16+
}
17+
};
18+
19+
foreach ($foo as $baz) {
20+
for ($i = 0; $i < 64; $i++) {
21+
$baz->__toString();
22+
}
23+
}
24+
?>
25+
DONE
26+
--EXPECT--
27+
DONE

0 commit comments

Comments
 (0)