Remove range inference for booleans.

Range inference for bolleans and longs comparison was incorrect.

Fizes oss-fuzz #fuzz-42161.php
This commit is contained in:
Dmitry Stogov 2021-12-10 14:32:47 +03:00
parent 5675ebe649
commit 6f42c073cf
3 changed files with 28 additions and 163 deletions

View File

@ -996,8 +996,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp)
{
zend_long op1_min, op2_min, op1_max, op2_max;
tmp->underflow = 0;
tmp->overflow = 0;
switch (opline->opcode) {
@ -1025,8 +1023,8 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa,
tmp->min = ZEND_LONG_MIN;
tmp->max = ZEND_LONG_MAX;
} else {
op1_min = OP1_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
zend_long op1_min = OP1_MIN_RANGE();
zend_long op1_max = OP1_MAX_RANGE();
tmp->min = ~op1_max;
tmp->max = ~op1_min;
}
@ -1059,144 +1057,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa,
}
}
break;
case ZEND_BOOL:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
tmp->min = (op1_min > 0 || op1_max < 0);
tmp->max = (op1_min != 0 || op1_max != 0);
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_BOOL_NOT:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
tmp->min = (op1_min == 0 && op1_max == 0);
tmp->max = (op1_min <= 0 && op1_max >= 0);
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_BOOL_XOR:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op2_min = OP2_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
op2_max = OP2_MAX_RANGE();
op1_min = (op1_min > 0 || op1_max < 0);
op1_max = (op1_min != 0 || op1_max != 0);
op2_min = (op2_min > 0 || op2_max < 0);
op2_max = (op2_min != 0 || op2_max != 0);
tmp->min = 0;
tmp->max = 1;
if (op1_min == op1_max && op2_min == op2_max) {
if (op1_min == op2_min) {
tmp->max = 0;
} else {
tmp->min = 1;
}
}
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_IS_IDENTICAL:
case ZEND_IS_EQUAL:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op2_min = OP2_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
op2_max = OP2_MAX_RANGE();
tmp->min = (op1_min == op1_max &&
op2_min == op2_max &&
op1_min == op2_max);
tmp->max = (op1_min <= op2_max && op1_max >= op2_min);
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_IS_NOT_IDENTICAL:
case ZEND_IS_NOT_EQUAL:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op2_min = OP2_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
op2_max = OP2_MAX_RANGE();
tmp->min = (op1_min > op2_max || op1_max < op2_min);
tmp->max = (op1_min != op1_max ||
op2_min != op2_max ||
op1_min != op2_max);
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_IS_SMALLER:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op2_min = OP2_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
op2_max = OP2_MAX_RANGE();
tmp->min = op1_max < op2_min;
tmp->max = op1_min < op2_max;
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_IS_SMALLER_OR_EQUAL:
if (ssa_op->result_def == var) {
if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) {
op1_min = OP1_MIN_RANGE();
op2_min = OP2_MIN_RANGE();
op1_max = OP1_MAX_RANGE();
op2_max = OP2_MAX_RANGE();
tmp->min = op1_max <= op2_min;
tmp->max = op1_min <= op2_max;
return 1;
} else {
tmp->min = 0;
tmp->max = 1;
return 1;
}
}
break;
case ZEND_QM_ASSIGN:
case ZEND_JMP_SET:
case ZEND_COALESCE:
@ -1222,13 +1082,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa,
}
}
break;
case ZEND_ASSERT_CHECK:
if (ssa_op->result_def == var) {
tmp->min = 0;
tmp->max = 1;
return 1;
}
break;
case ZEND_SEND_VAR:
if (ssa_op->op1_def == var) {
if (ssa_op->op1_def >= 0) {
@ -1409,12 +1262,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa,
tmp->max = ZEND_LONG_MAX;
tmp->overflow = 0;
return 1;
} else if (mask == MAY_BE_BOOL) {
tmp->underflow = 0;
tmp->min = 0;
tmp->max = 1;
tmp->overflow = 0;
return 1;
}
}
}

View File

@ -335,10 +335,6 @@ static void place_essa_pis(
if (Z_TYPE_P(zv) == IS_LONG) {
add_val2 = Z_LVAL_P(zv);
} else if (Z_TYPE_P(zv) == IS_FALSE) {
add_val2 = 0;
} else if (Z_TYPE_P(zv) == IS_TRUE) {
add_val2 = 1;
} else {
var1 = -1;
}
@ -356,10 +352,6 @@ static void place_essa_pis(
zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1);
if (Z_TYPE_P(zv) == IS_LONG) {
add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1));
} else if (Z_TYPE_P(zv) == IS_FALSE) {
add_val1 = 0;
} else if (Z_TYPE_P(zv) == IS_TRUE) {
add_val1 = 1;
} else {
var2 = -1;
}

View File

@ -0,0 +1,26 @@
--TEST--
JIT CMP: 008 Wrong range inference for comparison between IS_LONG and IS_FALSE/IS_TRUE
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit_buffer_size=1M
opcache.protect_memory=1
--FILE--
<?php
function test() {
for ($i = 0; $i < 10; $i %= -4 != -4 < ($a = $a + $a)) {
}
}
test();
?>
--EXPECTF--
Warning: Undefined variable $a in %scmp_008.php on line 3
Warning: Undefined variable $a in %scmp_008.php on line 3
Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %scmp_008.php:3
Stack trace:
#0 %scmp_008.php(6): test()
#1 {main}
thrown in %scmp_008.php on line 3