Skip to content

Commit c325e9b

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
# Via GitHub * PHP-8.4: Fix JIT vm_interrupt (php#21910) # Conflicts: # ext/opcache/jit/zend_jit_ir.c
2 parents ca08e0f + 1f50b63 commit c325e9b

6 files changed

Lines changed: 90 additions & 13 deletions

File tree

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.5.7
44

5+
- Opcache:
6+
. Fixed tracing JIT crash when a VM interrupt is handled during an observed
7+
user function call. (Levi Morrison)
8+
59
- Standard:
610
. Fixed bug GH-21689 (version_compare() incorrectly handles versions ending
711
with a dot). (timwolla)

ext/opcache/jit/zend_jit_ir.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10423,28 +10423,19 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1042310423
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
1042410424
ir_ref observer_handler;
1042510425
ir_ref rx = jit_FP(jit);
10426+
const zend_op *observer_opline = NULL;
1042610427
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
1042710428
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1042810429
ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10429-
jit_SET_EX_OPLINE(jit, trace[1].opline);
10430+
observer_opline = trace[1].opline;
10431+
jit_SET_EX_OPLINE(jit, observer_opline);
1043010432
} else {
1043110433
// EX(opline) = opline
1043210434
ir_STORE(jit_EX(opline), jit_IP(jit));
1043310435
}
1043410436
jit_observer_fcall_begin(jit, rx, observer_handler);
1043510437

10436-
if (trace) {
10437-
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10438-
10439-
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10440-
if (!exit_addr) {
10441-
return 0;
10442-
}
10443-
} else {
10444-
exit_addr = NULL;
10445-
}
10446-
10447-
zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10438+
zend_jit_check_timeout(jit, observer_opline, NULL);
1044810439

1044910440
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
1045010441
}

ext/zend_test/observer.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ static void observer_begin(zend_execute_data *execute_data)
7878
{
7979
assert_observer_opline(execute_data);
8080

81+
if (ZT_G(observer_set_vm_interrupt_on_begin)) {
82+
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
83+
}
84+
8185
if (!ZT_G(observer_show_output)) {
8286
return;
8387
}
@@ -146,6 +150,14 @@ static void observer_end(zend_execute_data *execute_data, zval *retval)
146150
}
147151
}
148152

153+
static void (*zend_test_prev_interrupt_function)(zend_execute_data *execute_data);
154+
static void zend_test_interrupt_function(zend_execute_data *execute_data)
155+
{
156+
if (zend_test_prev_interrupt_function) {
157+
zend_test_prev_interrupt_function(execute_data);
158+
}
159+
}
160+
149161
static void observer_show_init(zend_function *fbc)
150162
{
151163
if (fbc->common.function_name) {
@@ -361,6 +373,7 @@ PHP_INI_BEGIN()
361373
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
362374
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
363375
STD_PHP_INI_ENTRY("zend_test.observer.show_opcode_in_user_handler", "", PHP_INI_SYSTEM, OnUpdateString, observer_show_opcode_in_user_handler, zend_zend_test_globals, zend_test_globals)
376+
STD_PHP_INI_BOOLEAN("zend_test.observer.set_vm_interrupt_on_begin", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_set_vm_interrupt_on_begin, zend_zend_test_globals, zend_test_globals)
364377
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_init", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_init, zend_zend_test_globals, zend_test_globals)
365378
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_switch", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_switch, zend_zend_test_globals, zend_test_globals)
366379
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_destroy", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_destroy, zend_zend_test_globals, zend_test_globals)
@@ -398,10 +411,20 @@ void zend_test_observer_init(INIT_FUNC_ARGS)
398411
zend_test_prev_execute_internal = zend_execute_internal;
399412
zend_execute_internal = zend_test_execute_internal;
400413
}
414+
415+
if (ZT_G(observer_set_vm_interrupt_on_begin)) {
416+
zend_test_prev_interrupt_function = zend_interrupt_function;
417+
zend_interrupt_function = zend_test_interrupt_function;
418+
}
401419
}
402420

403421
void zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS)
404422
{
423+
if (zend_interrupt_function == zend_test_interrupt_function) {
424+
zend_interrupt_function = zend_test_prev_interrupt_function;
425+
zend_test_prev_interrupt_function = NULL;
426+
}
427+
405428
if (type != MODULE_TEMPORARY) {
406429
UNREGISTER_INI_ENTRIES();
407430
}

ext/zend_test/php_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
4545
int observer_show_init_backtrace;
4646
int observer_show_opcode;
4747
char *observer_show_opcode_in_user_handler;
48+
int observer_set_vm_interrupt_on_begin;
4849
int observer_nesting_depth;
4950
int observer_fiber_init;
5051
int observer_fiber_switch;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace ZendTestJitInterrupt;
4+
5+
function external_target(mixed $value): mixed
6+
{
7+
return $value;
8+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
Observer: VM interrupt during tracing JIT user function call
3+
--EXTENSIONS--
4+
opcache
5+
zend_test
6+
--INI--
7+
opcache.enable=1
8+
opcache.enable_cli=1
9+
opcache.file_update_protection=0
10+
opcache.jit_buffer_size=64M
11+
opcache.jit=tracing
12+
opcache.jit_hot_loop=1
13+
opcache.jit_hot_func=1
14+
opcache.jit_hot_return=1
15+
opcache.jit_hot_side_exit=1
16+
opcache.jit_max_polymorphic_calls=0
17+
zend_test.observer.enabled=1
18+
zend_test.observer.show_output=0
19+
zend_test.observer.observe_function_names=ZendTestJitInterrupt\external_target
20+
zend_test.observer.set_vm_interrupt_on_begin=1
21+
--SKIPIF--
22+
<?php
23+
if (ini_get('opcache.jit') === false) die('skip JIT not available');
24+
?>
25+
--FILE--
26+
<?php
27+
namespace ZendTestJitInterrupt;
28+
29+
// Keep the callee in a separate file so the caller uses
30+
// INIT_NS_FCALL_BY_NAME/DO_FCALL_BY_NAME, not INIT_FCALL/DO_UCALL.
31+
require __DIR__ . '/observer_jit_vm_interrupt.inc';
32+
33+
function drive_probe(int $n): int
34+
{
35+
$sum = 0;
36+
for ($i = 0; $i < $n; $i++) {
37+
$sum += external_target($i);
38+
}
39+
return $sum;
40+
}
41+
42+
$total = 0;
43+
for ($round = 0; $round < 300; $round++) {
44+
$total += drive_probe(128);
45+
}
46+
47+
echo "total={$total}\n";
48+
?>
49+
--EXPECT--
50+
total=2438400

0 commit comments

Comments
 (0)