Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a StackOverflowException in a child AppDomain terminate the parent AppDomain?

I was under the impression that AppDomains are isolated from each other. It seems that in the case of a StackOverException, this isn't the case.

To demonstrate the issue, I created a simple console application whose only purpose is to spawn a new AppDomain, into which I load a very simple assembly and call one of its methods. This method happens to throw a StackOverflowException. This causes my console application to terminate unceremoniously.

My desired behavior is for the "child" AppDomain to crash and burn on such an exception, but leave my console application, running in the "parent" AppDomain, unscathed.

Is this possible?

UPDATE: here is some code. Neither of the exception handlers are hit.

    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            // create app domain
            var domain = AppDomain.CreateDomain("MyDomain");

            // create a component
            var component = (MyComponent)domain.CreateInstanceAndUnwrap(
                "AppDomainMonitor.Component", 
                typeof(MyComponent).FullName);

            // create a thread from a method on this component
            var thread = new Thread(component.CauseStackOverflow);

            // start the thread
            thread.Start();

            Console.ReadKey();
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // never hit
        }
    }

    public class MyComponent : MarshalByRefObject
    {
        public void CauseStackOverflow()
        {
            try
            {
                Infinite();
            }
            catch (Exception ex)
            {
                // never hit
            }
        }


        void Infinite()
        {
            Infinite();
        }
    }
like image 491
Mike Chamberlain Avatar asked Feb 22 '11 12:02

Mike Chamberlain


People also ask

What causes StackOverflowException?

A StackOverflowException is thrown when the execution stack overflows because it contains too many nested method calls. using System; namespace temp { class Program { static void Main(string[] args) { Main(args); // Oops, this recursion won't stop. } } }

Can you catch a StackOverflowException?

NET Framework 2.0, you can't catch a StackOverflowException object with a try / catch block, and the corresponding process is terminated by default. Consequently, you should write your code to detect and prevent a stack overflow.


2 Answers

Only the managed memory is isolated between AppDomains. If a thread throws an exception in any AppDomain, this will cause the whole application to crash.

I think the best solution is to ensure that all exceptions are properly handled on every thread (or thread pool work items).

There is however a hack which consist of applying this configuration in the App.Config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

Unhandled exceptions are crashing the process since .Net 2.0, but you can revert to the old policy using this trick.

I would use this cautiously tough as it's often best to let processes crash instead of failing silently. You can add traces in AppDomain.UnhandledException to be notified when unhandled exception occurs and handle them appropriately.

EDIT

You are right about StackOveflowException, since .Net 2.0 this exception cannot be handled by user code. (See the Remarks section of this page in msdn).

There is a way to override this by creating a custom CLR host, but this seems like a crazy thing to do. I guess you'll have to live with it or you can create child process instead of AppDomain if you really need this kind of fault tolerance.

like image 176
Jeff Cyr Avatar answered Sep 21 '22 01:09

Jeff Cyr


I suppose the problem is that you call method causing an exception from within your main AppDomain, that is you call some method in main AppDomain, this method calls problem method from child AppDomain. Exception rises in child AppDomain, but it is propagated up the call stack to your calling AppDomain (main AppDomain). Try to call this method from child AppDomain entirely. For example, spawn a thread in child AppDomain, so that this thread should call problem method.

like image 21
Dmitrii Lobanov Avatar answered Sep 25 '22 01:09

Dmitrii Lobanov