How to crash on unhandled Task exception? - c#

I'd like to properly understand the consequences of failing to observe an exception thrown on a Task used in a fire and forget manner without exception handling.
Here's an extract from CLR via C#, Third Edition by Jeffry Richter: "[...] when a Task object is garbage collected, its Finalize method checks to see if the Task experienced an unobserved exception; if it has, Task's Finalize method throws [an exception]. Since you cannot catch an exception thrown by the CLR's finalizer thread, your process is terminated immediately."
I am writing some test code to bring about a termination but am unable to cause one.
Using the test code here, I am able to see the TaskScheduler.UnobservedTaskException handler being called. However, if I comment out the event handler subscription, the exception appears to be swallowed and does not bring about termination of the program.
I've tried this using the .NET Framework on both versions 4 and 4.8 with a Release build.
How do I demonstrate that failing to observe an exception thrown on a Task does indeed cause a crash?

The problem is correctly identified by Jon Skeet in his comment to the original post.
The best resource I found concerning this topic is by Stephen Toub.
tldr:
"To make it easier for developers to write asynchronous code based on Tasks, .NET 4.5 changes the default exception behavior for unobserved exceptions. While unobserved exceptions will still cause the UnobservedTaskException event to be raised (not doing so would be a breaking change), the process will not crash by default. Rather, the exception will end up getting eaten after the event is raised, regardless of whether an event handler observes the exception. This behavior can be configured, though. A new CLR configuration flag may be used to revert back to the crashing behavior of .NET 4, e.g."
<configuration>
<runtime>
<ThrowUnobservedTaskExceptions enabled=”true”/>
</runtime>
</configuration>

Related

Unobserved task exception handling with TopShelf

I am using TopShelf framework which is just working great.
However I am having great trouble figuring out how to register a top level exception filter for unobserved task exceptions (i.e subscribing to TaskScheduler.UnobservedTaskException).
I tried different places to register to this event, but no matter what, I never get the notification when I throw exceptions from non awaited tasks.
How can I correctly get these notifications when using TopShelf.
Thanks.
My bad,
It had nothing related to TopShelf but to the behavior of TaskScheduler.UnobservedTaskException which must wait for the exception throwing task to be garbage collected before getting the exception :(

Exceptions that can't be caught by try-catch block in application code

MSDN states that StackOverflowException can't be caught by try-catch block starting with .NET Framework 2.
Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default.
Are there any other exceptions with the same behavior?
Yes, there are some others:
The ThreadAbortedException is special. It will always be re-raised when caught unless the catch block calls ResetAbort(). It is entirely uncatchable when the CLR performs a rude abort of the thread. Done when the AppDomain gets unloaded for example, typically at program exit.
Any native exceptions thrown by unmanaged code in a thread that got started by native code are uncatchable. The common scenario here is COM components that start their own threads. The CLR is powerless to trap such exceptions, it doesn't know about the thread and can't inject a catch block. If the native code doesn't catch the exception then Windows terminates the process.
Any exceptions thrown by finalizers, unless they are critical finalizers. They'll abort the finalizer thread which terminates the process.
Starting with .NET 4.0, an ExecutionEngineException is uncatchable. It is thrown by the CLR when it detects that its internal data structures are compromised. Most typically by an AccessViolationException that's raised while the garbage collector is busy. Continuing to execute managed code when the GC heap is compromised is a risky proposition, and exploitable, .NET 4 pulled the plug on it entirely.
Starting with the .NET 4.0 version of the CLR, but possibly also present in unmanaged code that you interop with in earlier versions, Microsoft's secure CRT can terminate a program instantly when a security problem is detected. This is not actually an exception under the hood, the process is instantly terminated since the code considers the process compromised and not capable of safely processing exceptions. A common case is where the stack frame of native function is smashed, a common problem in native code and used by viral code to tinker with the return address to run arbitrary code. An attack scenario called "stack buffer overflow". There were a few false alarms in CLR code, early after the .NET 4.0 release but I haven't seen any in quite a while. You can trigger such an abort yourself by writing beyond the bounds of a stackalloc.
Quite infamously, exceptions thrown by Windows message handlers when you run code in 32-bit mode in the WOW64 emulation layer on a 64-bit operating system and you have a debugger attached. Best known for the troublesome Load event in Winforms but also present for other messages and in other runtime environments. The ugly details are in this answer.
Starting with .NET 4.5, exceptions that Microsoft classifies as Corrupted State Exceptions (CSEs). They can be caught, but that should only ever be done by a top-level exception handler that doesn't do anything but generate a diagnostic for the user's benefit and terminates the app unconditionally. Backgrounder is available in this magazine article.
Any exception that is thrown by the jitter before your code can start running cannot be caught or reported. Failure to compile your Main() method is the common case, typically a FileNotFoundException.

Abort current process from async task

I have some complex functions that run in an async Task spawned via the TPL, which could occasionally fail in unexpected ways. When such a failure occurs, this indicates a programming error which could have resulted in corrupted program state. Therefore, I don't want my program to catch the exception, handle it and "limp on", I want my process to crash and terminate.
I also want the thing to die in such a way that the Windows Error Reporting system detects it as a crash, and does all the useful debugging things like catching a minidump, sending it to Microsoft, etc.
I realise this may run counter to your opinions of what programs should do in error conditions, but the question is not about that.
The problem I have is, because the exception is raised from a task, it doesn't immediately cause the process to crash. It crashes some time later when the garbage collector, in its wisdom, decides to collect the "unobserved" exception.
I want the process to crash immediately, because...
The call stack and thread dump from the actual error is what I want to collect in the crash dump
The process "limping on" and crashing some indeterminate time later could cause further damage, as it will be working on a possibly corrupt program state
Users get confused about what operation actually caused the crash to occur
So, in short, the question is:
How can I cause my process to crash from an async Task, created with the TPL, such that Windows Error Reporting is able to create a useful minidump?
Thanks in advance!
You could try this, or something similar:
public static Task FailFastOnException(this Task task)
{
task.ContinueWith(c => Environment.FailFast(“Task faulted”, c.Exception),
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.DetachedFromParent);
return task;
}
and then:
var t = Task.Factory.StartNew(…).FailFastOnException();
We've just used it a lot with "fire and forget" tasks that we want to take down the process if they for some reason fail.
Taken from a blog post written by Stephen Toub:
http://blogs.msdn.com/b/pfxteam/archive/2009/05/31/9674669.aspx
Take a look at ThrowUnobservedTaskExceptions (app.config setting):
<configuration>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
</configuration>
If an exception that is associated with a Task has not been observed,
there is no Wait operation, the parent is not attached, and the
System.Threading.Tasks.Task.Exception property was not read the task
exception is considered to be unobserved.
In the .NET Framework 4, by
default, if a Task that has an unobserved exception is garbage
collected, the finalizer throws an exception and terminates the
process. The termination of the process is determined by the timing of
garbage collection and finalization.
To make it easier for developers
to write asynchronous code based on tasks, the .NET Framework 4.5
changes this default behavior for unobserved exceptions. Unobserved
exceptions still cause the UnobservedTaskException event to be raised,
but by default, the process does not terminate. Instead, the exception
is ignored after the event is raised, regardless of whether an event
handler observes the exception.
In the .NET Framework 4.5, you can use
the element in an application
configuration file to enable the .NET Framework 4 behavior of throwing
an exception.
You can also specify the exception behavior in one of
the following ways:
By setting the environment variable
COMPlus_ThrowUnobservedTaskExceptions (set
COMPlus_ThrowUnobservedTaskExceptions=1).
By setting the registry
DWORD value ThrowUnobservedTaskExceptions = 1 in the
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework key.

How does ASP.NET handle unhandled exceptions?

When writing for ASP.NET and, while the debugger is attached, if you visit a web page that throws an exception, the unhandled exception helper is launched at the line of code that caused the exception.
This occurs even if you only are catching unhandled exceptions and are not catching thrown exceptions. However, hitting F5, ignoring the exception, or not having the debugger attached does not cause the AppDomain to be torn down. Instead somehow ASP.NET handles the unhandled exception anyway.
How does this work, and can exception handling like this be implemented elsewhere so that other unhandled exceptions can be swallowed rather than kill the whole AppDomain or process?
Edit: To clarify, I understand how exception handling and try...catch blocks work. However, in this case it seems that the debugger is considering the exception unhandled while at the same time ASP.NET is wrapping the exception in a try...catch. That is the behavior I want to emulate.
How does this work,
asp.net just wraps executing code in whatever exception-handling code they want. asp.net webpage (or view, or controller) is just a class, and how to use it is entirely up to host (in our case, asp.net).
why does VS debugger break on it if it's handled?
There's a quote from MSDN documentation:
ASP.NET has a top-level exception handler that handles exceptions to show error pages to browser users. That top-level exception handler will stop an unhandled exception from breaking into the debugger unless Just My Code is turned on. Make sure that you enable Just My Code for ASP.NET debugging.
Which means that if you have "Just my code" enabled in VS Debug options (and it's enabled by default) you'll break at exceptions that are unhandled in your own code, irregardless of whether they are handled in your caller or not.
can exception handling like this be implemented elsewhere so that other unhandled exceptions can be swallowed rather than kill the whole AppDomain or process?
You can't do that, it is a security measure.
Your webpage is just a bunch of method calls from IIS & the ASP.NET Runtime, you're webpage isn't running alone in your appdomain. The code calling into your code has an ordinary try/catch block around that method call.
You could create a similar setup yourself:
For a ConsoleApplication, by placing a try/catch block around eveything in Main, meaning that you'l catch any exceptions that aren't handled elsewhere in your app.
For a Windows Forms application, by handling the Application.ThreadException event (Which allows you to hook into Windows Forms' message loop's try/catch block)
For a WPF appliaction, by handling the Application.DispatcherUnhandledException event (Which allows you to hook into WPF's message loop's try/catch block)
... or maybe you could use the AppDomain.UnhandledException event
The problem with these kinds of programs then would be: Where in the app should you continue?
The last question is solved easily in ASP.NET, since every page call is isolated from each other. The user just continues by navigating to a page again.

CLR exits when a thread gets unhandled exception

I have background threads in my application. When one of the threads gets an exception that is not handled the entire CLR exits.
Is it normal behavior, or is it a bug in the CLR?
I would expect that the thread will exit but the CLR will continue working.
The default behavior in .NET applications is to exit whenever an unhandled exception occurs. When an exception goes unhandled, the program is in an unknown and possibly unsteady state. Just because it happened in a background thread doesn't mean that the error won't affect the rest of the program. The most prudent course for the runtime in that situation is to dump the program.
You might look into AppDomain.CurrentDomain.UnhandledException, which will allow you to catch unhandled exceptions and react accordingly. A better solution is to wrap your thread proc with a try...catch. But only have it handle those exceptions it knows how to handle. Doing this:
void MyThreadProc()
{
try
{
// ...
}
catch
{
// handle all exceptions
// This is a BAD idea
}
}
Is a really bad idea, because it can mask exceptions that you really do want to be propagated to the main program.
Your expected behavior used to be the behavior back in 1.1. It was generally considered to have been a bad idea. When you have an unhandled exception in any thread, your process can be left in an inconsistent state. Updates to shared data may be partially applied, etc. The runtime doesn't have the information to safely handle this scenario, or even know how you want to handle this scenario, so its choice would amount to terminating the thread and leaving your program in a strange state. This could lead to resource leaks, hangs, corruption of data, etc. By terminating the process given an unhandled exception you know exactly what happens, the process ends.
This is a normal behavior of the CLR from v2.0. Here is a MSDN post on this. To avoid process from terminating you could use something like this
<legacyUnhandledExceptionPolicy enabled="1"/>
which is not advisable.
It is normal behavior. Perhaps you want to catch the exception to prevent the application from exiting.

Categories

Resources