JIT: (bug) constant-NaN Math.Min/Max folding drops the other argument's side effects
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
```csharp
using System;
using System.Runtime.CompilerServices;
class P
{
static double[] a = new double[1];
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static double Test(int i)
{
return Math.Min(a[i], double.NaN);
}
static void Main()
{
try
{
Console.WriteLine("NO EXCEPTION, result=" + Test(5));
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("IndexOutOfRangeException (correct)");
}
}
}
```
**Expected:** `IndexOutOfRangeException (correct)` — `a[5]` on a length-1 array must throw before `Math.Min` returns.
**Actual:** `NO EXCEPTION, result=NaN` — the array load, including its bounds check, is discarded.
Notes:
- `run.ps1 -Cs repro.cs` (csc `-optimize+`, Checked corerun x64). Compiling with `-optimize-` prints the correct `IndexOutOfRangeException`, so it is purely the optimized-JIT path.
- `src\coreclr\jit\gentree.cpp` in `gtNewSimdMinMaxNode`: the `isNaN` shortcut does `return cnsNode;` (non-Number) / `return otherNode;` (Number) with no `gtExtractSideEffList`/COMMA for the discarded operand.
- Only on the non-AVX10v2 xarch path (the AVX10v2 branch is taken earlier and is unaffected). Same shape works for `MathF.Min`, `Math.Max`, and the `MinNumber`/`MaxNumber` variants (drop the *other* operand there).
Contributor guide
Assessment
This issue has not been assessed yet.