From c9c51eb1f15117517384ba4e1707af326b3a161b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 22 Aug 2022 15:38:41 +0300 Subject: [PATCH] Tracing JIT: Fix incorrect guard elimination Fixes oss-fuzz #49917 --- ext/opcache/jit/zend_jit_trace.c | 48 ++++++++++++++++++++++++++---- ext/opcache/tests/jit/add_014.phpt | 25 ++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 ext/opcache/tests/jit/add_014.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 2890f7ebfd7..47463fc682c 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -981,6 +981,9 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_STRING)) { return 0; } + if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } return 1; } else if (opline->opcode == ZEND_ASSIGN_OP && (opline->extended_value == ZEND_ADD @@ -991,6 +994,17 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) { return 0; } + if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } + if (opline->op2_type == IS_CONST) { + zval *zv = RT_CONSTANT(opline, opline->op2); + if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) { + return 0; + } + } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } return 1; } } @@ -998,11 +1012,7 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u const zend_op *opline = ssa_opcodes[idx]; if (opline->opcode == ZEND_ADD || opline->opcode == ZEND_SUB - || opline->opcode == ZEND_MUL - || opline->opcode == ZEND_PRE_DEC - || opline->opcode == ZEND_PRE_INC - || opline->opcode == ZEND_POST_DEC - || opline->opcode == ZEND_POST_INC) { + || opline->opcode == ZEND_MUL) { if ((opline->op1_type & (IS_VAR|IS_CV)) && tssa->ops[idx].op1_use >= 0 && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) { @@ -1013,6 +1023,34 @@ static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, u && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) { return 0; } + if (opline->op1_type == IS_CONST) { + zval *zv = RT_CONSTANT(opline, opline->op1); + if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) { + return 0; + } + } else if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } + if (opline->op2_type == IS_CONST) { + zval *zv = RT_CONSTANT(opline, opline->op2); + if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) { + return 0; + } + } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } + } else if (opline->opcode == ZEND_PRE_DEC + || opline->opcode == ZEND_PRE_INC + || opline->opcode == ZEND_POST_DEC + || opline->opcode == ZEND_POST_INC) { + if ((opline->op1_type & (IS_VAR|IS_CV)) + && tssa->ops[idx].op1_use >= 0 + && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) { + return 0; + } + if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) { + return 0; + } return 1; } } diff --git a/ext/opcache/tests/jit/add_014.phpt b/ext/opcache/tests/jit/add_014.phpt new file mode 100644 index 00000000000..b7691c77033 --- /dev/null +++ b/ext/opcache/tests/jit/add_014.phpt @@ -0,0 +1,25 @@ +--TEST-- +JIT ADD: 014 incorrect guard elimination +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- +> 4 - $j++; + if ($j > 14) break; + } +} +try { + @test(); +} catch (Throwable $e) { + echo $e->getMessage() . "\n"; +} +?> +--EXPECT-- +Bit shift by negative number