.Net Core: Finally Block Not Called on Unhandled Exception on Linux

.NET Core: Finally block not called on unhandled exception on Linux

Official response is that this is an expected behavior.

Interestingly enough, the C# doc page on try-finally explicitly calls this out right at the top (emphasis mine)

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up. For more information, see Unhandled Exception Processing in the CLR.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

One thing I found in my experimentation is that it doesn't appear to be enough to catch the exception, you have to handle it as well. If execution leaves the catch block via a throw, the finally will not run.

Why isn't the finally getting executed?

When you get the "ConsoleApplication1" has stopped responding, you have two choices.

Windows Error Reporting dialog

If you press cancel, the unhandled exception is allowed to continue until eventually the application is terminated. This allows the finally block to execute. If you do not press cancel then Windows Error Reporting halts the process, collects a minidump and then terminates the application. This means the finally block is not executed.

Alternatively, if you handle the exception in a higher method you will definitely see the finally block. For example:

static void unhandled()
{
try
{
throw new Exception();
}
finally
{
Console.WriteLine("finally");
}
}

static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
try
{
unhandled();
}
catch ( Exception )
{
// squash it
}
}

Always gives the output "finally"

Using statement doesn't work correctly

The problem might be that you are running the code in the debugger. That means that whatever code comes after an unhandled exception wont be executed becuase the debugger will halt at that point.

If you run a test scenario out of the debugger then the Dispose() method will be called when the runtime cleans up the mess. Put some code "marker" in the Dispose() method that will give you a visible sign that Dipose is called: for example create a file in some accessible folder namesd DisposedHasRun.yeah (note that outputting to the Console or a MessageBox is not an option because the application is quitting due to an unhandled exception). When you run the test case outside the debugger you'll see that the file has been created.

That said, there are ocassions where Dispose wont be called (nor finally blocks). For example an StackOverflow exception due to an infinite recursion will not call Dispose() as the runtime will make the application bail out asap. (ThreadAbortException I think will behave the same)

What is the purpose of finally in try/catch/finally

In your example, it doesn't make a whole lot of difference.

Picture this, though:

    try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}
catch (SomeOtherException e)
{
Console.WriteLine("{0} Caught exception #1.", e);
}
finally
{
Console.WriteLine("Executing finally block.");
}

Console.WriteLine("Executing stuff after try/catch/finally.");

In this case, the catch won't catch the error, so anything after the whole try/catch/finally will never be reached. However, the finally block will still run.

.NET Global exception handler in console application

No, that's the correct way to do it. This worked exactly as it should, something you can work from perhaps:

using System;

class Program {
static void Main(string[] args) {
System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
throw new Exception("Kaboom");
}

static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) {
Console.WriteLine(e.ExceptionObject.ToString());
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
Environment.Exit(1);
}
}

Do keep in mind that you cannot catch type and file load exceptions generated by the jitter this way. They happen before your Main() method starts running. Catching those requires delaying the jitter, move the risky code into another method and apply the [MethodImpl(MethodImplOptions.NoInlining)] attribute to it.

Exception handling Try Catch block

What I was wondering is does execution continue in the method that caused the error or does execution continue in the method that handles the error.

Second one is correct.For example in your B method if there is exception thrown and not handled,it goes to the caller method for example A,and if A handles that exception program will continue execution from that method.Consider this example:

private static void Main(string[] args)
{
A();
}

static void A()
{
try
{
B();
}
catch (Exception ex)
{
Console.WriteLine("Exception is thrown by {0} method and handled in A method.",ex.TargetSite);
}

Console.WriteLine("We are still in A method...");

}

static void B()
{
throw new Exception();
Console.WriteLine("We can't see this...");
}

This will produce the output:

// Exception is thrown by B() method and handled in A method.
// We are still in A method...


Related Topics



Leave a reply



Submit