From 522d512d2067ec275ab090fe232cac79c19dfc24 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Nov 2023 12:28:32 +0300 Subject: [PATCH] Backport fix for GH-12512: JIT Assertion `info & (1 << type)' failed --- ext/opcache/jit/zend_jit_trace.c | 72 ++++++++++++++++++++++++++-- ext/opcache/tests/jit/gh12512.phpt | 41 ++++++++++++++++ ext/opcache/tests/jit/gh12512_2.phpt | 44 +++++++++++++++++ 3 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/jit/gh12512.phpt create mode 100644 ext/opcache/tests/jit/gh12512_2.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 4a57986130666..86cd2aae06094 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5022,6 +5022,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) { goto jit_failure; } + if (ssa_op->op2_def > 0 + && Z_MODE(op2_addr) == IS_REG + && ssa->vars[ssa_op->op2_def].no_val) { + uint8_t type = (op2_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op2_def].use_chain < 0 + && !ssa->vars[ssa_op->op2_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op2_type == IS_CV && ssa_op->op2_def >= 0 && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS) { @@ -5058,6 +5073,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par res_use_info, res_info, res_addr)) { goto jit_failure; } + if (ssa_op->op1_def > 0 + && Z_MODE(op1_addr) == IS_REG + && ssa->vars[ssa_op->op1_def].no_val) { + uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op1_def].use_chain < 0 + && !ssa->vars[ssa_op->op1_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op1_type == IS_CV && ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) { @@ -5140,6 +5170,21 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op1_info, op1_addr, op1_def_addr)) { goto jit_failure; } + if (ssa_op->op1_def > 0 + && Z_MODE(op1_addr) == IS_REG + && ssa->vars[ssa_op->op1_def].no_val) { + uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE; + uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var); + + if (STACK_MEM_TYPE(stack, var_num) != type + && ssa->vars[ssa_op->op1_def].use_chain < 0 + && !ssa->vars[ssa_op->op1_def].phi_use_chain) { + if (!zend_jit_store_var_type(&dasm_state, var_num, type)) { + return 0; + } + SET_STACK_TYPE(stack, var_num, type, 1); + } + } if (opline->op1_type == IS_CV && ssa_op->op1_def >= 0 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) { @@ -6872,9 +6917,30 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par } } else if (p->stop == ZEND_JIT_TRACE_STOP_LINK || p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) { - if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL, - stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) { - goto jit_failure; + if (ra + && (p-1)->op != ZEND_JIT_TRACE_ENTER + && (p-1)->op != ZEND_JIT_TRACE_BACK + && opline->opcode != ZEND_DO_UCALL + && opline->opcode != ZEND_DO_FCALL + && opline->opcode != ZEND_DO_FCALL_BY_NAME + && opline->opcode != ZEND_INCLUDE_OR_EVAL) { + if (!zend_jit_trace_deoptimization(&dasm_state, 0, NULL, + stack, op_array->last_var + op_array->T, NULL, NULL, NULL, 0)) { + goto jit_failure; + } + for (i = 0; i < op_array->last_var; i++) { + int8_t reg = STACK_REG(stack, i); + uint8_t type = STACK_TYPE(stack, i); + + if (reg == ZREG_NONE + && type != IS_UNKNOWN + && type != STACK_MEM_TYPE(stack, i)) { + if (!zend_jit_store_var_type(&dasm_state, i, type)) { + return 0; + } + SET_STACK_TYPE(stack, i, type, 1); + } + } } if (p->stop == ZEND_JIT_TRACE_STOP_LINK) { const void *timeout_exit_addr = NULL; diff --git a/ext/opcache/tests/jit/gh12512.phpt b/ext/opcache/tests/jit/gh12512.phpt new file mode 100644 index 0000000000000..35307d18cc61f --- /dev/null +++ b/ext/opcache/tests/jit/gh12512.phpt @@ -0,0 +1,41 @@ +--TEST-- +GH-12512: missing type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + $val) { + if ($val === 2) { + unset($a[$key]); + } + } + return $ret; +} + +function foo($a, bool $b): bool { + if ($b) return true; + $n2 = count($a); + do { + $n = $n2; + $res = bar($a); + $n2 = count($a); + } while ($res === null && $n !== $n2); + + if ($res === null && $n === 0) { + return false; + } + return true; +} + +$a = [1,'a'=>5]; +bar($a); +foo([1,'a'=>5], true); +foo([1,'a'=>5], false); +foo([2,'a'=>5], false); +?> +DONE +--EXPECT-- +DONE diff --git a/ext/opcache/tests/jit/gh12512_2.phpt b/ext/opcache/tests/jit/gh12512_2.phpt new file mode 100644 index 0000000000000..67c5b091494c3 --- /dev/null +++ b/ext/opcache/tests/jit/gh12512_2.phpt @@ -0,0 +1,44 @@ +--TEST-- +GH-12512: missing type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +--FILE-- + $y; + } + if ($exit) { + return $n; + } + } + + return $n; +} +var_dump(foo([1,2,3,4,5,6,7,8], 1)); +var_dump(foo([1,2,3,4,5,6,7,8], 1)); +var_dump(foo([1,2,3,4,5,6,7,8], 0)); +?> +DONE +--EXPECT-- +int(0) +int(0) +int(0) +DONE