[php-src] Issue #24391: JIT: switch on constant null takes default instead of case 0 (opcache.jit=function, optimization_level=0)

From: Date: Sat, 17 Oct 2026 22:07:32 +0000
Subject: [php-src] Issue #24391: JIT: switch on constant null takes default instead of case 0 (opcache.jit=function, optimization_level=0)
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253016@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24391 Author: waroad With the function JIT and the optimizer disabled, switch (null) with enough integer cases jumps to default instead of taking case 0. ```php <?php function f() { switch (null) { case 0: return 1; case 1: return 2; case 2: return 3; case 3: return 4; case 4: return 5; default: return 6; } } var_dump(f()); ``` ``` php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=64M -d opcache.jit=function -d opcache.optimization_level=0 input.php ``` ``` int(6) ``` Expected int(1), since null == 0 is true. The interpreter with the same settings but opcache.jit=0 prints int(1). Found at c65321c70f7de5f4a4f810f1d23112374d92d1a7 and it still reproduces at 5ccc56b1e43f. The debug/sanitizer build and the release build both print int(6) with exit code 0, no assertion or crash. With the default opcache.optimization_level the output is int(1), and with 3 cases instead of 5 it is also right (no jump table is emitted). This looks like the IS_CONST branch of zend_jit_switch in ext/opcache/jit/zend_jit_ir.c: for a constant of the wrong type for SWITCH_LONG/SWITCH_STRING it goes to the default target, while the VM handler continues at opline+1 (the IS_EQUAL chain). The tracing JIT trips over the same branch. Here switch (0) compiles to SWITCH_STRING with an int constant, the VM continues at opline+1, and the JIT's default target does not match the trace: ```php <?php function f() { switch (0) { case "aa": $b=1;break; case "bb": $b=2; break; case "cc": $b=3; break; default: $b=6; } return $b; } for ($i=0;$i<80;$i++) $r=f(); echo json_encode($r),"\n"; ``` ``` php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=64M -d opcache.jit=tracing -d opcache.optimization_level=0 input.php ``` ``` php: ext/opcache/jit/zend_jit_ir.c:16424: zend_jit_switch: Assertion `target == next_opline' failed. ``` That is the debug build at c65321c70f7d (exit 134; with opcache.jit=0 it prints 6). I did not run this one on a release build or at 5ccc56b1e43f. The trigger is contrived (a literal constant as the switch subject, optimizer off); it is not from a real program. Found with an LLM-based testing tool; I used Claude to reduce it and look for the cause.

« previous php.bugs (#253016) next »