Skip to content

Commit ef873f6

Browse files
committed
Fix JIT SWITCH_STRING type checks on referenced operand
The tracing guard checked IS_LONG instead of IS_STRING after ZVAL_DEREF, passing a non-string to zend_hash_find(). The function JIT path checked IS_STRING instead of IS_REFERENCE, so the deref fast path was dead. Closes GH-24796.
1 parent 154b090 commit ef873f6

4 files changed

Lines changed: 57 additions & 2 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ PHP NEWS
159159
. Fixed bug GH-24675 (function with >~1.7 MB of machine code corrupts JIT
160160
buffer accounting). (ndossche)
161161
. Call orig_post_shutdown_cb(). (ndossche)
162+
. Fixed JIT segfault on switch over a string reference holding a
163+
non-string value. (jorgsowa)
162164

163165
- PDO:
164166
. Fixed invalid ATTR_ORACLE_NULLS values being accepted and truncated.

‎ext/opcache/jit/zend_jit_ir.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16247,7 +16247,7 @@ static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_
1624716247
if (fallback_label) {
1624816248
jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
1624916249
} else {
16250-
ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16250+
ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
1625116251
ir_IF_FALSE_cold(if_ref);
1625216252
ir_refs_add(slow_inputs, ir_END());
1625316253
ir_IF_TRUE(if_ref);
@@ -16257,7 +16257,7 @@ static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_
1625716257
op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
1625816258

1625916259
if (fallback_label) {
16260-
jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16260+
jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
1626116261
} else {
1626216262
if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
1626316263
ir_IF_FALSE_cold(if_string);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
JIT SWITCH_STRING on a reference holding a non-string value
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit=tracing
8+
opcache.jit_hot_loop=1
9+
--EXTENSIONS--
10+
opcache
11+
--FILE--
12+
<?php
13+
function test($a) {
14+
$n = 0;
15+
foreach ($a as &$x) {
16+
switch ($x) {
17+
case "a": case "b": $n++; break;
18+
}
19+
}
20+
return $n;
21+
}
22+
var_dump(test(["a"]));
23+
var_dump(test([1]));
24+
?>
25+
--EXPECT--
26+
int(1)
27+
int(0)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
JIT SWITCH_STRING on a reference (function JIT)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit=function
8+
--EXTENSIONS--
9+
opcache
10+
--FILE--
11+
<?php
12+
function test($a) {
13+
$n = 0;
14+
foreach ($a as &$x) {
15+
switch ($x) {
16+
case "a": case "b": $n++; break;
17+
}
18+
}
19+
return $n;
20+
}
21+
var_dump(test(["a", "b", "c"]));
22+
var_dump(test([1]));
23+
?>
24+
--EXPECT--
25+
int(2)
26+
int(0)

0 commit comments

Comments
 (0)