Skip to content

Commit aa7465a

Browse files
committed
Fixed missed type store
Fixes oss-fuzz #63601
1 parent 7fcbedd commit aa7465a

File tree

3 files changed

+123
-16
lines changed

3 files changed

+123
-16
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,24 +1095,62 @@ static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array *
10951095

10961096
/* Remove intervals used once */
10971097
for (i = 0; i < ssa->vars_count; i++) {
1098-
if (ra[i].ref &&
1099-
(ra[i].flags & ZREG_LOAD) &&
1100-
(ra[i].flags & ZREG_STORE) &&
1101-
(ssa->vars[i].use_chain < 0 ||
1102-
zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
1103-
bool may_remove = 1;
1104-
zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1105-
1106-
while (phi) {
1107-
if (ra[phi->ssa_var].ref &&
1108-
!(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1109-
may_remove = 0;
1110-
break;
1098+
if (ra[i].ref) {
1099+
if (!(ra[i].flags & (ZREG_LOAD|ZREG_STORE))) {
1100+
uint32_t var_num = ssa->vars[i].var;
1101+
uint32_t op_num = ssa->vars[i].definition;
1102+
1103+
/* Check if a tempoary variable may be freed by exception handler */
1104+
if (op_array->last_live_range
1105+
&& var_num >= op_array->last_var
1106+
&& ssa->vars[i].definition >= 0
1107+
&& ssa->ops[op_num].result_def == i) {
1108+
const zend_live_range *range = op_array->live_range;
1109+
int j;
1110+
1111+
op_num++;
1112+
if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1113+
op_num++;
1114+
}
1115+
for (j = 0; j < op_array->last_live_range; range++, j++) {
1116+
if (range->start > op_num) {
1117+
/* further blocks will not be relevant... */
1118+
break;
1119+
} else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
1120+
/* check if opcodes in range may throw */
1121+
do {
1122+
if (zend_may_throw(op_array->opcodes + op_num, ssa->ops + op_num, op_array, ssa)) {
1123+
ra[i].flags |= ZREG_STORE;
1124+
break;
1125+
}
1126+
op_num++;
1127+
if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1128+
op_num++;
1129+
}
1130+
} while (op_num < range->end);
1131+
break;
1132+
}
1133+
}
11111134
}
1112-
phi = zend_ssa_next_use_phi(ssa, i, phi);
11131135
}
1114-
if (may_remove) {
1115-
ra[i].ref = IR_UNUSED;
1136+
if ((ra[i].flags & ZREG_LOAD)
1137+
&& (ra[i].flags & ZREG_STORE)
1138+
&& (ssa->vars[i].use_chain < 0
1139+
|| zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
1140+
bool may_remove = 1;
1141+
zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1142+
1143+
while (phi) {
1144+
if (ra[phi->ssa_var].ref &&
1145+
!(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1146+
may_remove = 0;
1147+
break;
1148+
}
1149+
phi = zend_ssa_next_use_phi(ssa, i, phi);
1150+
}
1151+
if (may_remove) {
1152+
ra[i].ref = IR_UNUSED;
1153+
}
11161154
}
11171155
}
11181156
}

ext/opcache/jit/zend_jit_trace.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6174,6 +6174,56 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
61746174
} else {
61756175
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
61766176
(gen_handler || type == IS_UNKNOWN || !ra || !RA_HAS_REG(ssa_op->result_def)));
6177+
6178+
if (op_array->last_live_range
6179+
&& opline->result.var > op_array->last_var
6180+
&& STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) != type) {
6181+
if (!gen_handler && type != IS_UNKNOWN && ra && RA_HAS_REG(ssa_op->result_def)) {
6182+
uint32_t var_num = opline->result.var;
6183+
uint32_t op_num = opline - op_array->opcodes;
6184+
const zend_live_range *range = op_array->live_range;
6185+
int j;
6186+
6187+
op_num += zend_jit_trace_op_len(opline);
6188+
for (j = 0; j < op_array->last_live_range; range++, j++) {
6189+
if (range->start > op_num) {
6190+
/* further blocks will not be relevant... */
6191+
break;
6192+
} else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
6193+
/* check if opcodes in range may throw */
6194+
bool store_type = 0;
6195+
const zend_ssa_op *next_ssa_op = ssa_op + zend_jit_trace_op_len(opline);
6196+
const zend_jit_trace_rec *q = p + 1;
6197+
6198+
while (1) {
6199+
if (q->op != ZEND_JIT_TRACE_VM) {
6200+
store_type = 1;
6201+
break;
6202+
}
6203+
op_num = q->opline - op_array->opcodes;
6204+
if (op_num >= range->end || op_num < range->start) {
6205+
break;
6206+
}
6207+
if (zend_may_throw(q->opline, next_ssa_op, op_array, ssa)) {
6208+
store_type = 1;
6209+
break;
6210+
}
6211+
next_ssa_op += zend_jit_trace_op_len(q->opline);
6212+
q++;
6213+
}
6214+
if (store_type) {
6215+
var_num = EX_VAR_TO_NUM(var_num);
6216+
6217+
if (!zend_jit_store_type(&ctx, var_num, type)) {
6218+
return 0;
6219+
}
6220+
SET_STACK_TYPE(stack, var_num, type, 1);
6221+
}
6222+
break;
6223+
}
6224+
}
6225+
}
6226+
}
61776227
if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
61786228
RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
61796229
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Register Alloction 021: TMP variables captured by live_ranges have to be stored
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
--FILE--
9+
<?php
10+
$a = 0;
11+
for($i = 5; $i >= 0; $i--) {
12+
$a = 1 + ++$a - 5 % $i;
13+
}
14+
?>
15+
--EXPECTF--
16+
Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %sreg_alloc_021.php:4
17+
Stack trace:
18+
#0 {main}
19+
thrown in %sreg_alloc_021.php on line 4

0 commit comments

Comments
 (0)