Skip to content

Bug in JIT Code generation with aborts beam #11419

Closed

Description

@rk108

Describe the bug

On x86-64, BeamModuleAssembler::emit_is_in_range passes RET as the spill register to the
sub/cmp helpers. When the range width does not fit in a signed 32-bit immediate, those helpers
materialize the constant with mov_imm(RET, val), clobbering RET. The enclosing
preserve_cache(...) declares only ARG1 as clobbered, so the register cache still believes RET
holds the source BEAM register. The next instruction fetches the operand from RET and reads the
range constant instead of the actual value.

The result is a guard-checked integer that silently becomes a constant. Depending on what consumes
it, this is either a wrong result or heap corruption with a VM abort.

The BEAM code produced by the compiler is correct — this is purely JIT code generation. The bug
therefore does not show up in the shell, since erl_eval never goes through the JIT.

To Reproduce

-module(jit_bug).
-export([f/1, g/1]).

f(X) ->
    D = X band 16#FFFFFFFF,
    case D > 0 andalso D < 16#80000000 of
        true  -> D / 1;
        false -> 0.0
    end.

g(X) ->
    D = X band 16#FFFFFFFF,
    case D > 0 andalso D < 16#80000000 of
        true  -> D + 1;
        false -> 0
    end.
$ erlc jit_bug.erl

$ erl -noshell -eval 'io:format("~p~n",[jit_bug:f(100)]),halt().'
2147483646.0

$ erl -noshell -eval 'io:format("~p~n",[jit_bug:f(7)]),halt().'
2147483646.0

$ erl -noshell -eval 'io:format("~p~n",[jit_bug:g(100)]),halt().'
size_object: bad tag for 0xfffffff0

Expected behavior

jit_bug:f(100)  ->  100.0
jit_bug:f(7)    ->  7.0
jit_bug:g(100)  ->  101

Instead f/1 returns the same constant for every input, and g/1 aborts the VM.

Note that 2147483646 =:= 34359738336 bsr 4, i.e. the untagged range-width constant that
is_in_range materializes into RET.

Affected versions

Reproduced on x86-64 Linux:

OTP ERTS
27 15.2.7.6
27 15.2.7.11
28 16.4.0.4
29 17.0.4

Not tested: OTP 26 and earlier, and the aarch64 JIT. jit/arm/instr_common.cpp has a similarly
shaped emit_is_in_range, so aarch64 is probably worth checking as well.

Activity

  1. added
    bugIssue is reported as a bug
    on Aug 2, 2026
  2. added a commit that references this issue on Aug 11, 2026
  3. added a commit that references this issue on Sep 1, 2026
  4. added a commit that references this issue on Sep 1, 2026
  5. added a commit that references this issue on Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugIssue is reported as a bugteam:VMAssigned to OTP team VM

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions