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:
1
NEWS
1
NEWS
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
27
ext/opcache/tests/jit/gh17577.phpt
Normal file
27
ext/opcache/tests/jit/gh17577.phpt
Normal 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
|
||||
Reference in New Issue
Block a user