JIT: Fix register clobbering

Fixes oss-fuzz #42657
This commit is contained in:
Dmitry Stogov 2021-12-20 12:48:48 +03:00
parent f18bb2477f
commit 7c674e1aa7
2 changed files with 61 additions and 21 deletions

View File

@ -772,17 +772,12 @@ static void* dasm_labels[zend_lb_MAX];
|| } || }
|.endmacro |.endmacro
|.macro LONG_OP, long_ins, reg, addr |.macro LONG_OP, long_ins, reg, addr, tmp_reg
|| if (Z_MODE(addr) == IS_CONST_ZVAL) { || if (Z_MODE(addr) == IS_CONST_ZVAL) {
| .if X64 | .if X64
|| if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) { || if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
|| if (reg != ZREG_R0) { | mov64 tmp_reg, Z_LVAL_P(Z_ZV(addr))
| mov64 r0, Z_LVAL_P(Z_ZV(addr)) | long_ins Ra(reg), tmp_reg
| long_ins Ra(reg), r0
|| } else {
| mov64 r1, Z_LVAL_P(Z_ZV(addr))
| long_ins Ra(reg), r1
|| }
|| } else { || } else {
| long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr)) | long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
|| } || }
@ -862,25 +857,25 @@ static void* dasm_labels[zend_lb_MAX];
|| } || }
|.endmacro |.endmacro
|.macro LONG_MATH, opcode, reg, addr |.macro LONG_MATH, opcode, reg, addr, tmp_reg
|| switch (opcode) { || switch (opcode) {
|| case ZEND_ADD: || case ZEND_ADD:
| LONG_OP add, reg, addr | LONG_OP add, reg, addr, Ra(tmp_reg)
|| break; || break;
|| case ZEND_SUB: || case ZEND_SUB:
| LONG_OP sub, reg, addr | LONG_OP sub, reg, addr, Ra(tmp_reg)
|| break; || break;
|| case ZEND_MUL: || case ZEND_MUL:
| LONG_OP imul, reg, addr | LONG_OP imul, reg, addr, Ra(tmp_reg)
|| break; || break;
|| case ZEND_BW_OR: || case ZEND_BW_OR:
| LONG_OP or, reg, addr | LONG_OP or, reg, addr, Ra(tmp_reg)
|| break; || break;
|| case ZEND_BW_AND: || case ZEND_BW_AND:
| LONG_OP and, reg, addr | LONG_OP and, reg, addr, Ra(tmp_reg)
|| break; || break;
|| case ZEND_BW_XOR: || case ZEND_BW_XOR:
| LONG_OP xor, reg, addr | LONG_OP xor, reg, addr, Ra(tmp_reg)
|| break; || break;
|| default: || default:
|| ZEND_UNREACHABLE(); || ZEND_UNREACHABLE();
@ -4390,7 +4385,16 @@ static int zend_jit_math_long_long(dasm_State **Dst,
} else if (same_ops && opcode != ZEND_DIV) { } else if (same_ops && opcode != ZEND_DIV) {
| LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg) | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
} else { } else {
| LONG_MATH opcode, result_reg, op2_addr zend_reg tmp_reg;
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
tmp_reg = ZREG_R1;
} else if (result_reg != ZREG_R0) {
tmp_reg = ZREG_R0;
} else {
tmp_reg = ZREG_R1;
}
| LONG_MATH opcode, result_reg, op2_addr, tmp_reg
} }
} }
if (may_overflow) { if (may_overflow) {
@ -5117,12 +5121,20 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) { } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
zval tmp; zval tmp;
zend_jit_addr tmp_addr; zend_jit_addr tmp_addr;
zend_reg tmp_reg;
/* Optimisation for mod of power of 2 */ /* Optimisation for mod of power of 2 */
ZVAL_LONG(&tmp, op2_lval - 1); ZVAL_LONG(&tmp, op2_lval - 1);
tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp); tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp);
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
tmp_reg = ZREG_R1;
} else if (result_reg != ZREG_R0) {
tmp_reg = ZREG_R0;
} else {
tmp_reg = ZREG_R1;
}
| GET_ZVAL_LVAL result_reg, op1_addr | GET_ZVAL_LVAL result_reg, op1_addr
| LONG_MATH ZEND_BW_AND, result_reg, tmp_addr | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, tmp_reg
} else { } else {
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) { if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
| mov aword T1, r0 // save | mov aword T1, r0 // save
@ -5210,8 +5222,17 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
| GET_ZVAL_LVAL result_reg, op1_addr | GET_ZVAL_LVAL result_reg, op1_addr
| LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg) | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
} else { } else {
zend_reg tmp_reg;
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
tmp_reg = ZREG_R1;
} else if (result_reg != ZREG_R0) {
tmp_reg = ZREG_R0;
} else {
tmp_reg = ZREG_R1;
}
| GET_ZVAL_LVAL result_reg, op1_addr | GET_ZVAL_LVAL result_reg, op1_addr
| LONG_MATH opcode, result_reg, op2_addr | LONG_MATH opcode, result_reg, op2_addr, tmp_reg
} }
if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) { if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) {
@ -7025,13 +7046,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr)) | test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
} else { } else {
| LONG_OP cmp, Z_REG(op1_addr), op2_addr | LONG_OP cmp, Z_REG(op1_addr), op2_addr, r0
} }
} else if (Z_MODE(op2_addr) == IS_REG) { } else if (Z_MODE(op2_addr) == IS_REG) {
if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) { if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) {
| test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr)) | test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
} else { } else {
| LONG_OP cmp, Z_REG(op2_addr), op1_addr | LONG_OP cmp, Z_REG(op2_addr), op1_addr, r0
} }
swap = 1; swap = 1;
} else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) { } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) {
@ -7044,7 +7065,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst,
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
| test r0, r0 | test r0, r0
} else { } else {
| LONG_OP cmp, ZREG_R0, op2_addr | LONG_OP cmp, ZREG_R0, op2_addr, r0
} }
} }

View File

@ -0,0 +1,19 @@
--TEST--
JIT ADD: 012 register allocation for 64-bit constant
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.file_update_protection=0
opcache.jit_buffer_size=1M
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
$x = 0;
$y = [0];
$y[$x]++;
$y[$x] += 4467793343;
?>
DONE
--EXPECT--
DONE