JIT: (bug) localloc with a negative native-int constant size becomes a zero-sized allocation
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Repro
C#'s `stackalloc` emits `conv.u`, which zero-extends, so the negative constant has to come from IL.
```csharp
using System;
using System.Reflection.Emit;
unsafe class Program
{
delegate byte* Alloc();
static void Main()
{
var m = new DynamicMethod("NegLocalloc", typeof(byte*), Type.EmptyTypes);
m.InitLocals = true;
ILGenerator il = m.GetILGenerator();
il.DeclareLocal(typeof(IntPtr));
il.Emit(OpCodes.Ldc_I4_M1);
il.Emit(OpCodes.Conv_I); // native int -1 == (nuint)ulong.MaxValue bytes
il.Emit(OpCodes.Localloc);
il.Emit(OpCodes.Ret);
byte* p = m.CreateDelegate()();
Console.WriteLine($"localloc returned {(nint)p:X}");
if (p != null) { p[0] = 1; Console.WriteLine(p[0]); }
}
}
```
Run with `DOTNET_TieredCompilation=0`.
## Expected
A request for `(nuint)(-1)` bytes cannot be satisfied, so `localloc` should overflow the stack
rather than succeed.
## Actual
On a **Release** runtime the allocation "succeeds" and hands back a writable pointer:
```
localloc returned 479677EC10
1
```
The size is rounded up and wraps to 0, so the JIT emits a zero-byte allocation but still returns a
non-null pointer; writing through it corrupts unrelated stack memory instead of failing the request.
A Checked runtime asserts five times on the same method (`DOTNET_ContinueOnAssert=1` to see them all):
```
Assertion failed 'layout->GetSize() != 0' in '(dynamicClass):NegLocalloc():ptr' during 'Lowering nodeinfo'
Assertion failed '(amount > 0) && (amount <= UINT_MAX)' in '(dynamicClass):NegLocalloc():ptr' during 'Generate code'
Assertion failed 'amount > 0' in '(dynamicClass):NegLocalloc():ptr' during 'Generate code'
Assertion failed 'spDelta < 0' in '(dynamicClass):NegLocalloc():ptr' during 'Generate code'
Assertion failed 'spDelta < 0' in '(dynamicClass):NegLocalloc():ptr' during 'Generate code'
```
## Platform
Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1e2a). Reproduces on Release and Checked builds
with `DOTNET_TieredCompilation=0`; no special CPU features.
Contributor guide
Assessment
This issue has not been assessed yet.