From 1330e4996b9c30220d37c9c61affa62083b4652e Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 21 Mar 2024 15:09:20 +0100 Subject: [PATCH] Always load EX(opline) into the current frame in JIT when observers are enabled Fixes #13772. --- ext/opcache/jit/zend_jit_arm64.dasc | 7 ++++++- ext/opcache/jit/zend_jit_x86.dasc | 7 ++++++- ext/opcache/tests/jit/gh13772.phpt | 26 ++++++++++++++++++++++++++ ext/zend_test/observer.c | 10 ++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/jit/gh13772.phpt diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index 329eb42507e3e..37fca7cfeb60a 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -9449,7 +9449,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend } if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP + if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) { + ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); + | SET_EX_OPLINE trace[1].opline, REG0 + } else { + | SAVE_IP + } | mov FCARG1x, FP | EXT_CALL zend_observer_fcall_begin, REG0 } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index d1cbbd6391c53..7ae69c9fb657e 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -10187,7 +10187,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend } if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP + if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) { + ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); + | SET_EX_OPLINE trace[1].opline, r0 + } else { + | SAVE_IP + } | mov FCARG1a, FP | EXT_CALL zend_observer_fcall_begin, r0 } diff --git a/ext/opcache/tests/jit/gh13772.phpt b/ext/opcache/tests/jit/gh13772.phpt new file mode 100644 index 0000000000000..97fa6536e0ce7 --- /dev/null +++ b/ext/opcache/tests/jit/gh13772.phpt @@ -0,0 +1,26 @@ +--TEST-- +EX(opline) is correctly set for nested JIT user code calls +--EXTENSIONS-- +opcache +zend_test +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_output=0 +--FILE-- + +--EXPECT-- +int(61) + diff --git a/ext/zend_test/observer.c b/ext/zend_test/observer.c index de83d7beb18c5..af45f91a5da5b 100644 --- a/ext/zend_test/observer.c +++ b/ext/zend_test/observer.c @@ -67,8 +67,16 @@ static void observer_show_opcode(zend_execute_data *execute_data) php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode)); } +static inline void assert_observer_opline(zend_execute_data *execute_data) { + ZEND_ASSERT(!ZEND_USER_CODE(EX(func)->type) || + (EX(opline) >= EX(func)->op_array.opcodes && EX(opline) < EX(func)->op_array.opcodes + EX(func)->op_array.last) || + (EX(opline) >= EG(exception_op) && EX(opline) < EG(exception_op) + 3)); +} + static void observer_begin(zend_execute_data *execute_data) { + assert_observer_opline(execute_data); + if (!ZT_G(observer_show_output)) { return; } @@ -112,6 +120,8 @@ static void get_retval_info(zval *retval, smart_str *buf) static void observer_end(zend_execute_data *execute_data, zval *retval) { + assert_observer_opline(execute_data); + if (!ZT_G(observer_show_output)) { return; }