Skip to content

Commit

Permalink
Fixed bug #81226 (Integer overflow behavior is different with JIT ena…
Browse files Browse the repository at this point in the history
…bled)
  • Loading branch information
dstogov committed Jul 21, 2021
1 parent 0ba6dde commit 053c56f
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 22 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ PHP NEWS
. Fixed Bug #81255 (Memory leak in PHPUnit with functional JIT). (Dmitry)
. Fixed Bug #80959 (infinite loop in building cfg during JIT compilation)
(Nikita, Dmitry)
. Fixed bug #81226 (Integer overflow behavior is different with JIT
enabled). (Dmitry)

- Standard:
. Fixed bug #72146 (Integer overflow on substr_replace). (cmb)
Expand Down
6 changes: 6 additions & 0 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ static zend_bool zend_long_is_power_of_two(zend_long x)
return (x > 0) && !(x & (x - 1));
}

static zend_always_inline uint32_t zend_long_floor_log2(zend_long x)
{
ZEND_ASSERT(zend_long_is_power_of_two(x));
return zend_ulong_ntz(x);
}

#define OP_RANGE(ssa_op, opN) \
(((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
ssa->var_info && \
Expand Down
54 changes: 32 additions & 22 deletions ext/opcache/jit/zend_jit_x86.dasc
Original file line number Diff line number Diff line change
Expand Up @@ -4234,7 +4234,7 @@ static int zend_jit_math_long_long(dasm_State **Dst,
} else {
result_reg = Z_REG(res_addr);
}
} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
} else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr) && !may_overflow) {
result_reg = Z_REG(op1_addr);
} else if (Z_REG(res_addr) != ZREG_R0) {
result_reg = ZREG_R0;
Expand All @@ -4245,32 +4245,42 @@ static int zend_jit_math_long_long(dasm_State **Dst,
}

if (opcode == ZEND_MUL &&
((Z_MODE(op2_addr) == IS_CONST_ZVAL &&
IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op2_addr))) &&
is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) ||
(Z_MODE(op1_addr) == IS_CONST_ZVAL &&
IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op1_addr))) &&
is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))))) {
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
if (Z_MODE(op1_addr) == IS_REG && Z_LVAL_P(Z_ZV(op2_addr)) == 2) {
| lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Ra(Z_REG(op1_addr))]
} else {
| GET_ZVAL_LVAL result_reg, op1_addr
| shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
}
Z_MODE(op2_addr) == IS_CONST_ZVAL &&
Z_LVAL_P(Z_ZV(op2_addr)) == 2) {
if (Z_MODE(op1_addr) == IS_REG && !may_overflow) {
| lea Ra(result_reg), [Ra(Z_REG(op1_addr))+Ra(Z_REG(op1_addr))]
} else {
if (Z_MODE(op2_addr) == IS_REG && Z_LVAL_P(Z_ZV(op1_addr)) == 2) {
| lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Ra(Z_REG(op2_addr))]
} else {
| GET_ZVAL_LVAL result_reg, op2_addr
| shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
}
| GET_ZVAL_LVAL result_reg, op1_addr
| add Ra(result_reg), Ra(result_reg)
}
} else if (opcode == ZEND_MUL &&
Z_MODE(op2_addr) == IS_CONST_ZVAL &&
!may_overflow &&
Z_LVAL_P(Z_ZV(op2_addr)) > 0 &&
zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) {
| GET_ZVAL_LVAL result_reg, op1_addr
| shl Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
} else if (opcode == ZEND_MUL &&
Z_MODE(op1_addr) == IS_CONST_ZVAL &&
Z_LVAL_P(Z_ZV(op1_addr)) == 2) {
if (Z_MODE(op2_addr) == IS_REG && !may_overflow) {
| lea Ra(result_reg), [Ra(Z_REG(op2_addr))+Ra(Z_REG(op2_addr))]
} else {
| GET_ZVAL_LVAL result_reg, op2_addr
| add Ra(result_reg), Ra(result_reg)
}
} else if (opcode == ZEND_MUL &&
Z_MODE(op1_addr) == IS_CONST_ZVAL &&
!may_overflow &&
Z_LVAL_P(Z_ZV(op1_addr)) > 0 &&
zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))) {
| GET_ZVAL_LVAL result_reg, op2_addr
| shl Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
} else if (opcode == ZEND_DIV &&
(Z_MODE(op2_addr) == IS_CONST_ZVAL &&
is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) {
zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) {
| GET_ZVAL_LVAL result_reg, op1_addr
| shr Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
| shr Ra(result_reg), zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
} else if (opcode == ZEND_ADD &&
!may_overflow &&
Z_MODE(op1_addr) == IS_REG &&
Expand Down

0 comments on commit 053c56f

Please sign in to comment.