JIT: (bug) x64: assert `dstOffset < (INT32_MAX - size)` in `genCodeForInitBlkUnroll`/`genCodeForCpBlkUnroll` for a boundary address-mode displacement
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
`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
```csharp
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(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(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 (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.
Contributor guide
Assessment
This issue has not been assessed yet.