Skip to content

Commit 886dd7c

Browse files
committed
Improve fix for GH-12512: JIT Assertion `info & (1 << type)' failed
1 parent 5492f0a commit 886dd7c

File tree

2 files changed

+169
-2
lines changed

2 files changed

+169
-2
lines changed

ext/opcache/jit/zend_jit_trace.c

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3842,6 +3842,126 @@ static bool zend_jit_trace_next_is_send_result(const zend_op *oplin
38423842
return 0;
38433843
}
38443844

3845+
static int zend_jit_find_ssa_var(const zend_op_array *op_array,
3846+
const zend_ssa *ssa,
3847+
uint32_t opline_num,
3848+
uint32_t var_num)
3849+
{
3850+
int ssa_var, j, b = ssa->cfg.map[opline_num];
3851+
const zend_basic_block *bb = ssa->cfg.blocks + b;
3852+
const zend_ssa_phi *phi;
3853+
const zend_ssa_op *ssa_op;
3854+
zend_worklist worklist;
3855+
ALLOCA_FLAG(use_heap)
3856+
3857+
while (1) {
3858+
ssa_op = ssa->ops + opline_num;
3859+
ssa_var = ssa_op->result_def;
3860+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3861+
return ssa_var;
3862+
}
3863+
ssa_var = ssa_op->op2_def;
3864+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3865+
return ssa_var;
3866+
}
3867+
ssa_var = ssa_op->op1_def;
3868+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3869+
return ssa_var;
3870+
}
3871+
if (opline_num == bb->start) {
3872+
break;
3873+
}
3874+
opline_num--;
3875+
}
3876+
phi = ssa->blocks[b].phis;
3877+
ssa_var = -1;
3878+
while (phi) {
3879+
if (phi->var == var_num) {
3880+
ssa_var = phi->ssa_var;
3881+
}
3882+
phi = phi->next;
3883+
}
3884+
if (ssa_var >= 0) {
3885+
return ssa_var;
3886+
}
3887+
3888+
if (!bb->predecessors_count) {
3889+
return -1;
3890+
}
3891+
3892+
ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
3893+
3894+
for (j = 0; j < bb->predecessors_count; j++) {
3895+
b = ssa->cfg.predecessors[bb->predecessor_offset + j];
3896+
zend_worklist_push(&worklist, b);
3897+
}
3898+
3899+
while (zend_worklist_len(&worklist) != 0) {
3900+
b = zend_worklist_pop(&worklist);
3901+
bb = &ssa->cfg.blocks[b];
3902+
if (bb->len) {
3903+
opline_num = bb->start + bb->len - 1;
3904+
while (1) {
3905+
ssa_op = ssa->ops + opline_num;
3906+
ssa_var = ssa_op->result_def;
3907+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3908+
goto found;
3909+
}
3910+
ssa_var = ssa_op->op2_def;
3911+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3912+
goto found;
3913+
}
3914+
ssa_var = ssa_op->op1_def;
3915+
if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
3916+
goto found;
3917+
}
3918+
if (opline_num == bb->start) {
3919+
break;
3920+
}
3921+
opline_num--;
3922+
}
3923+
}
3924+
phi = ssa->blocks[b].phis;
3925+
ssa_var = -1;
3926+
while (phi) {
3927+
if (phi->var == var_num) {
3928+
ssa_var = phi->ssa_var;
3929+
}
3930+
phi = phi->next;
3931+
}
3932+
if (ssa_var >= 0) {
3933+
goto found;
3934+
}
3935+
for (j = 0; j < bb->predecessors_count; j++) {
3936+
b = ssa->cfg.predecessors[bb->predecessor_offset + j];
3937+
zend_worklist_push(&worklist, b);
3938+
}
3939+
}
3940+
return -1;
3941+
3942+
found:
3943+
ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
3944+
return ssa_var;
3945+
}
3946+
3947+
static bool zend_jit_trace_must_store_type(const zend_op_array *op_array,
3948+
const zend_ssa *ssa,
3949+
uint32_t opline_num,
3950+
uint32_t var_num,
3951+
uint8_t type)
3952+
{
3953+
if (ssa->var_info) {
3954+
int ssa_var = zend_jit_find_ssa_var(op_array, ssa, opline_num, var_num);
3955+
3956+
if (ssa_var >= 0) {
3957+
if ((ssa->var_info[ssa_var].type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1U << type)) {
3958+
return 0;
3959+
}
3960+
}
3961+
}
3962+
return 1;
3963+
}
3964+
38453965
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
38463966
{
38473967
const void *handler = NULL;
@@ -6861,12 +6981,15 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
68616981
int32_t ref = STACK_REF(stack, i);
68626982
uint8_t type = STACK_TYPE(stack, i);
68636983

6864-
if (ref && (!(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE)))) {
6984+
if (ref && !(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE))) {
68656985
if (!zend_jit_store_ref(jit, 1 << type, i, ref, STACK_MEM_TYPE(stack, i) != type)) {
68666986
goto jit_failure;
68676987
}
68686988
SET_STACK_TYPE(stack, i, type, 1);
6869-
} else if (type != IS_UNKNOWN && type != STACK_MEM_TYPE(stack, i)) {
6989+
} else if (i < op_array->last_var
6990+
&& type != IS_UNKNOWN
6991+
&& type != STACK_MEM_TYPE(stack, i)
6992+
&& zend_jit_trace_must_store_type(op_array, op_array_ssa, opline - op_array->opcodes, i, type)) {
68706993
if (!zend_jit_store_type(jit, i, type)) {
68716994
return 0;
68726995
}

ext/opcache/tests/jit/gh12512_2.phpt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
GH-12512: missing type store
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
--FILE--
7+
<?php
8+
function foo(array $a, $exit) {
9+
$n = 0;
10+
11+
$count = count($a);
12+
if ($count == 0) {
13+
return 0;
14+
}
15+
$a2 = [];
16+
foreach ($a as $v) {
17+
$a2[] = $v;
18+
}
19+
20+
$count = $a2[5];
21+
22+
for ($i = 0; $i < $count; $i++) {
23+
$x = $a[$i];
24+
for ($k = $i + 1; $k < $count; $k++) {
25+
$y = $a[$k];
26+
$n += $x > $y;
27+
}
28+
if ($exit) {
29+
return $n;
30+
}
31+
}
32+
33+
return $n;
34+
}
35+
var_dump(foo([1,2,3,4,5,6,7,8], 1));
36+
var_dump(foo([1,2,3,4,5,6,7,8], 1));
37+
var_dump(foo([1,2,3,4,5,6,7,8], 0));
38+
?>
39+
DONE
40+
--EXPECT--
41+
int(0)
42+
int(0)
43+
int(0)
44+
DONE

0 commit comments

Comments
 (0)