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

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.

Leave a Comment