问题
I have a .NET application (service) that consists of C# and C++ code.
"Crashes" (i.e. System.AccessViolationException
and other Corrupted State Exceptions) in the C++ Code will be ("non-") handled correctly, they will directly lead to my AppDomain.CurrentDomain.UnhandledException
handler (which logs) and then the application will terminate, writing a WER dump file if so configured (which it is).
For this application, I have determined that System.NullReferenceException
is always a bug, especially since some C++/CLI Access Violation bugs will report this one instead of an AV.
Is there any way to make .NET not catch a NullReferenceException
on an exception boundary (my OnTimer
callback in this case) but instead directly terminate the app, without unwinding the stack, basically "jumping" directly to AppDomain.CurrentDomain.UnhandledException
?
回答1:
You could:
AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
and then
static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
if (e.Exception is NullReferenceException)
{
Environment.FailFast("FailFast", e.Exception);
}
}
The Environment.FailFast:
Immediately terminates a process after writing a message to the Windows Application event log, and then includes the message in error reporting to Microsoft.
and
This method terminates a process without running any active try/finally blocks or finalizers.
Clearly in the CurrentDomain_FirstChanceException
you could duplicate the logging code you probably have in your UnhandledException
(or have a common method that is called by both)
回答2:
The fact that FirstChanceException
is actually a "simple" global exception filter got me on the track (it remains to be seen whether it's the "right" track):
We already have exception filters in CLI.
If one has the luxury of working in C# 6, it's as simple as:
try
{
throw new NullReferenceException("No, Really");
}
catch(Exception ex) when (FilterExType(ex))
{
Console.WriteLine($"2: Caught 'any' exception: {ex}");
}
static bool FilterExType(Exception ex)
{
if (ex is NullReferenceException)
{
Environment.FailFast("BOOM from C#!", ex);
}
// always handle if we return
return true;
}
And for those of us (like me) stuck on earlier versions, we can route the filtering through VB.NET via a delegate / lambda:
try {
VbFilterLib.FilteredRunner.RunFiltered(() =>
{
throw new NullReferenceException("Via VB.NET");
});
}
catch (Exception ex)
{
Console.WriteLine("1: Caught 'any' exception: {0}", ex");
}
with VB as such (bear with me, VB.NET is far from a language I'm fluent in):
Public Class FilteredRunner
Delegate Sub VoidCode()
Private Shared Function FilterAction(x As Exception) As Boolean
If TypeOf x Is NullReferenceException Then
Environment.FailFast("Abort program! Investigate Bug via crash dump!", x)
End If
' Never handle here:'
Return False
End Function
Public Shared Sub RunFiltered(code As VoidCode)
Try
code.Invoke()
Catch ex As Exception When FilterAction(ex)
Throw New InvalidProgramException("Unreachable!", ex)
End Try
End Sub
End Class
Obviously, to make it work you need some more configuration rigging, but that seems to be exactly what I want. :-)
来源:https://stackoverflow.com/questions/35503673/how-to-terminate-net-application-on-a-specific-exception-possibly-without-sta