Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ExecuteCodeWithGuaranteedCleanup doesn't work?

Tags:

c#

I was trying to "measure" stack depth. Why the following program doesn't print anything?

class Program
{
    private static int Depth = 0;

    static void A(object o) 
    {
        Depth++;
        A(o);
    }

    static void B(object o, bool e)
    {
        Console.WriteLine(Depth);
    }

    static void Main(string[] args)
    {
        RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
    }
}

Some answers simply include a quote from MSDN, like "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." Believe me, sometimes (when there is enough stack space) it can be cought, the following prints some number just fine:

class Program
{
    private static int depth = 0;

    static void A(object o)
    {
        depth++;
        if (Environment.StackTrace.Length > 8000)
            throw new StackOverflowException("Catch me if you can.");
        A(o);
    }

    static void B(object o, bool e)
    {
        Console.WriteLine(depth);
    }

    static void Main(string[] args)
    {
        RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
    }
}
like image 365
Prankster Avatar asked Apr 14 '09 17:04

Prankster


4 Answers

Regarding your edit, I don't think user code throwing a StackOverflowException is the same as the CLR throwing it.

There's a bit of discussion about it here.

Jeffrey's (Richter, author of Applied Microsoft® .NET Framework Programming ) comment applies to real stack overflows, i.e. to stack overflows that occur if your code contains an infinite recursion, something like:

void MyMethod() { MyMethod(); }

If you throw the StackOverflowException yourself, it will be handled like any other exception, and Jeffrey's comment does not apply.

Also, Jeffrey's comment says: "if the stack overflow occurs WITHIN THE CLR ITSELF ...". So, if the .NET VM can detect the stack overflow "cleanly", i.e. without running ITSELF into a stack overflow, then you should get a StackOverflowException and your catch and finally blocks should execute as usual. But, in the tragic case where the VM ITSELF runs into a stack overflow, you won't be as lucky: the VM will not propagate a StackOverflowException (but crash in some other weird way) and your catch and finally blocks won't execute.

Morale is: be careful with infinite recursion because you don't have a 100% guarantee that the VM will detect and signal them cleanly!

Bruno.

Clarified who "Jeffrey" was since the OP was citing that book.

like image 174
Davy8 Avatar answered Nov 19 '22 18:11

Davy8


If you want to catch it, load it into another process (that calls-back to yours via remoting) and lets the miscreant code execute there. The other process may terminate, and you could get a neat SOE popping out the end of the pipe on your side - without the adverse effects of the rather inconvenient exception.

Note that a separate AppDomain in the same process won't cut it.

If you want to get the stack trace from an exception the following code will do you great justice:

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Recurse(0);
            }
            catch (Exception ex)
            {
                StackTrace st = new StackTrace(ex);
                // Go wild.
                Console.WriteLine(st.FrameCount);
            }
            Console.ReadLine();
        }

        static void Recurse(int counter)
        {
            if (counter >= 100)
                throw new Exception();
            Recurse(++counter);
        }
    }
like image 26
Jonathan C Dickinson Avatar answered Nov 19 '22 18:11

Jonathan C Dickinson


According to MSDN:

In prior versions of the .NET Framework, your application could catch a StackOverflowException object (for example, to recover from unbounded recursion). However, that practice is currently discouraged because significant additional code is required to reliably catch a stack overflow exception and continue program execution.

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. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. Note that an application that hosts the common language runtime (CLR) can specify that the CLR unload the application domain where the stack overflow exception occurs and let the corresponding process continue. For more information, see ICLRPolicyManager Interface and Hosting the Common Language Runtime.

Due to this fact I don't believe that you will be able to do what you want to do as the `StackOverflowException will terminate the process.

like image 41
Andrew Hare Avatar answered Nov 19 '22 18:11

Andrew Hare


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

like image 1
jyoung Avatar answered Nov 19 '22 18:11

jyoung