-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
When using StackTrace to get the one-and-only StackFrame of a first chance exception within a AppDomain.FirstChanceException event handler, the offsets for the frames are incorrect. The ILOffset is wrong for x64 architecture and it appears that NativeOffset may be wrong on non-x64 architectures (namely x86 and arm64). This was determined using StackTrace for the current thread and searching for the corresponding StackFrame from the thrown exception within the threads call stack; while the method does exist, the offsets do not match.
Reproduction Steps
- Clone repro project from https://github.com/jander-msft/unmatched-frame-offsets.git
- Run
.\restore.cmdfrom repo root to restore toolset and dependencies. - Run
.\build.cmd -testfrom repo root to build and execute the single test.
Expected behavior
No test failures
Actual behavior
The .NET 8 test will fail. Output:
Begin Observing Exception: System.Threading.Tasks.TaskCanceledException
Throwing Frame: [ThrowForNonSuccess, 0x37]
Begin Checking Thread Frames:
- [ValidateExceptionStackFrame, 0xB5]
- [FirstChanceExceptionCallback, 0x41]
- [<AsyncExceptionCallStack>b__0, 0x6]
- [ThrowForNonSuccess, 0x26]
- [HandleNonSuccessAndDebuggerNotification, 0x2D]
- [MoveNext, 0xD7]
- [RunInternal, 0x40]
- [MoveNext, 0x40]
- [<Post>b__1, 0x0]
- [RunOnSyncContext, 0xB]
- [<WorkerThreadProc>b__0, 0x0]
- [RunInternal, 0x40]
- [Run, 0x5]
- [WorkerThreadProc, 0x7C]
- [<QueueUserWorkItem>b__5_0, 0x7]
- [RunInternal, 0x40]
- [ExecuteWithThreadLocal, 0x96]
End Checking Thread Frames:
End Observing Exception: System.Threading.Tasks.TaskCanceledException
Note that the throwing frame from inspecting StackTrace of the exception has an IL offset of 0x37 whereas the thread has an IL offset of 0x26.
Using ildasm reveals that TaskAwaiter.ThrowForNonSuccess following for the IL body:
IL_0000: /* 02 | */ ldarg.0
IL_0001: /* 6F | (06)003C8D */ callvirt instance valuetype System.Threading.Tasks.TaskStatus/*020003E1*/ System.Threading.Tasks.Task/*020003E2*/::get_Status() /* 06003C8D */
IL_0006: /* 0C | */ stloc.2
IL_0007: /* 08 | */ ldloc.2
IL_0008: /* 1C | */ ldc.i4.6
IL_0009: /* 2E | 05 */ beq.s IL_0010
IL_000b: /* 08 | */ ldloc.2
IL_000c: /* 1D | */ ldc.i4.7
IL_000d: /* 2E | 18 */ beq.s IL_0027
IL_000f: /* 2A | */ ret
IL_0010: /* 02 | */ ldarg.0
IL_0011: /* 6F | (06)003CAB */ callvirt instance class System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/ System.Threading.Tasks.Task/*020003E2*/::GetCancellationExceptionDispatchInfo() /* 06003CAB */
IL_0016: /* 0A | */ stloc.0
IL_0017: /* 06 | */ ldloc.0
IL_0018: /* 2C | 06 */ brfalse.s IL_0020
IL_001a: /* 06 | */ ldloc.0
IL_001b: /* 6F | (06)0045A7 */ callvirt instance void System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/::Throw() /* 060045A7 */
IL_0020: /* 02 | */ ldarg.0
IL_0021: /* 73 | (06)003D9A */ newobj instance void System.Threading.Tasks.TaskCanceledException/*020003FE*/::.ctor(class System.Threading.Tasks.Task/*020003E2*/) /* 06003D9A */
IL_0026: /* 7A | */ throw
IL_0027: /* 02 | */ ldarg.0
IL_0028: /* 6F | (06)003CAA */ callvirt instance class System.Collections.Generic.List`1/*020009B4*/<class System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/> System.Threading.Tasks.Task/*020003E2*/::GetExceptionDispatchInfos() /* 06003CAA */
IL_002d: /* 0B | */ stloc.1
IL_002e: /* 07 | */ ldloc.1
IL_002f: /* 6F | (0A)0001DE */ callvirt instance int32 class System.Collections.Generic.List`1/*020009B4*/<class System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/>/*1B0000C5*/::get_Count() /* 0A0001DE */
IL_0034: /* 16 | */ ldc.i4.0
IL_0035: /* 31 | 0D */ ble.s IL_0044
IL_0037: /* 07 | */ ldloc.1
IL_0038: /* 16 | */ ldc.i4.0
IL_0039: /* 6F | (0A)0001DF */ callvirt instance !0 class System.Collections.Generic.List`1/*020009B4*/<class System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/>/*1B0000C5*/::get_Item(int32) /* 0A0001DF */
IL_003e: /* 6F | (06)0045A7 */ callvirt instance void System.Runtime.ExceptionServices.ExceptionDispatchInfo/*020004D9*/::Throw() /* 060045A7 */
IL_0043: /* 2A | */ ret
IL_0044: /* 02 | */ ldarg.0
IL_0045: /* 6F | (06)003C8C */ callvirt instance class System.AggregateException/*020000D7*/ System.Threading.Tasks.Task/*020003E2*/::get_Exception() /* 06003C8C */
IL_004a: /* 7A | */ throw
Note that offset 0x37 as claimed by the exception is a ldloc.1 instruction whereas offset 0x26 from the same frame but from the thread is a throw instruction.
Regression?
Yes, regression seem to have started with SDK 8.0.100-rc.1.23381.3. .NET 6 and .NET 7 do not seem to have this issue.
Known Workarounds
Using the native offset seems to work correctly in my limited testing on x64 architectures, but is mismatched for x86 and arm64 architectures. I would have to employ an algorithm that effectively says "if x64, then use native offset, otherwise use IL offset" to try to find matching StackFrame instances.
Configuration
.NET SDK:
Version: 8.0.100-rc.1.23381.3
Commit: b625398912
Runtime Environment:
OS Name: Windows
OS Version: 10.0.22621
OS Platform: Windows
RID: win10-x64
Base Path: C:\src\jander-msft\unmatched-frame-offsets.dotnet\sdk\8.0.100-rc.1.23381.3\
.NET workloads installed:
There are no installed workloads to display.
Host:
Version: 8.0.0-rc.1.23380.3
Architecture: x64
Commit: 30db9b7
RID: win-x64
.NET SDKs installed:
8.0.100-rc.1.23381.3 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 8.0.0-rc.1.23378.7 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.20 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.9 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0-rc.1.23380.3 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 8.0.0-rc.1.23380.1 [C:\src\jander-msft\unmatched-frame-offsets.dotnet\shared\Microsoft.WindowsDesktop.App]
Other information
No response