Question

We have a service which will log unhandled exceptions at the app domain level (via Log4net).

We logged:

2014-01-28 16:49:19,636 ERROR [49] FeedWrapperService - unhandled System.NullReferenceException: Object reference not set to an instance of an object.

This exception has no stack trace. How is that possible without doing some crazy things to the exception object?

Our handling code:

AppDomain.CurrentDomain.UnhandledException += LogAnyExceptions;

private void LogAnyExceptions(object sender, UnhandledExceptionEventArgs e)
{
    log.Error("unhandled", (Exception)e.ExceptionObject);
    throw (Exception)e.ExceptionObject;
}

It occurs to me that the re-throw here is pointless because the AppDomain will come down along with the process anyway, but I don't think it affects our situation.

The windows application event viewer also shows only this null ref exception and no trace.

I've tested the exception handler logging and it successfully logs the stack trace and any inner exception. If it was thrown by our code, we would see a stack trace. If it was thrown by the 3rd party c# library then, again, we would see a stack trace of at least one method (whether it was a re-thrown exception or not). Here we see a managed exception with no stack trace. I don't know how this is possible.

Looking at the decompiled 3rd party library it talks to unmanaged code, and the event that raised this exception is likely in unmanaged land, but how could such a situation cause a managed null ref exception without a stacktrace?

The cause of this problem is intermittent. We've been running this code in production for several months and seen it do this once. It's pretty freaky.

The general consensus is that the system responsible for this kind of problem should be pushed off into a child process so we can deal with the problem and restart safely and automatically, but it would be nice to know what's going on.

Edit to include comment info from below:

My exception is not a standard re-throw, because the stack trace is either null or empty. It does not have the name of the re-throwing method in it. Digging further, the Exception class can be constructed from serialized info, and it looks like the serialized info could contain null strings for stack trace, and potentially that could be created without causing other errors. I guess it might come from there, but I don't know how it originated.

Was it helpful?

Solution 3

Since this has been open long enough, I'll take the only likely answer rather than leave it open forever :)

Namely:

The Exception class can be constructed from serialized info, and it looks like the serialized info could contain null strings for stack trace, and potentially that could be created without causing other errors. I guess it might come from there, but I don't know how it originated.

My only other thought was that perhaps the rest of the exception information could not be written to the log file before the app domain was torn down. But since the same was displayed in the Event Viewer and I assume that the whole event is created atomically, I think that's not how it happened.

OTHER TIPS

If you're receiving an exception but no corresponding stack trace then at some point an exception handler is probably evaluating the exception and re-throwing it incorrectly. For example, if you're doing a throw ex; you'll eat the stack trace that led to that point. To preserve the existing call stack you want to simply throw; Throwing exceptions best practices

Note that the C# way is the opposite of the convention for the Java language, where you are supposed to throw ex; Java reference: Best Practice: Catching and re-throwing Java Exceptions

I prefer to manage my exceptions with custom exceptions, If in your case you are using your own exceptions you can go the the class were you define them and override the stacktrace. e.g:

public class YourCustomException: Exception
{
    public YourCustomException() : base() { } //constructor

    public override string StackTrace 
    {
        get { return "Message instead stacktrace"; }
    }
}

Create common exception type like this:

/// <summary>
/// Special kind of exception, which is known and no need to report call stack on it's failure.
/// </summary>
class UIException: Exception
{
    public UIException(string message): base(message)
    { 
    }

    /// <summary>
    /// Don't display call stack as it's irrelevant
    /// </summary>
    public override string StackTrace
    {
        get {
            return "";
        }
    }
}

And then just throw new UIException("failure message");

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top