An unhandled exception in a thread entering the CLR from unmanaged code does not trigger the "normal" unhandled exception CLR processing.
In the code below calling CSSimpleObject.GetstringLength()
from C++ with
In case "1"
In case "2" (expected behavior)
What has to be done to get the "normal" behavior?
The code below is based on the Visual Studio 2010 "CppHostCLR" code sample from the "all interop and fusion samples".
RuntimeHost (C++):
PCWSTR pszStaticMethodName = L"GetStringLength";
PCWSTR pszStringArg = L"1";
//PCWSTR pszStringArg = L"2";
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath,
pszClassName, pszStaticMethodName, pszStringArg, &dwLengthRet);
if (FAILED(hr))
{
wprintf(L"Failed to call GetStringLength w/hr 0x%08lx\n", hr);
goto Cleanup;
}
Managed Code (C#):
public class CSSimpleObject
{
public CSSimpleObject()
{
}
//------8<----------
public static int GetStringLength(string str)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
switch (str)
{
case "1":
throw new Exception("exception in non-CLR-created thread");
case "2":
Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
thread.Start();
break;
}
return str.Length;
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("CurrentDomain_UnhandledException:" + e.ToString());
Console.ReadKey();
}
public static void WorkThreadFunction()
{
throw new Exception(""exception in CLR-created thread"");
}
MSDN initially implies that unhandled exceptions in a non-CLR-created thread should behave more or less "naturally" - see "Exceptions in Managed Threads"
The common language runtime allows most unhandled exceptions in threads to proceed naturally. In most cases this means that the unhandled exception causes the application to terminate."
"Most" meaning that in CLR-created threads internal, thread abort and Application Domain unloaded exceptions are handled differently. In non-CLR threads
"they proceed normally, resulting in termination of the application."
Further research led me to "Unhandled Exception Processing In The CLR" where I found out the following:
"if the exception was not handled ... in the managed method, the exception would exit the CLR but continue to propagate up the stack as a native SEH exception (managed exceptions are represented as native SEH exceptions) ... The OS unhandled exception filter (UEF) mechanism may not always result in triggering the CLR's unhandled exception processing. Under normal circumstances, this will work as expected and the CLR's unhandled exception processing will be triggered. However, in certain instances this may not happen."
What is wrong with the code above or how can it be changed so that the CLR's unhandled exception processing is triggered?
I just found an old bug report, "UnhandledExceptionEventHandler is not called when managed code is called from unmanaged and throws an exception - http://tinyurl.com/44j6gvu", where Microsoft confirms this is a "buggy" behavior:
Thank you for taking the time to report this problem. The behavior is indeed a bug caused by the CLR execution engine and the CRT competing for the UnhandledExceptionFilter. The architecture of the CLR has been revised in the 4.0 version supporting this scenario.
Why is it important to get this right?
Note: changing the CLR behavior through SetActionOnFailure()
makes matters worse, in the sence, that it ends up masking the original exception (i.e. instead of an out of memory you endup seeing threadAborts - without a clue where the original error cam from)!
Exception, the CLR execution engine can raise exceptions, and unmanaged code can raise exceptions as well. Exceptions raised on a thread of execution follow the thread through native and managed code, across AppDomains, and, if not handled by the program, are treated as unhandled exceptions by the operating system.
A CLR Exception is a type of Exception made by . NET applications. The exception is encapsulated in a class derived from the System. Exception class. The Exception Code is 0xE0434352 (a.k.a. Error "CCR" in ASCII).
The reports in the Unhandled Exceptions are C# exceptions that your application is not catching in a try-catch block. These do not result in a crash (the application keeps running), but may result in unexpected behavior.
The update implies that you perhaps have a solution here. However, its solution won't work in all cases, so here is some more info.
If you prefer CLR Unhandled Exception behaviour, then make that the outer-most program and call native code only to perform specific functions. That will ensure that the CLR gets control of the unhandled exception filter.
If you want to retain your current structure and the C++ code you have is small, you could stop using the CRT at all (which will deny you a bunch of useful stuff including static constructors and C++ exception handling). That will ensure that the CLR gets the Unhandled Exception Filter.
And, of course, you could simply call SetUnhandledExceptionFilter youself and get the behaviour you want.
However, I think the best recommendation in this situation is to put an actual function with a catch block on the call stack of any thread where you want to do something when an exception happens and not rely on the UEF mechanism -- because in the context of a component system, it is always fragile as multiple users compete for it.
Martyn
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