dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

Rethrow stack trace reporting difference between NativeAOT and CoreCLR #107507

Open SingleAccretion opened 1 week ago

SingleAccretion commented 1 week ago

Test app:

[MethodImpl(MethodImplOptions.NoInlining)]
static void ThrowCatchAndRethrow(bool doCatch)
{
    try
    {
        throw new Exception();
    }
    catch when (doCatch)
    {
        throw;
    }
}

try
{
    ThrowCatchAndRethrow(doCatch: true);
}
catch (Exception e)
{
    Console.WriteLine("With rethrow:\n" + e.StackTrace);
    Console.WriteLine($"Offset: 0x{new StackTrace(e).GetFrame(0).GetNativeOffset():X}");
}

try
{
    ThrowCatchAndRethrow(doCatch: false);
}
catch (Exception e)
{
    Console.WriteLine("\nNo rethrow:\n" + e.StackTrace);
    Console.WriteLine($"Offset: 0x{new StackTrace(e).GetFrame(0).GetNativeOffset():X}");
}

CoreCLR output:

> dotnet run -f net9.0
With rethrow:
   at RyuJitReproduction.Program.ThrowCatchAndRethrow(Boolean doCatch) in C:\Users\Accretion\source\dotnet\RyuJit\RyuJitReproduction\Program.cs:line 77
   at RyuJitReproduction.Program.Main() in C:\Users\Accretion\source\dotnet\RyuJit\RyuJitReproduction\Program.cs:line 94
Offset: 0x54

No rethrow:
   at RyuJitReproduction.Program.ThrowCatchAndRethrow(Boolean doCatch) in C:\Users\Accretion\source\dotnet\RyuJit\RyuJitReproduction\Program.cs:line 77
   at RyuJitReproduction.Program.Main() in C:\Users\Accretion\source\dotnet\RyuJit\RyuJitReproduction\Program.cs:line 104
Offset: 0x54

Note how the native offsets are equal, and so are the line numbers.

NativeAOT output:

> dotnet publish -f net9.0 /p:PublishAot=true && .\bin\Release\net9.0\win-x64\publish\RyuJitReproduction.exe
With rethrow:
   at RyuJitReproduction.Program.ThrowCatchAndRethrow(Boolean) + 0x50
   at RyuJitReproduction.Program.Main() + 0x55
Offset: 0x50

No rethrow:
   at RyuJitReproduction.Program.ThrowCatchAndRethrow(Boolean) + 0x2d
   at RyuJitReproduction.Program.Main() + 0x5e
Offset: 0x2D

Note how different IPs are reported (the IP of the throw is switched to the IP of the rethrow).

See also ThrowStatementDoesNotResetExceptionStackLineOtherMethod, which suggests that this difference is a NativeAOT bug.

This is the reason for the difference: https://github.com/dotnet/runtime/blob/c4792a228ea36792b90f87ddf7fce2477e827822/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Exception.NativeAot.cs#L66-L73

dotnet-policy-service[bot] commented 1 week ago

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas See info in area-owners.md if you want to be subscribed.