1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-17577: JIT packed type guard crash

When a guard check is created for a variable to check if it's a packed array,
it is possible that there was no prior type check for that variable.
This happens in the global scope for example when the variable aliases.
In the test, this causes a dereference of address 8 because the integer
element in `$a` is interpreted as an array address.

This patch adds a check to see if the guard is handled.
If we were not able to determine or guard the type then we also cannot know the array is packed.

Closes GH-17584.
This commit is contained in:
Niels Dossche
2025-01-26 13:33:40 +01:00
parent f88445bdf8
commit 0c3cf1f311
3 changed files with 43 additions and 6 deletions

1
NEWS
View File

@@ -14,6 +14,7 @@ PHP NEWS
- Opcache:
. Fixed bug GH-17654 (Multiple classes using same trait causes function
JIT crash). (nielsdos)
. Fixed bug GH-17577 (JIT packed type guard crash). (nielsdos, Dmitry)
- PHPDBG:
. Partially fixed bug GH-17387 (Trivial crash in phpdbg lexer). (nielsdos)

View File

@@ -1745,7 +1745,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
if (!(orig_op1_type & IS_TRACE_PACKED)) {
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
&& (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
info->type |= MAY_BE_PACKED_GUARD;
info->type &= ~MAY_BE_ARRAY_PACKED;
}
@@ -1754,7 +1755,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
&& val_type != IS_UNDEF) {
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
&& (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
info->type |= MAY_BE_PACKED_GUARD;
info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
}
@@ -1833,7 +1835,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
&& (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
info->type |= MAY_BE_PACKED_GUARD;
if (orig_op1_type & IS_TRACE_PACKED) {
info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
@@ -1935,7 +1938,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
&& (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
info->type |= MAY_BE_PACKED_GUARD;
if (orig_op1_type & IS_TRACE_PACKED) {
info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
@@ -1965,7 +1969,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
&& (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
info->type |= MAY_BE_PACKED_GUARD;
info->type &= ~MAY_BE_ARRAY_PACKED;
}
@@ -4164,10 +4169,14 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
if ((info & MAY_BE_PACKED_GUARD) != 0
&& (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
|| (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
&& (opline-1)->result_type == IS_VAR
&& EX_VAR_TO_NUM((opline-1)->result.var) == i))
&& (ssa->vars[i].use_chain != -1
|| (ssa->vars[i].phi_use_chain
&& !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) {
ZEND_ASSERT(STACK_TYPE(stack, i) == IS_ARRAY);
if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) {
goto jit_failure;
}

View File

@@ -0,0 +1,27 @@
--TEST--
GH-17577 (JIT packed type guard crash)
--EXTENSIONS--
opcache
--INI--
opcache.jit_buffer_size=16M
opcache.jit_hot_func=1
--FILE--
<?php
$a = array(
array(1,2,3),
0,
);
function my_dump($var) {
}
foreach($a as $b) {
for ($i = 0; $i < 3; $i++) {
my_dump($b[$i]);
}
}
?>
--EXPECTF--
Warning: Trying to access array offset on int in %s on line %d
Warning: Trying to access array offset on int in %s on line %d
Warning: Trying to access array offset on int in %s on line %d