dotnet / dotnet/runtime

JIT: (bug) Bounds check incorrectly eliminated — range analysis ignores signed underflow of `x + negativeConstant`

Open
#133,820 1 comment 0 reactions 0 assignees View on GitHub
area-CodeGen-coreclr
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

RangeCheck removes an array bounds check for an index computed as `x + ` without accounting for signed underflow of the addition. The result is a silent out-of-bounds read instead of `IndexOutOfRangeException`.

### Minimal Repro

```csharp
using System;
using System.Runtime.CompilerServices;

public static class Program
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public static int Test(int x)
{
int[] arr = new int[8];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = i + 1;
}

if (x < int.MaxValue)
{
int y = x + (-2147483640);
if (y >= 0)
{
return arr[y];
}
}
return -1;
}

public static void Main()
{
Console.WriteLine(Test(int.MinValue));
}
}
```

### Expected

`int.MinValue + (-2147483640)` wraps to `8`, and `arr.Length == 8`, so the indexer must throw:

```
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Program.Test(Int32 x)
at Program.Main()
```

### Actual

```
UB
```

No `CORINFO_HELP_RNGCHKFAIL` is emitted. `DOTNET_JITMinOpts=1` throws correctly.

### Notes

- x64, `main` @ `6ed2ba318dcaa936da60f7d6bc9eb30cad54fc0c`; also reproduces on .NET 10.0.12 Release, so not a regression (not bisected further).
- Also happens with a heap array (store `arr` into a static to force escape), turning it into an out-of-bounds *heap* read.
- Root cause: from `x <= int.MaxValue - 1` the JIT derives `y <= 6`, and with the dominating `y >= 0` concludes `y in [0, 6]`. `RangeCheck::AddOverflows` / `GetLimitMax` (`src/coreclr/jit/rangecheck.cpp`) only test the operands' *upper* limits, so underflow at the lower end — one operand a negative constant, the other's lower limit unconstrained at `int.MinValue` — is never detected.

Contributor guide

Open the contributing guide

Research direction

Start in src/coreclr/jit/rangecheck.cpp, focusing on RangeCheck::AddOverflows and GetLimitMax, and reproduce the issue with the provided C# program using the stated runtime configuration. Done means signed underflow is accounted for so the array access retains its bounds check and the repro throws IndexOutOfRangeException rather than producing an out-of-bounds read.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.