I am currently investigating some weird behaviour regarding stacktraces of Exceptions in release builds.
I understand that the common way of tracking exceptions is to register your own handler as a callback for the unity logger. However the stacktraces for exceptions that get passed to the handler sometimes are incomplete. If they are incomplete they will contain only the first method that was called, or if any call to Debug.Log was made from the current stack the stacktrace will include all calls up to that point. For example if I do this:
void Start ()
{
ThrowException();
}
void ThrowException()
{
Debug.Log("");
DoThrowException();
}
void DoThrowException()
{
throw new System.NullReferenceException();
}
Then the stacktrace will report that the exception was fired from ThrowException. If I remove the Debug.Log it will only contain the Start() method.
But it gets weirder. So for some exceptions i get the correct stacktrace, and for some I don't. For instance throwing an IndexOutOfRangeException does not produce the correct stacktrace, but if I actually try to access an array with an index bigger than its length the resulting runtime exception WILL have the correct stacktrace. NullReferenceExceptions never seem to have the correct stacktrace. This seems really weird to me. Is there any explanation for this? (i assume that unity is somehow tampering with some of the exceptions behind the scenes) If not, is there a better way of getting stacktraces for Exceptions in a release build?
If you want to try it yourself you can just use this script and (un)comment the various cases:
using UnityEngine;
using System.Collections;
public class SbsErrorTrackingTest : MonoBehaviour {
void HandleLog (string message, string stackTrace, LogType type)
{
Debug.LogException(null);
}
// Use this for initialization
void Start () {
Debug.Log("START");
ThrowException();
}
void ThrowException ()
{
DoThrowException();
}
void DoThrowException ()
{
// if this line is un-commented the stack trace is probably correct
// Debug.Log("");
// doesn't work
throw new System.NullReferenceException(message);
// doesn't work
throw new System.IndexOutOfRangeException("test");
// does work
string[] arr = { "" };
var s = arr[3];
// doesn't work
int x = 0;
int y = 1 / x;
// does work
System.Collections.Generic.Dictionary dict = new System.Collections.Generic.Dictionary();
var s = dict["key"];
// does not work
DummyClass dm = new DummyClass();
var s = dm.GetStringCopy();
}
}
public class DummyClass
{
string s = null;
public string GetStringCopy ()
{
return s.Clone() as string;
}
}
I tried this with release builds on Android and iOS.
↧