Skip to content

Commit 7c674e1

Browse files
committed
JIT: Fix register clobbering
Fixes oss-fuzz #42657
1 parent f18bb24 commit 7c674e1

File tree

2 files changed

+61
-21
lines changed

2 files changed

+61
-21
lines changed

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -772,17 +772,12 @@ static void* dasm_labels[zend_lb_MAX];
772772
|| }
773773
|.endmacro
774774

775-
|.macro LONG_OP, long_ins, reg, addr
775+
|.macro LONG_OP, long_ins, reg, addr, tmp_reg
776776
|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
777777
| .if X64
778778
|| if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
779-
|| if (reg != ZREG_R0) {
780-
| mov64 r0, Z_LVAL_P(Z_ZV(addr))
781-
| long_ins Ra(reg), r0
782-
|| } else {
783-
| mov64 r1, Z_LVAL_P(Z_ZV(addr))
784-
| long_ins Ra(reg), r1
785-
|| }
779+
| mov64 tmp_reg, Z_LVAL_P(Z_ZV(addr))
780+
| long_ins Ra(reg), tmp_reg
786781
|| } else {
787782
| long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
788783
|| }
@@ -862,25 +857,25 @@ static void* dasm_labels[zend_lb_MAX];
862857
|| }
863858
|.endmacro
864859

865-
|.macro LONG_MATH, opcode, reg, addr
860+
|.macro LONG_MATH, opcode, reg, addr, tmp_reg
866861
|| switch (opcode) {
867862
|| case ZEND_ADD:
868-
| LONG_OP add, reg, addr
863+
| LONG_OP add, reg, addr, Ra(tmp_reg)
869864
|| break;
870865
|| case ZEND_SUB:
871-
| LONG_OP sub, reg, addr
866+
| LONG_OP sub, reg, addr, Ra(tmp_reg)
872867
|| break;
873868
|| case ZEND_MUL:
874-
| LONG_OP imul, reg, addr
869+
| LONG_OP imul, reg, addr, Ra(tmp_reg)
875870
|| break;
876871
|| case ZEND_BW_OR:
877-
| LONG_OP or, reg, addr
872+
| LONG_OP or, reg, addr, Ra(tmp_reg)
878873
|| break;
879874
|| case ZEND_BW_AND:
880-
| LONG_OP and, reg, addr
875+
| LONG_OP and, reg, addr, Ra(tmp_reg)
881876
|| break;
882877
|| case ZEND_BW_XOR:
883-
| LONG_OP xor, reg, addr
878+
| LONG_OP xor, reg, addr, Ra(tmp_reg)
884879
|| break;
885880
|| default:
886881
|| ZEND_UNREACHABLE();
@@ -4390,7 +4385,16 @@ static int zend_jit_math_long_long(dasm_State **Dst,
43904385
} else if (same_ops && opcode != ZEND_DIV) {
43914386
| LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
43924387
} else {
4393-
| LONG_MATH opcode, result_reg, op2_addr
4388+
zend_reg tmp_reg;
4389+
4390+
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
4391+
tmp_reg = ZREG_R1;
4392+
} else if (result_reg != ZREG_R0) {
4393+
tmp_reg = ZREG_R0;
4394+
} else {
4395+
tmp_reg = ZREG_R1;
4396+
}
4397+
| LONG_MATH opcode, result_reg, op2_addr, tmp_reg
43944398
}
43954399
}
43964400
if (may_overflow) {
@@ -5117,12 +5121,20 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
51175121
} else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
51185122
zval tmp;
51195123
zend_jit_addr tmp_addr;
5124+
zend_reg tmp_reg;
51205125

51215126
/* Optimisation for mod of power of 2 */
51225127
ZVAL_LONG(&tmp, op2_lval - 1);
51235128
tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp);
5129+
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
5130+
tmp_reg = ZREG_R1;
5131+
} else if (result_reg != ZREG_R0) {
5132+
tmp_reg = ZREG_R0;
5133+
} else {
5134+
tmp_reg = ZREG_R1;
5135+
}
51245136
| GET_ZVAL_LVAL result_reg, op1_addr
5125-
| LONG_MATH ZEND_BW_AND, result_reg, tmp_addr
5137+
| LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, tmp_reg
51265138
} else {
51275139
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) {
51285140
| mov aword T1, r0 // save
@@ -5210,8 +5222,17 @@ static int zend_jit_long_math_helper(dasm_State **Dst,
52105222
| GET_ZVAL_LVAL result_reg, op1_addr
52115223
| LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
52125224
} else {
5225+
zend_reg tmp_reg;
5226+
5227+
if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) {
5228+
tmp_reg = ZREG_R1;
5229+
} else if (result_reg != ZREG_R0) {
5230+
tmp_reg = ZREG_R0;
5231+
} else {
5232+
tmp_reg = ZREG_R1;
5233+
}
52135234
| GET_ZVAL_LVAL result_reg, op1_addr
5214-
| LONG_MATH opcode, result_reg, op2_addr
5235+
| LONG_MATH opcode, result_reg, op2_addr, tmp_reg
52155236
}
52165237

52175238
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,
70257046
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
70267047
| test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
70277048
} else {
7028-
| LONG_OP cmp, Z_REG(op1_addr), op2_addr
7049+
| LONG_OP cmp, Z_REG(op1_addr), op2_addr, r0
70297050
}
70307051
} else if (Z_MODE(op2_addr) == IS_REG) {
70317052
if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) {
70327053
| test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
70337054
} else {
7034-
| LONG_OP cmp, Z_REG(op2_addr), op1_addr
7055+
| LONG_OP cmp, Z_REG(op2_addr), op1_addr, r0
70357056
}
70367057
swap = 1;
70377058
} 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,
70447065
if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
70457066
| test r0, r0
70467067
} else {
7047-
| LONG_OP cmp, ZREG_R0, op2_addr
7068+
| LONG_OP cmp, ZREG_R0, op2_addr, r0
70487069
}
70497070
}
70507071

ext/opcache/tests/jit/add_012.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
JIT ADD: 012 register allocation for 64-bit constant
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--SKIPIF--
9+
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
10+
--FILE--
11+
<?php
12+
$x = 0;
13+
$y = [0];
14+
$y[$x]++;
15+
$y[$x] += 4467793343;
16+
?>
17+
DONE
18+
--EXPECT--
19+
DONE

0 commit comments

Comments
 (0)