In C# I'm trying to modify the StackTrace property of a custom exception I created. For this, I just override the StackTrace getter and it seems to be working (Exception has it as a virtual method, so it should work). This is my custom exception:
class CustomTimeoutException : Exception
{
private string oldStack;
public CustomTimeoutException(string message, String stack)
: base(message)
{
oldStack = stack;
}
public override string StackTrace
{
get
{
return oldStack;
}
}
public override string Message
{
get
{
return "lalalala2";
}
}
public override System.Collections.IDictionary Data
{
get
{
return null;
}
}
}
I'm using this class the following way:
class Program
{
static void Main(string[] args)
{
try
{
Program p = new Program();
p.throwTimeout2();
}
catch(TimeoutException e)
{
CustomTimeoutException tor = new CustomTimeoutException(e.Message + "with more", e.StackTrace);
Console.WriteLine(tor);
Console.WriteLine(tor.StackTrace);
throw tor;
}
}
public void throwTimeout2()
{
throwTimeout();
}
public void throwTimeout()
{
throw new TimeoutException("this is a message ");
}
}
When I write the property StackTrace to the console, it prints the StackTrace of the TimeoutException, which means it's in fact overriding it. But, when the console shows the error, the StackTrace is not the one it gets from my property, yet the Message is the one it gets from the Message property I'm also overriding.
So, where does the console get the StackTrace of the exception from? I'm using Visual Studio for running.
(Note: one thing I still really don't understand about your question is that, while you seem to be asking for a way to affect how an exception is reported to the console, you also say that you have some "tool" that apparently has access to the Exception object itself and is reporting on the inner-most exception, i.e. following the InnerException property chain until it reaches the last one. These two statements seem to be in contradiction with each other, so I'm not really sure I completely understand the question. Still, I spent some time looking into it, and will share what I have regardless. :) .)
IMHO, there is not a good way to do what you want. There is an ugly way (see below), but I don't recommend it. Especially since your main limitation is the "tool that uses the message"; it is IMHO a very bad idea to go changing production code just to suit some tool. That path leads to big maintenance headaches, if not outright buggy code.
If you really must change the exception message, you should just bite the bullet and toss the entire stack trace text you want to preserve into the message as well. Trying to mess around with the stack trace of the eventually-thrown exception itself is bad news.
That said…
If you were to add diagnostic calls to Console.WriteLine() to your method overrides, you would confirm (as you've probably already guessed) that the StackTrace property is not called when the exception is re-thrown and reported by the CLR to the console. Overriding the property is not going to help.
There are at least two problems with trying that strategy:
The StackTrace property is just a string containing formatted information about the stack trace. The Exception object does actually contain a private field _stackTrace. When you execute the throw statement with an Exception object, the CLR stores the current stack trace information into this field. You would have to find some way to overwrite this field after the fact, to fake a throw site different from the actual one.
The CLR exception handling leverages existing Windows exception handling infrastructure. One of the first things that happens when an exception is thrown is the exception handling code attempts to find a handler up the stack. If it fails to find one, then you get the "Unhandled Exception:" message. But note that in the process, the stack has not been unwound. Thus, the exception handling code does not even need to inspect the Exception object at all to determine the throw site; the stack is still there, and its state can be reported directly. There is literally nothing you can do with the Exception object that would affect reporting, if indeed the exception handling code is looking directly at the stack state.
Now, as it happens, for the version of .NET I'm running on my Windows 8.1 machine, it appears that the CLR is reporting the stack trace as stored in the Exception object and not directly inspecting the stack, per option #2 above. So something like this actually works:
ExceptionWrapper class
class ExceptionWrapper : Exception
{
private readonly string _trace;
private readonly string _message;
private readonly string _toString;
private readonly object _stackTrace;
public ExceptionWrapper(Exception e)
{
_trace = e.StackTrace;
_message = e.Message + ", wrapped";
_toString = e.ToString();
_stackTrace = typeof(Exception).GetField("_stackTrace",
BindingFlags.NonPublic | BindingFlags.Instance).GetValue(e);
}
public override string StackTrace { get { return _trace; } }
public override string Message
{
get
{
typeof(Exception)
.GetField("_stackTrace", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(this, _stackTrace);
return _message;
}
}
public override string ToString() { return _toString; }
}
Test program
class Program
{
static void Main(string[] args)
{
try
{
M1();
}
catch (Exception e)
{
throw;
}
}
private static void M1()
{
try
{
M();
}
catch (Exception e)
{
throw new ExceptionWrapper(e);
}
}
static void M()
{
throw new Exception("test exception");
}
}
There is a very significant caveat though. This works only because of two specific facts:
The CLR is not taking advantage of the current stack state, but instead is trusting the Exception object to contain correct stack information in the _stackTrace field.
The CLR calls the Message getter of the Exception object before retrieving the stack trace. This gives the object an opportunity to overwrite the _stackTrace field before the CLR accesses it for the purpose of reporting the stack trace.
Both of these are, as near as I can tell, completely undocumented implementation details. The second one in particular is very fragile; while I can see why the CLR might always have to stick with the first detail, I see no reason at all that Microsoft (never mind other implementors of the CLS) should feel compelled to preserve the behavior in the second point.
Writing code that relies on these implementation details is just asking for trouble. Whatever the broader goal here is, I simply cannot imagine it would be worthwhile to suffer the risk of breaking your project for this need. IMHO, it would be much more reasonable to simply rewrite this "tool" you are trying to accommodate.
Tools are (or at least should be) inherently simple in nature, and not only would rewriting it allow you to produce the results you want without mucking around with private implementation details in third-party code, it would also give you the chance to a) add new features, such as providing options for controlling how to process exception data (e.g. looking at something other than the inner-most exception), and b) have a tool for which you do have the source code, with which you can make further improvements in the future.
I strongly advise that you not paint yourself into this particular corner. :)
Related
The exception from a static constructor is wrapped in a TypeInitializationException. Consider the example below
using System;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
try
{
new MyClass();
}
catch (Exception e)
{
Console.WriteLine(e.GetType().ToString());
}
}
public class MyClass
{
static MyClass()
{
throw new Exception();
}
}
}
}
The output of the program is
System.TypeInitializationException
What are the reasons for wrapping the exception in a TypeInitializationException ?
Why is the original exception not returned ?
What are the reasons for wrapping the exception in a TypeInitializationException ?
Exceptions in static constructors are difficult. Basic issue is that the execution context of the exception is very vague. The CLI does not give any specific promise exactly when the constructor runs. Only guarantee is that it will run soon enough, how soon is unspecified.
So a dooms-day scenario without the exception being wrapped is that you get a vague bug report from a user like "I get a NullReferenceException when I click the Save button". You'll study your SaveButton_Click() event handler but no matter how hard you look, you'll never find a good reason for that exception. It occurred in code that's far removed from the event handler method, code that ran at an unpredictable time.
By wrapping it in TypeInitializationException, you'll know where to look.
Why is the original exception not returned ?
It is returned, it will be the InnerException of the TIE. Forgetting to look at it is a standard oversight. If you ever write try/catch code then never make the mistake of only displaying Message property of the exception you caught. The InnerException is important too. Strongly favor displaying the string generated by the exception object's ToString() method. It is gobbledegooky to the user but essential to you. Avoid the gobble with logging or hiding details that can be revealed with "Details" button in the error dialog.
Static constructors are called on initialization, so although it's your static constructor that's failing, it's the type initalizer that's calling that, so that's the exception you get: https://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx
Let's say that I have a class in my dll file:
public ClassInDllFile()
{
String str = "";
try
{
str = someClassMethod();
}
catch (Exception e) // or more precised exception type
{
// some code
}
}
I don't want to put exception message in MessageBox from Dll level (it requires additional references), but I would to pass it to some (on example) WinForm application.
You can just catch the exception in the WinForms class.
This means you should not catch the exception here, but in the WinForms class itself, where you can show a dialog.
You could use something like (I changed a bit of code from your example to improve naming):
public ClassInDllFile()
{
# Other functions
///
/// Might throw a ... exception
///
public Run()
{
String str = someClassMethod(); # Might cause an exception
# More code
}
And in your WinForms class:
var instance = ClassInDllFile()
try
{
instance.Run()
}
catch (Exception e) // or more precised exception type
{
// Error handling code
}
# More code
Also it is a good idea to document the ClassInDllFile.Run function which type of exceptions it might generate to inform calling functions to act upon it.
There are several ways in which you could handle this.
One simple way is to just throw the exception, and handle it in the outer / calling class.
Another is to gather info from the exception in your catch clause (like ExceptionMessage, StackTrace, and perhaps InternalException), and store these in properties that the the calling class can check. You might then also include a boolean property like Suceeded, which you set to false if an exception occurs. Then the calling class can check that property after making the call, and retrieve more details about the exception if it needs them.
You can manipulate this however you want. Experiment until you find a solution that fits your needs.
My problem with DefaultTraceListener (which is the only trace listener, if not overridden in app.config) is that, if AssertUiEnabled is false (i.e. in ASP.NET) it writes a message as OutputDebugString on failed assertions (calls to Trace.Assert(false)), but continues the execution.
So I'm using the following sub-class of TraceListener, which instead throws an exception. I activate it using
TraceListenerWhichThrowsExceptionOnFail.InsertAsFirstTraceListener(Trace.Listeners);
in Application_Init.
Now, in the Application_Error event I can log the exception (as any exception) with the full stack trace, including the call of Trace.Assert(false).
public class TraceListenerWhichThrowsExceptionOnFail : TraceListener
{
public static void InsertAsFirstTraceListener(TraceListenerCollection traceListeners)
{
traceListeners.Insert(0, new TraceListenerWhichThrowsExceptionOnFail());
}
public override void Fail(string message, string detailMessage)
{
message = string.IsNullOrEmpty(detailMessage) ? message : message + ", Detail message: " + detailMessage;
throw new ApplicationException("Trace assertion failed" +
(string.IsNullOrEmpty(message) ? "" : ": " + message) + ".");
}
public override void Write(string message)
{
// NOP
}
public override void WriteLine(string message)
{
// NOP
}
}
Now my question: Does anyone see a problem with this approach?
I'd say exception in Trace.Assert is bad idea (not looking at your code).
Trace.XXXX methods generally used to trace stuff. It would be very surprising to future readers (including you) to learn that Trace.Assert actually throws exception.
It is even more surprising to see Trace.Assert (or even Fail) throwing exception. Purpose of Assert is to help identify issues in advance, not to kill application.
I'd recommend to come up with your custom method that clearly shows its behavior in the name instead of coming up with unexpected behavior of existing methods.
It depends.
I'm not sure this would be useful in an ASP.NET scenario. During debugging, you want assertions to behave normally. Throwing exceptions would probably be a bit confusing. And in production, you would use release builds, so that the Trace.Assert statements don't do anything anyway.
However, we use a similar technique for unit tests. You really don't want to have your build server hanging showing an "Assertion Failed" message box. Instead, you want your assertions to cause the tests to fail. So we use an App.config file for our unit tests (and only for hose!), that installs a trace listener that is similar to yours.
Throwing an exception in Fail() could lead to:
1. the call stack will be confusing, since the exception is not thrown near where the condition failed.
Generally you should throw exception near where the condition fails.
I'm looking into doing some Unity3D scripting stuff, and I'd like to set up global exception handling system. This is not for running in the release version of the game, the intention is to catch exceptions in user scripts and also in editor scripts and make sure they are forwarded to a database for analysis (and also to send email to relevant devs so they can fix their shizzle).
In a vanilla C# app I'd have a try-catch around the Main method. In WPF I'd hook one or more of the unhandled exception events. In Unity...?
So far the best I've been able to come up with is something like this:
using UnityEngine;
using System.Collections;
public abstract class BehaviourBase : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
try
{
performUpdate();
print("hello");
}
catch (System.Exception e)
{
print(e.ToString());
}
}
public abstract void performUpdate();
}
In other scripts, I derive BehaviourBase instead of MonoBehavior and implement performUpdate() instead of Update(). I haven't implemented a parallel version for Editor clases but I assume I'd have to do the same thing there.
I don't like this strategy, however, because I'll have to backport it to any scripts we grab from the community (and I'll have to enforce it on the team). The Editor scripts don't have a single point of entry comparable to MonoBehavior either, so I assume I'd have to implement exception safe versions of wizards, editors and so on.
I've seen suggestions about catching log messages (as opposed to exceptions) using Application.RegisterLogCallback, but this makes me uncomfortable because I'd need to parse the debug log string rather than having access to the actual exceptions and stacktraces.
So... what's the right thing to do?
Create an empty GameObject in your scene and attach this script to it:
using UnityEngine;
public class ExceptionManager : MonoBehaviour
{
void Awake()
{
Application.logMessageReceived += HandleException;
DontDestroyOnLoad(gameObject);
}
void HandleException(string logString, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
//handle here
}
}
}
make sure there is one instance.
The rest is up to you. You can also store the logs in file system, web server or cloud storage.
Note that DontDestroyOnLoad(gameObject) makes this GameObject persistent, by preventing it from being destroyed in case of scene change.
There is a working implementation of RegisterLogCallback that I found here: http://answers.unity3d.com/questions/47659/callback-for-unhandled-exceptions.html
In my own implementation I use it to call my own MessageBox.Show instead of writing to a log file. I just call SetupExceptionHandling from each of my scenes.
static bool isExceptionHandlingSetup;
public static void SetupExceptionHandling()
{
if (!isExceptionHandlingSetup)
{
isExceptionHandlingSetup = true;
Application.RegisterLogCallback(HandleException);
}
}
static void HandleException(string condition, string stackTrace, LogType type)
{
if (type == LogType.Exception)
{
MessageBox.Show(condition + "\n" + stackTrace);
}
}
I also now have the error handler email me via this routine, so I always know when my app crashes and get as much detail as possible.
internal static void ReportCrash(string message, string stack)
{
//Debug.Log("Report Crash");
var errorMessage = new StringBuilder();
errorMessage.AppendLine("FreeCell Quest " + Application.platform);
errorMessage.AppendLine();
errorMessage.AppendLine(message);
errorMessage.AppendLine(stack);
//if (exception.InnerException != null) {
// errorMessage.Append("\n\n ***INNER EXCEPTION*** \n");
// errorMessage.Append(exception.InnerException.ToString());
//}
errorMessage.AppendFormat
(
"{0} {1} {2} {3}\n{4}, {5}, {6}, {7}x {8}\n{9}x{10} {11}dpi FullScreen {12}, {13}, {14} vmem: {15} Fill: {16} Max Texture: {17}\n\nScene {18}, Unity Version {19}, Ads Disabled {18}",
SystemInfo.deviceModel,
SystemInfo.deviceName,
SystemInfo.deviceType,
SystemInfo.deviceUniqueIdentifier,
SystemInfo.operatingSystem,
Localization.language,
SystemInfo.systemMemorySize,
SystemInfo.processorCount,
SystemInfo.processorType,
Screen.currentResolution.width,
Screen.currentResolution.height,
Screen.dpi,
Screen.fullScreen,
SystemInfo.graphicsDeviceName,
SystemInfo.graphicsDeviceVendor,
SystemInfo.graphicsMemorySize,
SystemInfo.graphicsPixelFillrate,
SystemInfo.maxTextureSize,
Application.loadedLevelName,
Application.unityVersion,
GameSettings.AdsDisabled
);
//if (Main.Player != null) {
// errorMessage.Append("\n\n ***PLAYER*** \n");
// errorMessage.Append(XamlServices.Save(Main.Player));
//}
try {
using (var client = new WebClient()) {
var arguments = new NameValueCollection();
//if (loginResult != null)
// arguments.Add("SessionId", loginResult.SessionId.ToString());
arguments.Add("report", errorMessage.ToString());
var result = Encoding.ASCII.GetString(client.UploadValues(serviceAddress + "/ReportCrash", arguments));
//Debug.Log(result);
}
} catch (WebException e) {
Debug.Log("Report Crash: " + e.ToString());
}
}
Unity devs just do not provide us with tools like that. They catch exceptions internally in framework here and there and log them as strings, giving us Application.logMessageReceived[Threaded]. So, if you need exceptions to happen or be logged with your own processing (not unity's) I can think of:
do not use framework mechanics, but use your own so exception is not caught by framework
make your own class implementing UnityEngine.ILogHandler:
public interface ILogHandler
{
void LogFormat(LogType logType, Object context, string format, params object[] args);
void LogException(Exception exception, Object context);
}
And use it as said in official docs to log your exceptions. But that way you do not receive unhandled exceptions and exceptions logged from plugins (yes, someone do log exceptions in frameworks instead of throwing them)
Or you can make a suggestion/request to unity to make Debug.unityLogger (Debug.logger is deprecated in Unity 2017) have setter or other mechanism so we can pass our own.
Just set it with reflection. But it's temporary hack and will not work when unity change code.
var field = typeof(UnityEngine.Debug)
.GetField("s_Logger", BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null, your_debug_logger);
Note: To get correct stacktraces you need to set StackTraceLogType in editor settings/code to ScriptOnly (most times it's what you need, I wrote an article on how it work) And, when building for iOS, it is said that Script call optimization must be set to slow and safe
If interested, you can read how popular crash analytics tool works. If you look into crashlytics (crash report tool for android/ios), than you'll find out that it internally uses Application.logMessageReceived and AppDomain.CurrentDomain.UnhandledException events to log managed C# exceptions.
If interested in examples on unity framework catching exceptions, you may look at ExecuteEvents.Update And another article from me with testing it catching exception in button click listener can be found here.
Some summary on official ways to log unhandled exception:
I. Application.logMessageReceived is fired when exception happens on main thread. There are ways for it to happen:
exception caught in c# code and logged through Debug.LogException
exception caught in native code (probably c++ code when using il2cpp). In that case native code calls Application.CallLogCallback which results in firing Application.logMessageReceived
Note: StackTrace string will contain "rethrow" when original exception have inner exceptions
II. Application.logMessageReceivedThreaded is fired when exception happens on any thread, including main (it's said in docs) Note: it must be thread-safe
III. AppDomain.CurrentDomain.UnhandledException for example is fired when:
You call the following code in editor:
new Thread(() =>
{
Thread.Sleep(10000);
object o = null;
o.ToString();
}).Start();
But it causes crash on android 4.4.2 release build when using Unity 5.5.1f1
Note: I reproduced some bugs with unity missing stackframes when logging exceptions and assertions. I submited one of them.
You mentioned Application.RegisterLogCallback, have you tried implementing it? Because the logging callback passes back a stack trace, an error, and an error type (warning, error, etc).
The strategy you outline above would be tough to implement because MonoBehaviours don't just have a single entry point. You'd have to handle OnTriggerEvent, OnCollisionEvent, OnGUI, and so on. Each one wrapping its logic in an exception handler.
IMHO, exception handling is a bad idea here. If you don't immediately re-throw the exception, you'll end up propagating those errors in weird ways. Maybe Foo relies on Bar, and Bar on Baz. Say Baz throws an exception that is caught and logged. Then Bar throws an exception because the value it needs from Baz is incorrect. Finally Foo throws an exception because the value it was getting from Bar is invalid.
You can use a plugin called Reporter to receive an email of Debug Logs, Stack trace and screen capture on the moment of unhandled Error. Screen capture and stack trace are usually enough to figure out the reason of the Error. For stubborn sneaky Errors you should log more of suspicious data, build and wait again for the error.I Hope this helps.
I have a fun issue where during application shutdown, try / catch blocks are being seemingly ignored in the stack.
I don't have a working test project (yet due to deadline, otherwise I'd totally try to repro this), but consider the following code snippet.
class IndexNotFoundException : Exception { }
public static string RunAndPossiblyThrow(int index, bool doThrow)
{
try
{
return Run(index);
}
catch(IndexNotFoundException e)
{
if(doThrow)
throw;
}
return "";
}
public static string Run(int index)
{
if(_store.Contains(index))
return _store[index];
throw new IndexNotFoundException ();
}
public static string RunAndIgnoreThrow(int index)
{
try
{
return Run(index);
}
catch(IndexNotFoundException e)
{
}
return "";
}
During runtime this pattern works famously. We get legacy support for code that relies on exceptions for program control (bad) and we get to move forward and slowly remove exceptions used for program control.
However, when shutting down our UI, we see an exception thrown from "Run" even though "doThrow" is false for ALL current uses of "RunAndPossiblyThrow". I've even gone so far as to verify this by modifying code to look like "RunAndIgnoreThrow" and I'll still get a crash post UI shutdown.
Mr. Eric Lippert, I read your blog daily, I'd sure love to hear it's some known bug and I'm not going crazy.
EDIT
This is multi-threaded, and I've verified all objects are not modified while being accessed
EDIT
Explicitly show exception is ours
EDIT
forgot to mention, this is on closing, and unfortunately visual studio cannot catch the crash directly. It's likely crashing on a thread other than the UI thread, and once the main closes, this closes. I've only been able to debug this by repeatedly running & closing the application, with task manager open, "Create Dump File" and looking at the resulting 400+mb mess in Windbg. Win7 64 for reference. Make sure this makes sense to you.
EDIT
The following code on shutdown still shows the same exception.
class IndexNotFoundException : Exception { }
public static string RunAndPossiblyThrow(int index, bool doThrow)
{
try
{
return Run(index);
}
catch
{
}
return "";
}
public static string Run(int index)
{
if(_store.Contains(index))
return _store[index];
throw new IndexNotFoundException ();
}
The only thing that seems to get rid of the exception is to go straight to
class IndexNotFoundException : Exception { }
public static string RunAndPossiblyThrow(int index, bool doThrow)
{
try
{
return Run(index);
}
catch
{
}
return "";
}
public static string Run(int index)
{
if(_store.Contains(index))
return _store[index];
return "";
}
Naturally the exception's gone, but my fears of going crazy are still present.
EDIT
it just got worse... this still crashes...
class IndexNotFoundException : Exception { }
public static string RunAndPossiblyThrow(int index, bool doThrow)
{
try
{
throw new IndexNotFoundException();
}
catch
{
}
return "";
}
EDIT
I have a distinct feeling this is going to get me nowhere. On top of the wierd behavior, I can also note that during execution of the UI in the above case, the try catch is being executed faithfully. My UI doesn't crash & it's full of empty strings. However once I start closing the UI, the crash shows itself and the try catch no longer holds back the exception.
EDIT & final
Apparently the dump file was listing in it the most recent first-chance exception. I verified this by creating a new project that threw inside a try catch & slept for 10 seconds. During the wait I got the .dmp file & sure enough, my completely caught exception was showing up.
I'll mark some points for the useful answers, however unfortunately there's still no rhyme or reason why my code is crashing...
Add an Exception as an extra catch. I think you are getting some other exception than ApplicationException and that is the one crashing your app.
There are various exceptions that cannot be caught. Stack Overflow in particular! Could one of these be occurring somewhere in your code?
See http://www.bluebytesoftware.com/blog/PermaLink,guid,223970c3-e1cc-4b09-9d61-99e8c5fae470.aspx
Have you tried adding a "finally" clause? just to see if it won't ignore the try/catch completely? In theory it should always jump to that line before it exits the try/catch no matter what.
If it still ignore that then there is something definitely strange about it.
Probably you catch and throw again some other exception from Run. Probably _store is null or something.
A few things that may help with diagnosis:
Register for AppDomain.CurrentDomain.UnhandledException so you can see if something is crashing on a thread other than the UI thread
Register for Application.ThreadException to catch any exceptions not being caught in the UI thread
Since this is happening during shutdown, are you using any Finalizers that could be throwing on the finalizer thread?