From 4a9b89d83924f6738f01d32e750178e655347138 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 13 Nov 2024 18:27:26 +0100 Subject: [PATCH 1/2] Fix GH-16770: Tracing JIT type mismatch when returning UNDEF When returning an UNDEF value, it actually becomes NULL. The following code took this into account: https://github.com/php/php-src/blob/28344e0445bc2abae8dc5f1376aa0ff350e6d66d/ext/opcache/jit/zend_jit_trace.c#L2196-L2199 But the stack does not update the type to NULL, causing a mismatch. --- ext/opcache/jit/zend_jit_trace.c | 3 +++ ext/opcache/tests/jit/gh16770.phpt | 39 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 ext/opcache/tests/jit/gh16770.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 5b1186abd199d..260c02d09a348 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -6673,6 +6673,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par && (p+1)->op == ZEND_JIT_TRACE_VM) { const zend_op *opline = (p+1)->opline - 1; if (opline->result_type != IS_UNUSED) { + if (res_type == IS_UNDEF) { + res_type = IS_NULL; + } SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), res_type, 1); } } diff --git a/ext/opcache/tests/jit/gh16770.phpt b/ext/opcache/tests/jit/gh16770.phpt new file mode 100644 index 0000000000000..71d796ade8ed9 --- /dev/null +++ b/ext/opcache/tests/jit/gh16770.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-16770 (Tracing JIT type mismatch when returning UNDEF) +--INI-- +opcache.jit=1254 +opcache.jit_hot_loop=1 +opcache.jit_buffer_size=32M +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d + +Warning: Undefined variable $undefined in %s on line %d +NULL From df13dc5e34c86d56881473f032d087857edcad4e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 14 Nov 2024 21:45:30 +0100 Subject: [PATCH 2/2] Move check --- ext/opcache/jit/zend_jit_trace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 260c02d09a348..bb35ffa2a050c 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5404,6 +5404,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par res_type = Z_TYPE_P(RT_CONSTANT(opline, opline->op1)); } else if (op1_type != IS_UNKNOWN) { res_type = op1_type; + if (res_type == IS_UNDEF) { + res_type = IS_NULL; + } } if (op_array->type == ZEND_EVAL_CODE // TODO: support for top-level code @@ -6673,9 +6676,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par && (p+1)->op == ZEND_JIT_TRACE_VM) { const zend_op *opline = (p+1)->opline - 1; if (opline->result_type != IS_UNUSED) { - if (res_type == IS_UNDEF) { - res_type = IS_NULL; - } SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), res_type, 1); } }