Description
With the function JIT and the optimizer turned off, a caught DivisionByZeroError thrown in the middle of an integer expression crashes PHP while the exception is unwound.
<?php
function deep(int $a,int $b,int $c){$a&=255;return ($a+1)-($b+$b+(($a+1)%($b%$c)));}
$out=[deep(15,3,7)];
try{deep(15,3,0);}catch(DivisionByZeroError $e){$out[]=$e->getMessage();}
echo json_encode($out),"\n";php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=32M -d opcache.jit=function -d opcache.optimization_level=0 input.php
A UBSan build (run with USE_ZEND_ALLOC=0) reports:
Zend/zend_types.h:1418:9: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'struct zend_refcounted', which requires 4 byte alignment
#0 zval_delref_p Zend/zend_types.h:1418
#1 zval_ptr_dtor_nogc Zend/zend_variables.h:34
#2 cleanup_live_vars Zend/zend_execute.c:4991
#3 zend_dispatch_try_catch_finally_helper_SPEC Zend/zend_vm_execute.h:3384
#4 ZEND_HANDLE_EXCEPTION_SPEC_HANDLER Zend/zend_vm_execute.h:3458
A release build segfaults (exit 139) on the same command.
Expected output is [9,"Modulo by zero"], which is what the same script prints without the JIT.
Found at commit c65321c and it still reproduces at 3b8e988 (UBSan build: the report above; release build: segfault, exit 139). With the default opcache.optimization_level it does not fail, and I did not see it with opcache.jit=tracing. The release crash depends on heap contents: this input crashed 3/3, but a shorter variant (function f(int $a, int $c) { $a &= 255; return $a + 1 + $a % $c; }) only fails in the UBSan build.
Looks like the int temporary $a+1 is kept only in a register by the JIT and its frame slot (including the type) is never written, so cleanup_live_vars in Zend/zend_execute.c calls zval_ptr_dtor_nogc on garbage; the store is probably skipped somewhere in ext/opcache/jit/zend_jit_ir.c. Open PR #18392 (JIT and the IP register) may be related, not tested here.
The script is test input the tool generated and I reduced, not code from a real program.
Found with an LLM-based testing tool; I used Claude to reduce it and look for the cause.
Activity
Fix phpGH-24988: Incorrect opcode range check causes bugs with except…
Merge branch 'PHP-8.4' into PHP-8.5
Merge branch 'PHP-8.5' into PHP-8.6
Merge branch 'PHP-8.6'