dotnet / dotnet/runtime

JIT: (bug) Native-int-typed stack address is CSE'd across an await and reused after resumption

Open
#133,588 1 comment 0 reactions 1 assignee Claimed by @jakobbotsch View on GitHub
area-CodeGen-coreclr runtime-async
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.Threading.Tasks;

public static class Program
{
struct Buf { public int E0, E1, E2, E3, E4, E5, E6, E7; }

[MethodImpl(MethodImplOptions.NoInlining)]
static void Sink(ref int x) { x += 1; }

[MethodImpl(MethodImplOptions.NoInlining)]
static async Task Test(int index)
{
Buf buf = default;
Sink(ref Unsafe.Add(ref Unsafe.As(ref buf), index));
await Task.Yield();
Sink(ref Unsafe.Add(ref Unsafe.As(ref buf), index));
return buf.E0 + buf.E1 + buf.E2 + buf.E3 + buf.E4 + buf.E5 + buf.E6 + buf.E7;
}

public static int Main()
{
Console.WriteLine("start");
int r = Test(1).GetAwaiter().GetResult();
Console.WriteLine("result = " + r);
return 100;
}
}
```

Requires `runtime-async=on` in the project file.

## Expected

```
start
result = 2
```

## Actual

```
start
result = 1
```

The second `Sink` call writes through the address computed before the suspension, so the increment
lands in the abandoned frame instead of `buf.E1`. The `Unsafe.As` is what makes the
address native-int-typed rather than byref: writing `Unsafe.Add(ref buf.E0, index)` instead keeps it
byref-typed and prints the correct `result = 2`. Setting `DOTNET_JitNoCSE=1` also restores
`result = 2`.

## Platform

Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1e2a), `DOTNET_TieredCompilation=0`, runtime async
enabled. No special CPU features. Output above is from the Release build and is stable across runs;
on the Checked build the same program instead dies with an access violation after printing `start`
(exit code `-1073741819`).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.