11

I have been reading about Reliability Features in .NET and have written the following class to explore ExecuteCodeWithGuaranteedCleanup

class Failing
{
    public void Fail()
    {
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
        }
        finally
        {
            RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(Code, Cleanup, "fail");
        }
    }

    private void Code(object message)
    {
        // Some code in here that will cause an exception...
    }

    private void Cleanup(object message, bool something)
    {
        Console.WriteLine(message);
        Console.ReadLine();
    }
}

I have experimented with a variety of code bodies for the Code method. These, and their runtime results are listed below

Causing an OutOfMemoryException - Cleanup does not get called

List<string> ss = new List<string>();

while (true)
{
    string s = new string('x', 1000000);

    ss.Add(s);
}

Causing a StackOverflowException - Cleanup does not get called

Code(message); // recursive call

Causing a ExecutionEngineException - Cleanup does not get called

Environment.FailFast(message.ToString());

Causing a ThreadAbortException - Cleanup does get called (however a regular try...finally can also catch this exception)

Thread.CurrentThread.Abort();

So the questions are

  • Am I using ExecuteCodeWithGuaranteedCleanup correctly?
  • When is ExecuteCodeWithGuaranteedCleanup actually useful?
Richard Ev
  • 52,939
  • 59
  • 191
  • 278

1 Answers1

5

Some exceptions are fatal to the process and execution of user-supplied code just does not continue. The purpose of ExecuteCodeWithGuaranteedCleanup method is to so you can put your data structures back in a consistent state. If the process is going to die anyways with no way to stop it, this has no purpose. The OS (assuming it is working properly) will clean up any kernel objects automatically for you when a process ends, regardless of the reason the process ends.

As Hans hints, the ICLRPolicyManager of the host comes into play to determine which exceptions are fatal in this way when code is run in a particular host (especially SQL Server). See the nice grid at the bottom of this documentation page: ICLRPolicyManager::SetActionOnFailure Method

Jason Kresowaty
  • 16,105
  • 9
  • 57
  • 84
  • Old answer, so documentation and behavior may have changed, I'm not sure, but [MSDN currently says](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.runtimehelpers.probeforsufficientstack?view=netframework-4.8) _"If you are calling a recursive method or plan to use a lot of stack space, you must use the RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup method."_. This suggests at least that a `StackOverflowException` can be prevented with that method. – Abel Dec 14 '19 at 00:22