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();
}
}
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. } } }
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With