Skip to content

JIT: (bug) x64: assert dstOffset < (INT32_MAX - size) in genCodeForInitBlkUnroll/genCodeForCpBlkUnroll for a boundary address-mode displacement #133785

Description

@EgorBo

Lowering::ContainBlockStoreAddress accepts addrMode->Offset() == INT32_MAX - size (it rejects only >), while genCodeFor{Init,Cp}BlkUnroll assert the strict srcOffset/dstOffset < (INT32_MAX - size). A contained LEA(base + (INT32_MAX - size)) feeding an unrolled STORE_BLK therefore trips the assert in a Checked JIT.

Minimal Repro

using System;
using System.Runtime.CompilerServices;

public struct S3 { public byte A, B, C; }

public static class P
{
    // element offset = 16 + 715827876*3 = 2147483644 == int.MaxValue - 3
    const int Idx = 715827876;

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    public static void StoreCopy(S3[] arr, S3 v) => arr[Idx] = v;

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    public static void StoreInit(S3[] arr) => arr[Idx] = default;

    public static void Main(string[] args)
    {
        var a = new S3[1];
        if (args.Length == 0)
        {
            try { StoreInit(a); } catch (IndexOutOfRangeException) { Console.WriteLine("ok2"); }
        }
        else
        {
            try { StoreCopy(a, default); } catch (IndexOutOfRangeException) { Console.WriteLine("ok1"); }
        }
    }
}
set DOTNET_TieredCompilation=0
corerun out\blkdisp.dll        :: STORE_BLK (init) -> genCodeForInitBlkUnroll
corerun out\blkdisp.dll x      :: STORE_BLK (copy) -> genCodeForCpBlkUnroll

(The two methods are split by args because the first one jitted aborts the process.)

Expected

ok2

and

ok1

Actual

Assert failure(PID 30132, Thread: 33480): Assertion failed 'dstOffset < (INT32_MAX - static_cast<int>(size))'
in 'P:StoreInit(S3[])' during 'Generate code' (IL size 18; hash 0xe8a9310d; FullOpts)

    File: C:\prj\runtime-main3\src\coreclr\jit\codegenxarch.cpp:3219
Assert failure(PID 43972, Thread: 31304): Assertion failed 'dstOffset < (INT32_MAX - static_cast<int>(size))'
in 'P:StoreCopy(S3[],S3)' during 'Generate code' (IL size 13; hash 0x2433ddfe; FullOpts)

    File: C:\prj\runtime-main3\src\coreclr\jit\codegenxarch.cpp:3550

DOTNET_JitDump=StoreInit shows the contained boundary address mode right before the assert:

N017 (  1,  5) [000014] -c---+-----          t14 = *  LEA(b+2147483644) byref  REG NA
N021 ( 17, 25) [000004] nA-XG+-----                *  STORE_BLK struct<S3, 3> (init) (Unroll) REG NA $145

Notes

  • Off-by-one between lowerxarch.cpp:405 (>) and codegenxarch.cpp:3219/:3549-3550 (<); either lowering should reject >= or the asserts should use <=.
  • Over-strict assert, not a codegen bug: the largest displacement actually emitted is offset + size - 1 <= INT32_MAX - 1, so release codegen is correct (verified on .NET 10.0.12, which prints ok2/ok1).
  • Checked JIT, optimized codegen, x64/x86 only; with DOTNET_JITMinOpts=1 no containment happens and both methods run fine.
  • main @ b44cd904110a27d96ea83621e94332d55150d482; not a regression, the mismatch is present in the .NET 10 sources too.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions