Skip to content

Commit 7717df2

Browse files
committed
Merge branch 'PHP-8.4'
* PHP-8.4: Fix GH-9011: Assertion failure with tracing JIT (#17042)
2 parents 00bd5e2 + 5ab2c02 commit 7717df2

File tree

3 files changed

+82
-77
lines changed

3 files changed

+82
-77
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: 44 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8653,24 +8653,47 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
86538653
return 1;
86548654
}
86558655

8656+
static int zend_jit_func_guard(zend_jit_ctx *jit, ir_ref func_ref, const zend_function *func, const void *exit_addr)
8657+
{
8658+
if (func->type == ZEND_USER_FUNCTION &&
8659+
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8660+
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8661+
!func->common.function_name)) {
8662+
const zend_op *opcodes = func->op_array.opcodes;
8663+
8664+
// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8665+
ir_GUARD(
8666+
ir_EQ(
8667+
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8668+
ir_CONST_ADDR(opcodes)),
8669+
ir_CONST_ADDR(exit_addr));
8670+
#ifdef ZEND_WIN32
8671+
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
8672+
// ASLR may cause different addresses in different workers. Check for the internal function handler.
8673+
// JIT: if (call->func.internal_function.handler != handler) goto exit_addr;
8674+
ir_GUARD(
8675+
ir_EQ(
8676+
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler))),
8677+
ir_CONST_FC_FUNC(func->internal_function.handler)),
8678+
ir_CONST_ADDR(exit_addr));
8679+
#endif
8680+
} else {
8681+
// JIT: if (call->func != func) goto exit_addr;
8682+
ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8683+
}
8684+
8685+
return 1;
8686+
}
8687+
86568688
static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
86578689
{
86588690
int32_t exit_point;
86598691
const void *exit_addr;
86608692
ir_ref call;
86618693

8662-
if (func->type == ZEND_INTERNAL_FUNCTION) {
8663-
#ifdef ZEND_WIN32
8664-
// TODO: ASLR may cause different addresses in different workers ???
8665-
return 0;
8666-
#endif
8667-
} else if (func->type == ZEND_USER_FUNCTION) {
8668-
if (!zend_accel_in_shm(func->op_array.opcodes)) {
8669-
/* op_array and op_array->opcodes are not persistent. We can't link. */
8670-
return 0;
8671-
}
8672-
} else {
8673-
ZEND_UNREACHABLE();
8694+
if (func->type == ZEND_USER_FUNCTION
8695+
&& !zend_accel_in_shm(func->op_array.opcodes)) {
8696+
/* op_array and op_array->opcodes are not persistent. We can't link. */
86748697
return 0;
86758698
}
86768699

@@ -8688,24 +8711,7 @@ static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const ze
86888711
level--;
86898712
}
86908713

8691-
if (func->type == ZEND_USER_FUNCTION &&
8692-
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8693-
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8694-
!func->common.function_name)) {
8695-
const zend_op *opcodes = func->op_array.opcodes;
8696-
8697-
// JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8698-
ir_GUARD(
8699-
ir_EQ(
8700-
ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(call, func)), offsetof(zend_op_array, opcodes))),
8701-
ir_CONST_ADDR(opcodes)),
8702-
ir_CONST_ADDR(exit_addr));
8703-
} else {
8704-
// JIT: if (call->func != func) goto exit_addr;
8705-
ir_GUARD(ir_EQ(ir_LOAD_A(jit_CALL(call, func)), ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8706-
}
8707-
8708-
return 1;
8714+
return zend_jit_func_guard(jit, ir_LOAD_A(jit_CALL(call, func)), func, exit_addr);
87098715
}
87108716

87118717
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)
@@ -8812,17 +8818,8 @@ static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_
88128818
}
88138819
if (!func || opline->opcode == ZEND_INIT_FCALL) {
88148820
ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8815-
} else if (func->type == ZEND_USER_FUNCTION
8816-
&& !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) {
8817-
const zend_op *opcodes = func->op_array.opcodes;
8818-
8819-
ir_GUARD(
8820-
ir_EQ(
8821-
ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_op_array, opcodes))),
8822-
ir_CONST_ADDR(opcodes)),
8823-
ir_CONST_ADDR(exit_addr));
8824-
} else {
8825-
ir_GUARD(ir_EQ(ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8821+
} else if (!zend_jit_func_guard(jit, ref, func, exit_addr)) {
8822+
return 0;
88268823
}
88278824
} else {
88288825
jit_SET_EX_OPLINE(jit, opline);
@@ -9028,11 +9025,7 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
90289025
if ((!func || zend_jit_may_be_modified(func, op_array))
90299026
&& trace
90309027
&& trace->op == ZEND_JIT_TRACE_INIT_CALL
9031-
&& trace->func
9032-
#ifdef _WIN32
9033-
&& trace->func->type != ZEND_INTERNAL_FUNCTION
9034-
#endif
9035-
) {
9028+
&& trace->func) {
90369029
int32_t exit_point;
90379030
const void *exit_addr;
90389031

@@ -9047,19 +9040,8 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
90479040

90489041
func = (zend_function*)trace->func;
90499042

9050-
if (func->type == ZEND_USER_FUNCTION &&
9051-
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9052-
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9053-
!func->common.function_name)) {
9054-
const zend_op *opcodes = func->op_array.opcodes;
9055-
9056-
ir_GUARD(
9057-
ir_EQ(
9058-
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9059-
ir_CONST_ADDR(opcodes)),
9060-
ir_CONST_ADDR(exit_addr));
9061-
} else {
9062-
ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9043+
if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9044+
return 0;
90639045
}
90649046
}
90659047

@@ -9213,11 +9195,7 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit,
92139195
if ((!func || zend_jit_may_be_modified(func, op_array))
92149196
&& trace
92159197
&& trace->op == ZEND_JIT_TRACE_INIT_CALL
9216-
&& trace->func
9217-
#ifdef _WIN32
9218-
&& trace->func->type != ZEND_INTERNAL_FUNCTION
9219-
#endif
9220-
) {
9198+
&& trace->func) {
92219199
int32_t exit_point;
92229200
const void *exit_addr;
92239201

@@ -9232,19 +9210,8 @@ static int zend_jit_init_static_method_call(zend_jit_ctx *jit,
92329210

92339211
func = (zend_function*)trace->func;
92349212

9235-
if (func->type == ZEND_USER_FUNCTION &&
9236-
(!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
9237-
(func->common.fn_flags & ZEND_ACC_CLOSURE) ||
9238-
!func->common.function_name)) {
9239-
const zend_op *opcodes = func->op_array.opcodes;
9240-
9241-
ir_GUARD(
9242-
ir_EQ(
9243-
ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
9244-
ir_CONST_ADDR(opcodes)),
9245-
ir_CONST_ADDR(exit_addr));
9246-
} else {
9247-
ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
9213+
if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9214+
return 0;
92489215
}
92499216
}
92509217

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)