JIT: (bug) Copying a struct larger than 64 KiB silently drops fields past the 64 KiB mark
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Repro
```csharp
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit, Size = 65600)]
struct Big
{
[FieldOffset(0)] public int Head;
[FieldOffset(65592)] public object O; // one GC slot, past 64 KiB
}
class Holder
{
public Big B;
}
class Program
{
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
static void Test(Holder h)
{
Big b = default;
b.Head = 42;
b.O = "payload";
h.B = b;
}
static void Main()
{
var h = new Holder();
Test(h);
Console.WriteLine($"{h.B.Head}, {h.B.O ?? ""}");
}
}
```
## Expected
```
42, payload
```
## Actual
```
42,
```
A Checked build also asserts while jitting `Test`:
```
Assertion failed 'lclOffs <= UINT16_MAX' in 'Program:Test(Holder)' during 'Lowering nodeinfo'
```
The struct copy loses anything stored beyond offset 65535, so the reference field arrives as `null`;
a `ref Big` destination loses it the same way. Structs this large are legal C#.
## Platform
Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1e2a). Reproduces on Checked and Release builds
with `DOTNET_TieredCompilation=0`.
Contributor guide
Research direction
Start with the supplied C# reproduction and the Checked-build assertion in JIT lowering nodeinfo. Trace how the struct copy and its GC slot offsets are represented during JIT compilation. Done means the example prints `42, payload`, the reference is preserved past offset 65535, and the Checked build no longer asserts.
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
- 48/100