dotnet / runtime

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

Uncaught ThreadInterruptedException does not print unhandled exception message to console #107594

Open AustinWise opened 1 month ago

AustinWise commented 1 month ago

Description

Unlike every other uncaught exception in CoreCLR, an uncaught ThreadInterruptedException exits the process without printing an "unhandled exception" message to the console.

Reproduction Steps

Create a console program with dotnet new console. Replace the contents of Program.cs with the following:

using System.Threading;
throw new ThreadInterruptedException();

Run.

Expected behavior

I would expect a message to be printing to the console that looks roughly like this:

Unhandled exception. System.Threading.ThreadInterruptedException: Thread was interrupted from a waiting state.
   at Program.<Main>$(String[] args) in C:\temp\interrupt-test\Program.cs:line 2

Actual behavior

Nothing is printed. On unix-like operating systems, the shell says "aborted (core dumped)". Note that the "core dumped" message is only visible if the built executable is run directly, not if run with dotnet run.

Regression?

No, this reproduces in .NET 8 and .NET 6. .NET Framework 4.8.1 also has this behavior.

Known Workarounds

This exception can be caught with a normal exception handler. The ability to catch this exception is not a problem.

Configuration

This behavior reproduces with .NET 8.0.8 on the following systems:

Other information

I ran the reproducer program on HEAD of this repo to gather some stack traces. The system was a X64 Linux system. The problem reproduces both with the new and old exception handling.

DOTNET_LegacyExceptionHandling=1 Native stack trace: ``` * frame #0: 0x00007ffff78969fc libc.so.6`__GI___pthread_kill at pthread_kill.c:44:76 frame #1: 0x00007ffff78969b0 libc.so.6`__GI___pthread_kill [inlined] __pthread_kill_internal(signo=6, threadid=140737352611648) at pthread_kill.c:78:10 frame #2: 0x00007ffff78969b0 libc.so.6`__GI___pthread_kill(threadid=140737352611648, signo=6) at pthread_kill.c:89:10 frame #3: 0x00007ffff7842476 libc.so.6`__GI_raise(sig=6) at raise.c:26:13 frame #4: 0x00007ffff78287f3 libc.so.6`__GI_abort at abort.c:79:7 frame #5: 0x00007ffff76ceed3 libcoreclr.so`::PROCAbort(signal=6, siginfo=0x0000000000000000) at process.cpp:2562:5 frame #6: 0x00007ffff76ceb5e libcoreclr.so`PROCEndProcess(hProcess=0x00000000ffffff01, uExitCode=1, bTerminateUnconditionally=YES) at process.cpp:1354:13 frame #7: 0x00007ffff76cec30 libcoreclr.so`::TerminateProcess(hProcess=0x00000000ffffff01, uExitCode=1) at process.cpp:1251:11 frame #8: 0x00007ffff6ca339b libcoreclr.so`CrashDumpAndTerminateProcess(exitCode=1) at excep.cpp:3962:5 frame #9: 0x00007ffff70892c5 libcoreclr.so`UnwindManagedExceptionPass1(ex=0x00007fffffffc380, frameContext=0x00007fffffffb570) at exceptionhandling.cpp:4967:17 frame #10: 0x00007ffff70898ec libcoreclr.so`DispatchManagedException(ex=0x00007fffffffc380, isHardwareException=false) at exceptionhandling.cpp:5052:17 frame #11: 0x00007ffff6f3ee52 libcoreclr.so`IL_Throw(obj=0x00007fbf5e80a9e8) at jithelpers.cpp:3052:5 frame #12: 0x00007fff79121d4a frame #13: 0x00007ffff71e2a14 libcoreclr.so`CallDescrWorkerInternal at calldescrworkeramd64.S:70 frame #14: 0x00007ffff6e663d5 libcoreclr.so`CallDescrWorkerWithHandler(pCallDescrData=0x00007fffffffc7d8, fCriticalCall=NO) at callhelpers.cpp:63:5 frame #15: 0x00007ffff6e670cc libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=0x00007fffffffc900, pArguments=0x00007fffffffc8a8, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:585:9 frame #16: 0x00007ffff6bd3e53 libcoreclr.so`MethodDescCallSite::Call(this=0x00007fffffffc900, pArguments=0x00007fffffffc8a8) at callhelpers.h:465:9 frame #17: 0x00007ffff6bf5fdf libcoreclr.so`RunMainInternal(pParam=0x00007fffffffcb60) at assembly.cpp:1211:21 ``` .NET stack trace: ``` (lldb) sos clrstack OS Thread Id: 0x23b92 (1) Child SP IP Call Site 00007FFFFFFFC3C8 00007ffff78969fc [HelperMethodFrame: 00007fffffffc3c8] 00007FFFFFFFC4D0 00007FFF79121D4A Program.
$(System.String[]) ```
DOTNET_LegacyExceptionHandling=0 Native stack trace: ``` * frame #0: 0x00007ffff78969fc libc.so.6`__GI___pthread_kill at pthread_kill.c:44:76 frame #1: 0x00007ffff78969b0 libc.so.6`__GI___pthread_kill [inlined] __pthread_kill_internal(signo=6, threadid=140737352611648) at pthread_kill.c:78:10 frame #2: 0x00007ffff78969b0 libc.so.6`__GI___pthread_kill(threadid=140737352611648, signo=6) at pthread_kill.c:89:10 frame #3: 0x00007ffff7842476 libc.so.6`__GI_raise(sig=6) at raise.c:26:13 frame #4: 0x00007ffff78287f3 libc.so.6`__GI_abort at abort.c:79:7 frame #5: 0x00007ffff76ceed3 libcoreclr.so`::PROCAbort(signal=6, siginfo=0x0000000000000000) at process.cpp:2562:5 frame #6: 0x00007ffff76ceb5e libcoreclr.so`PROCEndProcess(hProcess=0x00000000ffffff01, uExitCode=3762504530, bTerminateUnconditionally=YES) at process.cpp:1354:13 frame #7: 0x00007ffff76cec30 libcoreclr.so`::TerminateProcess(hProcess=0x00000000ffffff01, uExitCode=3762504530) at process.cpp:1251:11 frame #8: 0x00007ffff6ca339b libcoreclr.so`CrashDumpAndTerminateProcess(exitCode=3762504530) at excep.cpp:3962:5 frame #9: 0x00007ffff7092bd2 libcoreclr.so`::SfiNext(pThis=0x00007fffffff8940, uExCollideClauseIdx=0x00007fffffff85b0, fUnwoundReversePInvoke=0x00007fffffff85c0, pfIsExceptionIntercepted=0x00007fffffff85d0) at exceptionhandling.cpp:8580:21 frame #10: 0x00007fff77bc4e9b frame #11: 0x00007fff77b9844b frame #12: 0x00007fff77b97e5c frame #13: 0x00007ffff71e2a14 libcoreclr.so`CallDescrWorkerInternal at calldescrworkeramd64.S:70 frame #14: 0x00007ffff6e663d5 libcoreclr.so`CallDescrWorkerWithHandler(pCallDescrData=0x00007fffffff8708, fCriticalCall=YES) at callhelpers.cpp:63:5 frame #15: 0x00007ffff6e66825 libcoreclr.so`DispatchCallSimple(pSrc=0x00007fffffff8810, numStackSlotsToCopy=0, pTargetAddress=140735228741672, dwDispatchCallSimpleFlags=1) at callhelpers.cpp:245:9 frame #16: 0x00007ffff7089e19 libcoreclr.so`DispatchManagedException(throwable=OBJECTREF @ 0x00007fffffffb528, pExceptionContext=0x00007fffffffb530) at exceptionhandling.cpp:5697:5 frame #17: 0x00007ffff708a784 libcoreclr.so`DispatchManagedException(throwable=OBJECTREF @ 0x00007fffffffc178) at exceptionhandling.cpp:5714:5 frame #18: 0x00007ffff6f3e68f libcoreclr.so`ThrowNew(oref=OBJECTREF @ 0x00007fffffffc370) at jithelpers.cpp:2994:5 frame #19: 0x00007ffff6f3e91c libcoreclr.so`IL_Throw(obj=0x00007fbf5e80a9e8) at jithelpers.cpp:3019:9 frame #20: 0x00007fff79111d4a frame #21: 0x00007ffff71e2a14 libcoreclr.so`CallDescrWorkerInternal at calldescrworkeramd64.S:70 frame #22: 0x00007ffff6e663d5 libcoreclr.so`CallDescrWorkerWithHandler(pCallDescrData=0x00007fffffffc7d8, fCriticalCall=NO) at callhelpers.cpp:63:5 frame #23: 0x00007ffff6e670cc libcoreclr.so`MethodDescCallSite::CallTargetWorker(this=0x00007fffffffc900, pArguments=0x00007fffffffc8a8, pReturnValue=0x0000000000000000, cbReturnValue=0) at callhelpers.cpp:585:9 frame #24: 0x00007ffff6bd3e53 libcoreclr.so`MethodDescCallSite::Call(this=0x00007fffffffc900, pArguments=0x00007fffffffc8a8) at callhelpers.h:465:9 frame #25: 0x00007ffff6bf5fdf libcoreclr.so`RunMainInternal(pParam=0x00007fffffffcb60) at assembly.cpp:1211:21 ``` .NET Stack trace: ``` (lldb) sos clrstack OS Thread Id: 0x23cd3 (1) Child SP IP Call Site 00007FFFFFFF8490 00007ffff78969fc [InlinedCallFrame: 00007fffffff8490] 00007FFFFFFF8490 00007fff77bc4e76 [InlinedCallFrame: 00007fffffff8490] 00007FFFFFFF8460 00007FFF77BC4E76 System.Runtime.ExceptionServices.InternalCalls.RhpSfiNext(System.Runtime.StackFrameIterator ByRef, UInt32*, Boolean*, Boolean*) 00007FFFFFFF8520 00007FFF77B9844B System.Runtime.EH.DispatchEx(System.Runtime.StackFrameIterator ByRef, ExInfo ByRef) 00007FFFFFFF8630 00007FFF77B97E5C System.Runtime.EH.RhThrowEx(System.Object, ExInfo ByRef) 00007FFFFFFFC3C8 00007ffff71e2a14 [HelperMethodFrame: 00007fffffffc3c8] 00007FFFFFFFC4D0 00007FFF79111D4A Program.
$(System.String[]) ```

It looks like that process is being aborted because the exception is being treated like an unhanded exception escaping from a reverse P/Invoke.

Looking at both code paths, I'm guessing this code might be responsible for the lack of message:

https://github.com/dotnet/runtime/blob/7ae87deb1250c978a207835e44cae6ca5f78680f/src/coreclr/vm/excep.cpp#L5023-L5028

It seems like it is intentional to print nothing on async exceptions?

For completeness, this also prints nothing when unhandled:

throw (Exception)Activator.CreateInstance(typeof(ThreadAbortException), nonPublic: true)!;

And this shows that runtime thrown exceptions also print nothing when unhandled:

Thread.CurrentThread.Interrupt();
Thread.Sleep(1);
KalleOlaviNiemitalo commented 4 weeks ago

Note that the "core dumped" message is only visible if the built executable is run directly, not if run with dotnet run.

That part may eventually be fixed as part of https://github.com/dotnet/sdk/issues/43250.