Skip to content

JIT: crash in cleanup_live_vars when % by zero throws mid-expression (function JIT, optimization_level=0) #24988

Closed

Description

@waroad

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

  1. self-assigned this
    on Oct 30, 2026
  2. added 4 commits that reference this issue on Oct 31, 2026
    bc3a830
    95c838b
    99b8c6a
    c0ae93b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions