51

Basically I’ve heard that certain conditions will cause .NET to blow past the finally block. Does anyone know what those conditions are?

Quirin F. Schroll
  • 1,302
  • 1
  • 11
  • 25
NotMe
  • 87,343
  • 27
  • 171
  • 245

7 Answers7

55

Two possibilities:

The finally block will not be executed when there's a StackOverflowException since there's no room on the stack to even execute any more code. It will also not be called when there's an ExecutionEngineException, which may arise from a call to Environment.FailFast().

Gabriel
  • 1,443
  • 15
  • 24
Haacked
  • 58,045
  • 14
  • 90
  • 114
  • 4
    Perhaps worth noting that ExecutingEngineException may arise from a call to Environment.FailFast() – Daniel Fortunov Jan 11 '10 at 11:55
  • 3
    B.T.W. I think it should be ExecutionEngineException instead of ExecutingEngineException? – Wiebe Tijsma Feb 09 '12 at 13:57
  • I am getting a __COM Context for this RuntimeCallableWraper failed__ error similar as described in https://stackoverflow.com/questions/36768352/transition-into-com-context-for-this-runtimecallablewrapper-failed-error-in-pa only I am using LINQ to SQL
    This doesn't seems to be an exception in the usual manner and doesn't execute the __finally__ block we have in place.
    Has anyone seen this error before and can confirm if it does not execute the __finally__ block?
    – Luke T O'Brien Sep 30 '17 at 09:31
  • Seems so the same goes for [InvalidProgramException](https://learn.microsoft.com/en-us/dotnet/api/system.invalidprogramexception?view=net-5.0). – Yarl Jun 18 '21 at 09:26
15

Unless the CLR blows up and goes down with an ExecutingEngineException (I've seen a few in the .net 1.1 days with just the right amount of COM Interop :) .. I think finally should always execute.

Gishu
  • 134,492
  • 47
  • 225
  • 308
7

You can get a situation where the code in the try block causes a SecurityException to be thrown before the try block entered (instead the exception is thrown when the containing method is called (see http://msdn.microsoft.com/en-us/library/fk6t46tz(VS.71).aspx)), in this situation you never even enter the try block so the code in the finally block is never called.

Other possibilities include StackOverflowException, and ExecutingEngineException.

Chris
  • 567
  • 3
  • 14
4

Finally block on background thread may not execute. However, It depends upon the completed execution of main foreground thread which terminates background thread operation even before the complete execution of background thread.

class Program
{

    static void Main(string[] args)
    {
        Program prgm = new Program();
        Thread backgroundThread = new Thread(prgm.CheckBgThread);
        backgroundThread.IsBackground = true;
        backgroundThread.Start();
        Console.WriteLine("Closing the program....");
    }

    void CheckBgThread()
    {
        try
        {
            Console.WriteLine("Doing some work...");
            Thread.Sleep(500);
        }
        finally
        {
            Console.WriteLine("This should be always executed");
        }
    }
}
Koen
  • 2,501
  • 1
  • 32
  • 43
Navneet
  • 61
  • 7
2

There is also Application.Exit method.

  • 3
    You mean `Environment.Exit`. `Application.Exit` allows the main routine to continue, so I'm sure `Finally` blocks are executed. – Mark Hurd Feb 15 '12 at 13:37
1

Since async/await, there is another way a finally might get ignored that I haven't seen mentioned in other answers:

static class Program
{
    [STAThread]
    static void Main()
    {
        async void ThreadExecutionAsync()
        {
            try
            {
                SynchronizationContext.SetSynchronizationContext(
                    new WindowsFormsSynchronizationContext());

                await Task.Yield(); // Yield to the context

                // The WindowsFormsSynchronizationContext will schedule the continuation
                // on the main thread, so the current thread will die
                // and we will never get here...
                Debugger.Break();
            }
            finally
            {
                // Will never get here either...
                Debugger.Break();
            }
        }

        var thread = new Thread(ThreadExecutionAsync);
        thread.Start();

        Application.Run();
    }
}
Melvyn
  • 622
  • 10
  • 11
  • Isn’t this almost like saying: “If you have an infinite loop in the `try` part, execution won’t reach the `finally` block”? The answer is a little vague phrasing it as “blow past” the `finally` block, but if the execution won’t reach the end of the `try` block, it certainly does not count. – Quirin F. Schroll Jul 15 '22 at 15:04
  • @Bolpat I don't understand why you would compare this with an infinite loop. This program looks fine and would run as expected if not for this specific synchronization context. The execution flow is silently "broken" by the async continuation back to the main thread. – Melvyn Jul 18 '22 at 18:12
  • Then, I didn’t really get why it’s broken. I thought the execution simply will not reach the end of the `try` block. – Quirin F. Schroll Jul 19 '22 at 08:38
  • Indeed it won't reach the end of the try block for the same reason it won't reach the finally. But I would expect a finally block to always be executed when the execution flow exits its try block, regardless of any early return. It's not the case here. – Melvyn Jul 19 '22 at 08:55
0

Neither code which follows a finally block, nor code in outer scopes, will execute without the finally block having been started first (an exception within the finally block may cause it to exit prematurely, in which case execution will jump out from the finalizer to an outer scope). If code prior to the finally block gets stuck in an endless loop or a method that never exits, or if the execution context is destroyed altogether, the finally block will not execute.

Note that it is proper to rely upon finally blocks, unlike "Finalize" methods (or C# "destructors") which should not properly be relied upon.

supercat
  • 77,689
  • 9
  • 166
  • 211