JIT: (bug) Assert `varTypeIsIntegral(type) || varTypeIsGC(type)` in morph: comma-throw propagated into a struct-typed parent
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
`fgPropagateCommaThrow` calls `BashToZeroConst(genActualType(parent))` for any non-`void` parent. With a
struct-typed parent (here a `GT_BLK` from a struct array load) this asserts in a Checked JIT and builds
malformed struct-typed `CNS_INT` IR in Release.
### Minimal Repro
```csharp
using System;
using System.Runtime.CompilerServices;
struct S { public int a, b, c, d; }
class Program
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static int Idx(long v) => checked((int)v);
[MethodImpl(MethodImplOptions.NoInlining)]
static S Test(S[] a) => a[Idx(long.MaxValue)];
static void Main()
{
try { Console.WriteLine(Test(new S[4]).a); }
catch (OverflowException) { Console.WriteLine("OverflowException"); }
}
}
```
Requires `DOTNET_TieredCompilation=0`; at tier-0 the folding does not happen.
### Expected
```
OverflowException
```
### Actual
```
Assert failure(PID 148588 [0x0002446c], Thread: 59900 [0xe9fc]): Assertion failed
'varTypeIsIntegral(type) || varTypeIsGC(type)' in 'Program:Test(S[]):S' during 'Morph - Global'
(IL size 21; hash 0xb183d2e0; FullOpts)
File: src\coreclr\jit\compiler.hpp:2191
```
Process exits with `0xC0000409`.
### Notes
After inlining, `gtFoldExprConst` turns the always-throwing checked cast into `COMMA(throw, 0)`, which
`fgPropagateCommaThrow` then propagates into the struct-typed parent; it should bail out (or use a different
"zero" representation) when the parent is not integral/GC-typed.
`Span` indexing and `S s = a[Idx(long.MaxValue)];` hit the same assert.
Release .NET 10.0.12 prints `OverflowException` — this is a Checked-assert / malformed-IR issue, not a known
silent bad-codegen bug.
Contributor guide
Research direction
Start with fgPropagateCommaThrow and gtFoldExprConst in the JIT, then inspect the assertion in src/coreclr/jit/compiler.hpp. Run the supplied C# reproducer with DOTNET_TieredCompilation=0 and compare Checked and Release behavior; done means the struct-typed parent no longer triggers the assertion or malformed IR and the repro prints OverflowException.
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