How to get the full stacktrace while method is inline? - c#

The question can be asked in another way, but I'm not sure which one is possible:
How to force the runtime to disable method inline?
Problem
I have a library assembly (no source code), some methods are marked with AggressiveInlining:
CSharpLib
public class ExceptionTest
{
private int[] a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void A()
=> B();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void B()
=> a[0] = 1;
}
The assembly is built in Debug mode (with "Optimize code" unchecked).
In my program I need to call the method A:
My program
static void Main(string[] args)
{
try
{
new CSharpLib.ExceptionTest().A();
}
catch (NullReferenceException e)
{
Console.WriteLine(e.ToString());
}
}
Even if the program is run in Debug mode, it only prints one line:
at Program.Main(String[] args)
So I wonder if I can get a stacktrace with method A and B involved?
My attempts
Both Environment.StackTrace and new StackTrace(true) return the same one frame.
If I put a break point at the end of the catch block and watch e.StackTrace and e, The value of e.StackTrace is the same as above, but the value of StackTrace under e is full:
at CSharpLib.ExceptionTest.B()
at CSharpLib.ExceptionTest.A()
at Program.Main(String[] args)
But I need log the stacktrace, so I cannot just refer the text here.

Related

Trying to merge sort a linked list and getting a stackoverflow exception. How might I prevent that? [duplicate]

I would like to either prevent or handle a StackOverflowException that I am getting from a call to the XslCompiledTransform.Transform method within an Xsl Editor I am writing. The problem seems to be that the user can write an Xsl script that is infinitely recursive, and it just blows up on the call to the Transform method. (That is, the problem is not just the typical programmatic error, which is usually the cause of such an exception.)
Is there a way to detect and/or limit how many recursions are allowed? Or any other ideas to keep this code from just blowing up on me?
From Microsoft:
Starting with the .NET Framework
version 2.0, a StackOverflowException
object cannot be caught by a try-catch
block and the corresponding process is
terminated by default. Consequently,
users are advised to write their code
to detect and prevent a stack
overflow. For example, if your
application depends on recursion, use
a counter or a state condition to
terminate the recursive loop.
I'm assuming the exception is happening within an internal .NET method, and not in your code.
You can do a couple things.
Write code that checks the xsl for infinite recursion and notifies the user prior to applying a transform (Ugh).
Load the XslTransform code into a separate process (Hacky, but less work).
You can use the Process class to load the assembly that will apply the transform into a separate process, and alert the user of the failure if it dies, without killing your main app.
EDIT: I just tested, here is how to do it:
MainProcess:
// This is just an example, obviously you'll want to pass args to this.
Process p1 = new Process();
p1.StartInfo.FileName = "ApplyTransform.exe";
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.Start();
p1.WaitForExit();
if (p1.ExitCode == 1)
Console.WriteLine("StackOverflow was thrown");
ApplyTransform Process:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
throw new StackOverflowException();
}
// We trap this, we can't save the process,
// but we can prevent the "ILLEGAL OPERATION" window
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
if (e.IsTerminating)
{
Environment.Exit(1);
}
}
}
NOTE The question in the bounty by #WilliamJockusch and the original question are different.
This answer is about StackOverflow's in the general case of third-party libraries and what you can/can't do with them. If you're looking about the special case with XslTransform, see the accepted answer.
Stack overflows happen because the data on the stack exceeds a certain limit (in bytes). The details of how this detection works can be found here.
I'm wondering if there is a general way to track down StackOverflowExceptions. In other words, suppose I have infinite recursion somewhere in my code, but I have no idea where. I want to track it down by some means that is easier than stepping through code all over the place until I see it happening. I don't care how hackish it is.
As I mentioned in the link, detecting a stack overflow from static code analysis would require solving the halting problem which is undecidable. Now that we've established that there is no silver bullet, I can show you a few tricks that I think helps track down the problem.
I think this question can be interpreted in different ways, and since I'm a bit bored :-), I'll break it down into different variations.
Detecting a stack overflow in a test environment
Basically the problem here is that you have a (limited) test environment and want to detect a stack overflow in an (expanded) production environment.
Instead of detecting the SO itself, I solve this by exploiting the fact that the stack depth can be set. The debugger will give you all the information you need. Most languages allow you to specify the stack size or the max recursion depth.
Basically I try to force a SO by making the stack depth as small as possible. If it doesn't overflow, I can always make it bigger (=in this case: safer) for the production environment. The moment you get a stack overflow, you can manually decide if it's a 'valid' one or not.
To do this, pass the stack size (in our case: a small value) to a Thread parameter, and see what happens. The default stack size in .NET is 1 MB, we're going to use a way smaller value:
class StackOverflowDetector
{
static int Recur()
{
int variable = 1;
return variable + Recur();
}
static void Start()
{
int depth = 1 + Recur();
}
static void Main(string[] args)
{
Thread t = new Thread(Start, 1);
t.Start();
t.Join();
Console.WriteLine();
Console.ReadLine();
}
}
Note: we're going to use this code below as well.
Once it overflows, you can set it to a bigger value until you get a SO that makes sense.
Creating exceptions before you SO
The StackOverflowException is not catchable. This means there's not much you can do when it has happened. So, if you believe something is bound to go wrong in your code, you can make your own exception in some cases. The only thing you need for this is the current stack depth; there's no need for a counter, you can use the real values from .NET:
class StackOverflowDetector
{
static void CheckStackDepth()
{
if (new StackTrace().FrameCount > 10) // some arbitrary limit
{
throw new StackOverflowException("Bad thread.");
}
}
static int Recur()
{
CheckStackDepth();
int variable = 1;
return variable + Recur();
}
static void Main(string[] args)
{
try
{
int depth = 1 + Recur();
}
catch (ThreadAbortException e)
{
Console.WriteLine("We've been a {0}", e.ExceptionState);
}
Console.WriteLine();
Console.ReadLine();
}
}
Note that this approach also works if you are dealing with third-party components that use a callback mechanism. The only thing required is that you can intercept some calls in the stack trace.
Detection in a separate thread
You explicitly suggested this, so here goes this one.
You can try detecting a SO in a separate thread.. but it probably won't do you any good. A stack overflow can happen fast, even before you get a context switch. This means that this mechanism isn't reliable at all... I wouldn't recommend actually using it. It was fun to build though, so here's the code :-)
class StackOverflowDetector
{
static int Recur()
{
Thread.Sleep(1); // simulate that we're actually doing something :-)
int variable = 1;
return variable + Recur();
}
static void Start()
{
try
{
int depth = 1 + Recur();
}
catch (ThreadAbortException e)
{
Console.WriteLine("We've been a {0}", e.ExceptionState);
}
}
static void Main(string[] args)
{
// Prepare the execution thread
Thread t = new Thread(Start);
t.Priority = ThreadPriority.Lowest;
// Create the watch thread
Thread watcher = new Thread(Watcher);
watcher.Priority = ThreadPriority.Highest;
watcher.Start(t);
// Start the execution thread
t.Start();
t.Join();
watcher.Abort();
Console.WriteLine();
Console.ReadLine();
}
private static void Watcher(object o)
{
Thread towatch = (Thread)o;
while (true)
{
if (towatch.ThreadState == System.Threading.ThreadState.Running)
{
towatch.Suspend();
var frames = new System.Diagnostics.StackTrace(towatch, false);
if (frames.FrameCount > 20)
{
towatch.Resume();
towatch.Abort("Bad bad thread!");
}
else
{
towatch.Resume();
}
}
}
}
}
Run this in the debugger and have fun of what happens.
Using the characteristics of a stack overflow
Another interpretation of your question is: "Where are the pieces of code that could potentially cause a stack overflow exception?". Obviously the answer of this is: all code with recursion. For each piece of code, you can then do some manual analysis.
It's also possible to determine this using static code analysis. What you need to do for that is to decompile all methods and figure out if they contain an infinite recursion. Here's some code that does that for you:
// A simple decompiler that extracts all method tokens (that is: call, callvirt, newobj in IL)
internal class Decompiler
{
private Decompiler() { }
static Decompiler()
{
singleByteOpcodes = new OpCode[0x100];
multiByteOpcodes = new OpCode[0x100];
FieldInfo[] infoArray1 = typeof(OpCodes).GetFields();
for (int num1 = 0; num1 < infoArray1.Length; num1++)
{
FieldInfo info1 = infoArray1[num1];
if (info1.FieldType == typeof(OpCode))
{
OpCode code1 = (OpCode)info1.GetValue(null);
ushort num2 = (ushort)code1.Value;
if (num2 < 0x100)
{
singleByteOpcodes[(int)num2] = code1;
}
else
{
if ((num2 & 0xff00) != 0xfe00)
{
throw new Exception("Invalid opcode: " + num2.ToString());
}
multiByteOpcodes[num2 & 0xff] = code1;
}
}
}
}
private static OpCode[] singleByteOpcodes;
private static OpCode[] multiByteOpcodes;
public static MethodBase[] Decompile(MethodBase mi, byte[] ildata)
{
HashSet<MethodBase> result = new HashSet<MethodBase>();
Module module = mi.Module;
int position = 0;
while (position < ildata.Length)
{
OpCode code = OpCodes.Nop;
ushort b = ildata[position++];
if (b != 0xfe)
{
code = singleByteOpcodes[b];
}
else
{
b = ildata[position++];
code = multiByteOpcodes[b];
b |= (ushort)(0xfe00);
}
switch (code.OperandType)
{
case OperandType.InlineNone:
break;
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
position += 1;
break;
case OperandType.InlineVar:
position += 2;
break;
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.ShortInlineR:
position += 4;
break;
case OperandType.InlineR:
case OperandType.InlineI8:
position += 8;
break;
case OperandType.InlineSwitch:
int count = BitConverter.ToInt32(ildata, position);
position += count * 4 + 4;
break;
case OperandType.InlineMethod:
int methodId = BitConverter.ToInt32(ildata, position);
position += 4;
try
{
if (mi is ConstructorInfo)
{
result.Add((MethodBase)module.ResolveMember(methodId, mi.DeclaringType.GetGenericArguments(), Type.EmptyTypes));
}
else
{
result.Add((MethodBase)module.ResolveMember(methodId, mi.DeclaringType.GetGenericArguments(), mi.GetGenericArguments()));
}
}
catch { }
break;
default:
throw new Exception("Unknown instruction operand; cannot continue. Operand type: " + code.OperandType);
}
}
return result.ToArray();
}
}
class StackOverflowDetector
{
// This method will be found:
static int Recur()
{
CheckStackDepth();
int variable = 1;
return variable + Recur();
}
static void Main(string[] args)
{
RecursionDetector();
Console.WriteLine();
Console.ReadLine();
}
static void RecursionDetector()
{
// First decompile all methods in the assembly:
Dictionary<MethodBase, MethodBase[]> calling = new Dictionary<MethodBase, MethodBase[]>();
var assembly = typeof(StackOverflowDetector).Assembly;
foreach (var type in assembly.GetTypes())
{
foreach (var member in type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).OfType<MethodBase>())
{
var body = member.GetMethodBody();
if (body!=null)
{
var bytes = body.GetILAsByteArray();
if (bytes != null)
{
// Store all the calls of this method:
var calls = Decompiler.Decompile(member, bytes);
calling[member] = calls;
}
}
}
}
// Check every method:
foreach (var method in calling.Keys)
{
// If method A -> ... -> method A, we have a possible infinite recursion
CheckRecursion(method, calling, new HashSet<MethodBase>());
}
}
Now, the fact that a method cycle contains recursion, is by no means a guarantee that a stack overflow will happen - it's just the most likely precondition for your stack overflow exception. In short, this means that this code will determine the pieces of code where a stack overflow can occur, which should narrow down most code considerably.
Yet other approaches
There are some other approaches you can try that I haven't described here.
Handling the stack overflow by hosting the CLR process and handling it. Note that you still cannot 'catch' it.
Changing all IL code, building another DLL, adding checks on recursion. Yes, that's quite possible (I've implemented it in the past :-); it's just difficult and involves a lot of code to get it right.
Use the .NET profiling API to capture all method calls and use that to figure out stack overflows. For example, you can implement checks that if you encounter the same method X times in your call tree, you give a signal. There's a project clrprofiler that will give you a head start.
I would suggest creating a wrapper around XmlWriter object, so it would count amount of calls to WriteStartElement/WriteEndElement, and if you limit amount of tags to some number (f.e. 100), you would be able to throw a different exception, for example - InvalidOperation.
That should solve the problem in the majority of the cases
public class LimitedDepthXmlWriter : XmlWriter
{
private readonly XmlWriter _innerWriter;
private readonly int _maxDepth;
private int _depth;
public LimitedDepthXmlWriter(XmlWriter innerWriter): this(innerWriter, 100)
{
}
public LimitedDepthXmlWriter(XmlWriter innerWriter, int maxDepth)
{
_maxDepth = maxDepth;
_innerWriter = innerWriter;
}
public override void Close()
{
_innerWriter.Close();
}
public override void Flush()
{
_innerWriter.Flush();
}
public override string LookupPrefix(string ns)
{
return _innerWriter.LookupPrefix(ns);
}
public override void WriteBase64(byte[] buffer, int index, int count)
{
_innerWriter.WriteBase64(buffer, index, count);
}
public override void WriteCData(string text)
{
_innerWriter.WriteCData(text);
}
public override void WriteCharEntity(char ch)
{
_innerWriter.WriteCharEntity(ch);
}
public override void WriteChars(char[] buffer, int index, int count)
{
_innerWriter.WriteChars(buffer, index, count);
}
public override void WriteComment(string text)
{
_innerWriter.WriteComment(text);
}
public override void WriteDocType(string name, string pubid, string sysid, string subset)
{
_innerWriter.WriteDocType(name, pubid, sysid, subset);
}
public override void WriteEndAttribute()
{
_innerWriter.WriteEndAttribute();
}
public override void WriteEndDocument()
{
_innerWriter.WriteEndDocument();
}
public override void WriteEndElement()
{
_depth--;
_innerWriter.WriteEndElement();
}
public override void WriteEntityRef(string name)
{
_innerWriter.WriteEntityRef(name);
}
public override void WriteFullEndElement()
{
_innerWriter.WriteFullEndElement();
}
public override void WriteProcessingInstruction(string name, string text)
{
_innerWriter.WriteProcessingInstruction(name, text);
}
public override void WriteRaw(string data)
{
_innerWriter.WriteRaw(data);
}
public override void WriteRaw(char[] buffer, int index, int count)
{
_innerWriter.WriteRaw(buffer, index, count);
}
public override void WriteStartAttribute(string prefix, string localName, string ns)
{
_innerWriter.WriteStartAttribute(prefix, localName, ns);
}
public override void WriteStartDocument(bool standalone)
{
_innerWriter.WriteStartDocument(standalone);
}
public override void WriteStartDocument()
{
_innerWriter.WriteStartDocument();
}
public override void WriteStartElement(string prefix, string localName, string ns)
{
if (_depth++ > _maxDepth) ThrowException();
_innerWriter.WriteStartElement(prefix, localName, ns);
}
public override WriteState WriteState
{
get { return _innerWriter.WriteState; }
}
public override void WriteString(string text)
{
_innerWriter.WriteString(text);
}
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
{
_innerWriter.WriteSurrogateCharEntity(lowChar, highChar);
}
public override void WriteWhitespace(string ws)
{
_innerWriter.WriteWhitespace(ws);
}
private void ThrowException()
{
throw new InvalidOperationException(string.Format("Result xml has more than {0} nested tags. It is possible that xslt transformation contains an endless recursive call.", _maxDepth));
}
}
This answer is for #WilliamJockusch.
I'm wondering if there is a general way to track down
StackOverflowExceptions. In other words, suppose I have infinite
recursion somewhere in my code, but I have no idea where. I want to
track it down by some means that is easier than stepping through code
all over the place until I see it happening. I don't care how hackish
it is. For example, It would be great to have a module I could
activate, perhaps even from another thread, that polled the stack
depth and complained if it got to a level I considered "too high." For
example, I might set "too high" to 600 frames, figuring that if the
stack were too deep, that has to be a problem. Is something like that
possible. Another example would be to log every 1000th method call
within my code to the debug output. The chances this would get some
evidence of the overlow would be pretty good, and it likely would not
blow up the output too badly. The key is that it cannot involve
writing a check wherever the overflow is happening. Because the entire
problem is that I don't know where that is. Preferrably the solution
should not depend on what my development environment looks like; i.e,
it should not assumet that I am using C# via a specific toolset (e.g.
VS).
It sounds like you're keen to hear some debugging techniques to catch this StackOverflow so I thought I would share a couple for you to try.
1. Memory Dumps.
Pro's: Memory Dumps are a sure fire way to work out the cause of a Stack Overflow. A C# MVP & I worked together troubleshooting a SO and he went on to blog about it here.
This method is the fastest way to track down the problem.
This method wont require you to reproduce problems by following steps seen in logs.
Con's: Memory Dumps are very large and you have to attach AdPlus/procdump the process.
2. Aspect Orientated Programming.
Pro's: This is probably the easiest way for you to implement code that checks the size of the call stack from any method without writing code in every method of your application. There are a bunch of AOP Frameworks that allow you to Intercept before and after calls.
Will tell you the methods that are causing the Stack Overflow.
Allows you to check the StackTrace().FrameCount at the entry and exit of all methods in your application.
Con's: It will have a performance impact - the hooks are embedded into the IL for every method and you cant really "de-activate" it out.
It somewhat depends on your development environment tool set.
3. Logging User Activity.
A week ago I was trying to hunt down several hard to reproduce problems. I posted this QA User Activity Logging, Telemetry (and Variables in Global Exception Handlers) . The conclusion I came to was a really simple user-actions-logger to see how to reproduce problems in a debugger when any unhandled exception occurs.
Pro's: You can turn it on or off at will (ie subscribing to events).
Tracking the user actions doesn't require intercepting every method.
You can count the number of events methods are subscribed too far more simply than with AOP.
The log files are relatively small and focus on what actions you need to perform to reproduce the problem.
It can help you to understand how users are using your application.
Con's: Isn't suited to a Windows Service and I'm sure there are better tools like this for web apps.
Doesn't necessarily tell you the methods that cause the Stack Overflow.
Requires you to step through logs manually reproducing problems rather than a Memory Dump where you can get it and debug it straight away.
Maybe you might try all techniques I mention above and some that #atlaste posted and tell us which one's you found were the easiest/quickest/dirtiest/most acceptable to run in a PROD environment/etc.
Anyway good luck tracking down this SO.
If you application depends on 3d-party code (in Xsl-scripts) then you have to decide first do you want to defend from bugs in them or not.
If you really want to defend then I think you should execute your logic which prone to external errors in separate AppDomains.
Catching StackOverflowException is not good.
Check also this question.
I had a stackoverflow today and i read some of your posts and decided to help out the Garbage Collecter.
I used to have a near infinite loop like this:
class Foo
{
public Foo()
{
Go();
}
public void Go()
{
for (float i = float.MinValue; i < float.MaxValue; i+= 0.000000000000001f)
{
byte[] b = new byte[1]; // Causes stackoverflow
}
}
}
Instead let the resource run out of scope like this:
class Foo
{
public Foo()
{
GoHelper();
}
public void GoHelper()
{
for (float i = float.MinValue; i < float.MaxValue; i+= 0.000000000000001f)
{
Go();
}
}
public void Go()
{
byte[] b = new byte[1]; // Will get cleaned by GC
} // right now
}
It worked for me, hope it helps someone.
With .NET 4.0 You can add the HandleProcessCorruptedStateExceptions attribute from System.Runtime.ExceptionServices to the method containing the try/catch block. This really worked! Maybe not recommended but works.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.ExceptionServices;
namespace ExceptionCatching
{
public class Test
{
public void StackOverflow()
{
StackOverflow();
}
public void CustomException()
{
throw new Exception();
}
public unsafe void AccessViolation()
{
byte b = *(byte*)(8762765876);
}
}
class Program
{
[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
Test test = new Test();
try {
//test.StackOverflow();
test.AccessViolation();
//test.CustomException();
}
catch
{
Console.WriteLine("Caught.");
}
Console.WriteLine("End of program");
}
}
}
#WilliamJockusch, if I understood correctly your concern, it's not possible (from a mathematical point of view) to always identify an infinite recursion as it would mean to solve the Halting problem. To solve it you'd need a Super-recursive algorithm (like Trial-and-error predicates for example) or a machine that can hypercompute (an example is explained in the following section - available as preview - of this book).
From a practical point of view, you'd have to know:
How much stack memory you have left at the given time
How much stack memory your recursive method will need at the given time for the specific output.
Keep in mind that, with the current machines, this data is extremely mutable due to multitasking and I haven't heard of a software that does the task.
Let me know if something is unclear.
By the looks of it, apart from starting another process, there doesn't seem to be any way of handling a StackOverflowException. Before anyone else asks, I tried using AppDomain, but that didn't work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
namespace StackOverflowExceptionAppDomainTest
{
class Program
{
static void recrusiveAlgorithm()
{
recrusiveAlgorithm();
}
static void Main(string[] args)
{
if(args.Length>0&&args[0]=="--child")
{
recrusiveAlgorithm();
}
else
{
var domain = AppDomain.CreateDomain("Child domain to test StackOverflowException in.");
domain.ExecuteAssembly(Assembly.GetEntryAssembly().CodeBase, new[] { "--child" });
domain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) =>
{
Console.WriteLine("Detected unhandled exception: " + e.ExceptionObject.ToString());
};
while (true)
{
Console.WriteLine("*");
Thread.Sleep(1000);
}
}
}
}
}
If you do end up using the separate-process solution, however, I would recommend using Process.Exited and Process.StandardOutput and handle the errors yourself, to give your users a better experience.
You can read up this property every few calls, Environment.StackTrace , and if the stacktrace exceded a specific threshold that you preset, you can return the function.
You should also try to replace some recursive functions with loops.

Gracefully handling corrupted state exceptions

Related to this question, I would like to force CLR to let my .NET 4.5.2 app catch Corrupted State Exceptions, for the sole purpose of logging them and then terminating the application. What's the correct way to do this, if I have catch (Exception ex) at several places around the app?
So, after I specify the <legacyCorruptedStateExceptionsPolicy> attribute, if I understood correctly, all the catch (Exception ex) handlers will catch exceptions like AccessViolationException and happily continue.
Yeah, I know catch (Exception ex) is a Bad Idea™, but if CLR would at least put the correct stack trace into the Event Log, I would be more than happy to explain to the customer that his server app failing fast at 1AM and being offline for the night is a good thing. But unfortunately, CLR logs an unrelated exception into the Event Log and then closes the process so that I cannot find out what actually happened.
The question is, how to make this happen, process wide:
if the exception thrown is a Corrupted State Exception:
- write the message to the log file
- end the process
(Update)
In other words, this would probably work for most exceptions in a simple app:
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main() // main entry point
{
try
{
}
catch (Exception ex)
{
// this will catch CSEs
}
}
But, it won't work for:
Unhandled app domain exceptions (i.e. thrown on non-foreground threads)
Windows Service apps (which don't have an actual Main entry point)
So it seems like <legacyCorruptedStateExceptionsPolicy> is the only way to make this work, in which case I don't know how to fail after logging the CSE?
Instead of using <legacyCorruptedStateExceptionsPolicy> it would be better to use [HandleProcessCorruptedStateExceptions] (and [SecurityCritical]) as stated here:
https://msdn.microsoft.com/en-us/magazine/dd419661.aspx
Following that, your Main method should look something like this:
[HandleProcessCorruptedStateExceptions, SecurityCritical]
static void Main(string[] args)
{
try
{
...
}
catch (Exception ex)
{
// Log the CSE.
}
}
But be aware that this doesn't catch the more serious exceptions like StackOverflowException and ExecutionEngineException.
Also finally of involved try blocks will not be executed:
https://csharp.2000things.com/2013/08/30/920-a-finally-block-is-not-executed-when-a-corrupted-state-exception-occurs/
For other unhandled appdomain exceptions you can use :
AppDomain.CurrentDomain.UnhandledException
Application.Current.DispatcherUnhandledException
TaskScheduler.UnobservedTaskException
(Please do a search for the details when a specific handler is appropriate for your situation. TaskScheduler.UnobservedTaskException for example is a bit tricky.)
If you don't have access to the Main method, you can also mark your AppDomain exception handler to catch the CSE:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
...
[HandleProcessCorruptedStateExceptions, SecurityCritical]
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// AccessViolationExceptions will get caught here but you cannot stop
// the termination of the process if e.IsTerminating is true.
}
The last line of defense could be an unmanaged UnhandledExceptionFilter like this:
[DllImport("kernel32"), SuppressUnmanagedCodeSecurity]
private static extern int SetUnhandledExceptionFilter(Callback cb);
// This has to be an own non generic delegate because generic delegates cannot be marshalled to unmanaged code.
private delegate uint Callback(IntPtr ptrToExceptionInfo);
And then somewhere at the beginning of your process:
SetUnhandledExceptionFilter(ptrToExceptionInfo =>
{
var errorCode = "0x" + Marshal.GetExceptionCode().ToString("x2");
...
return 1;
});
You can find more information about the possible return codes here:
https://msdn.microsoft.com/en-us/library/ms680634(VS.85).aspx
A "specialty" of the UnhandledExceptionFilter is that it isn't called if a debugger is attached. (At least not in my case of having a WPF app.) So be aware of that.
If you set all the appropriate ExceptionHandlers from above, you should be logging all exceptions that can be logged. For the more serious exceptions (like StackOverflowException and ExecutionEngineException) you have to find another way because the whole process is unusable after they happened. A possible way could perhaps be another process that watches the main process and logs any fatal errors.
Additional hints:
In the AppDomain.CurrentDomain.UnhandledException you can safely cast the e.ExceptionObject to Exception without having to worry - at least if you don't have any IL code that throws other objects than Exception: Why is UnhandledExceptionEventArgs.ExceptionObject an object and not an Exception?
If you want to suppress the Windows Error Reporting dialog, you can take a look here: How to terminate a program when it crashes? (which should just fail a unit test instead of getting stuck forever)
If you have a WPF application with multiple dispatchers you can also use a Dispatcher.UnhandledException for the other dispatchers.
Thanks to #haindl for pointing out that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions]1 attribute, so I made a little test app just to confirm if things really work as they are supposed to.
1 Note: Most answers state that I should also include the [SecurityCritical] attribute, although in the tests below omitting it didn't change the behavior (the [HandleProcessCorruptedStateExceptions] alone seemed to work just fine). However, I will leave both attributes below since I am presuming all these folks knew what they were saying. That's a school example of "Copied from StackOverflow" pattern in action.
The idea is, obviously, to remove the <legacyCorruptedStateExceptionsPolicy> setting from app.config, i.e. only allow our outermost (entry-level) handler(s) to catch the exception, log it, and then fail. Adding the setting will allow your app to continue, if you catch the exception in some inner handler, and this is not what you want: the idea is just to get the accurate exception info and then die miserably.
I used the following method to throw the exception:
static void DoSomeAccessViolation()
{
// if you have any questions about why this throws,
// the answer is "42", of course
var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);
}
1. Catching exceptions from Main:
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
try
{
DoSomeAccessViolation();
}
catch (Exception ex)
{
// this will catch all CSEs in the main thread
Log(ex);
}
}
2. Catching all exceptions, including background threads/tasks:
// no need to add attributes here
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
// throw on a background thread
var t = new Task(DoSomeAccessViolation);
t.Start();
t.Wait();
}
// but it's important that this method is marked
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// this will catch all unhandled exceptions, including CSEs
Log(e.ExceptionObject as Exception);
}
I would recommend using just the latter approach, and removing the [HandleProcessCorruptedStateExceptions] from all other places to make sure the exception doesn't get caught at the wrong place. I.e. if you have a try/catch block somewhere and an AccessViolationException is thrown, you want CLR to skip the catch block and propagate to the UnhandledException before ending the app.
Is party over? not so fast
Microsoft: "Use application domains to isolate tasks that might bring down a process."
The program below will protect your main application/thread from unrecoverable failures without risks associated with use of HandleProcessCorruptedStateExceptions and <legacyCorruptedStateExceptionsPolicy>
public class BoundaryLessExecHelper : MarshalByRefObject
{
public void DoSomething(MethodParams parms, Action action)
{
if (action != null)
action();
parms.BeenThere = true; // example of return value
}
}
public struct MethodParams
{
public bool BeenThere { get; set; }
}
class Program
{
static void InvokeCse()
{
IntPtr ptr = new IntPtr(123);
System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
}
// This is a plain code that will prove that CSE is thrown and not handled
// this method is not a solution. Solution is below
private static void ExecInThisDomain()
{
try
{
var o = new BoundaryLessExecHelper();
var p = new MethodParams() { BeenThere = false };
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
Console.ReadLine();
}
// This is a solution for CSE not to break your app.
private static void ExecInAnotherDomain()
{
AppDomain dom = null;
try
{
dom = AppDomain.CreateDomain("newDomain");
var p = new MethodParams() { BeenThere = false };
var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
finally
{
AppDomain.Unload(dom);
}
Console.ReadLine();
}
static void Main(string[] args)
{
ExecInAnotherDomain(); // this will not break app
ExecInThisDomain(); // this will
}
}

In C# can you return a default int value from main?

I want to return a default int value from main.
Consider the following:
using System;
class Class1
{
static int Main(string[] args)
{
int intReturnCode = 1;
int intRandNumber;
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
throw new Exception("ErrorError");
}
return intReturnCode;
}
}
When the exception is reached I don't get to set the returncode.
Is it possible to have a default return code inside of main?
Clarification: I have a program that is throwing Unhandled Exceptions. I have the application inside a try catch, however some errors (probably out of memory, stackoverflow etc) are still bubling up and causing my application to fail in production.
To fix this I've added code to capture unhandled exceptions.
This was added to main:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
And now I have this method that is reached when an unhandled exception occurs.
public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
//here's how you get the exception
Exception exception = (Exception)e.ExceptionObject;
//bail out in a tidy way and perform your logging
}
The prblem is that I'm no longer in Main and I want to exit with a non-zero exit code.
An unhandled exception is implementation defined behaviour. Anything can happen; the CLR can decide to set the return code of the process as it sees fit, it can start a debugger, it can do whatever it wants. You cannot rely on any behaviour of any program that contains an unhandled exception.
If you want to have predictable behaviour, like determining what the return code is when the process ends, then there must be a total of zero unhandled exceptions.
If you have a third party component that is throwing unhandled out of memory exceptions then your best bet is: fix the bug in that component. If you can't do that then isolate the component into its own process or its own appdomain.
The question is really why you are throwing an exception in main instead of providing a return code that indicates an error? Instead of what you're doing, my code would look as follows:
static int Main(string[] args)
{
int intRandNumber;
try
{
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
Console.WriteLine("Got invalid random number!");
return 0;
}
}
catch (Exception exp)
{
Console.WriteLine("Strange ... an error occurred! " + exp.ToString());
return -1;
}
return 1;
}
As a rule of thumb you should never throw exceptions to control program flow. If you can, handle conditions like oops, I got the wrong number without throwing an exception.
Throwing an exception in the main thread ends execution without reaching the return: that's when you get the "Console application has stopped working, would you like to debug?" dialog from the operating system. The Main cannot return anything under these conditions, because there is nothing to return.
If you would like to return something when you get an exception, code your program like this:
// Put your implementation into a private method
private static int DoWork(string[] args) {
... // Do actual work, and throw exceptions if you need to
return intReturnCode;
}
// The Main method calls the implementation, and returns the value
// returned from the implementation if everything goes well.
// If an exception is thrown, however, Main could return another value
// of its choice.
public static int Main(string[] args) {
try {
return DoWork(args);
} catch {
return myDefaultReturnCode;
}
}
catch your exception and set return statement in finally block
using System;
class Class1
{
static int Main(string[] args)
{
try
{
int intReturnCode = 1;
int intRandNumber;
Random myRandom = new Random();
intRandNumber = myRandom.Next(0,2);
if(intRandNumber ==1)
{
throw new Exception("ErrorError");
}
}
catch(Exception e)
{
// ...
}
finally
{
return intReturnCode;
}
}
}

Find where rethrown exception was originally thrown using Visual Studio C# debugger?

The usual advice when rethrowing an exception is to use a throw; statement so the original stack trace is preserved. (Example)
However, when I try this simple example, the Visual Studio debugger does not show the original stack trace.
namespace ExceptionTest
{
class Program
{
static void ThrowException()
{
throw new System.Exception(); // The line that I WANT the debugger to show.
}
static void Main(string[] args)
{
try
{
ThrowException();
}
catch (System.Exception)
{
System.Console.WriteLine("An exception was thrown.");
throw; // The line that the debugger ACTUALLY shows.
}
}
}
}
How can I use the debugger to find the original source of the exception?
Your best option is to ask Visual Studio to break on the original exception rather than navigate back to it from the stack trace. To do this:
1) Click on the 'Debug' menu item
2) Click 'Exceptions...'
3) Select 'Common Language Runtime Exceptions' - 'Thrown'
With this approach you may get more than you really wanted if there are many exceptions being thrown. You can filter which exceptions it breaks on by expanding the tree list.
See image:
If you're running Visual Studio 2010 Ultimate, use IntelliTrace.
It keeps a record of all exceptions thrown and allows you to "debug back in time" to see parameters, threads, and variables at the time of each throw.
(Taken from Chris Schmich's answer to a similar question.)
The best solution that I've found is write the Exception callstack to the Debug.Console and then let the built-in code line parser in Visual Studio to provide the navigation.
I found it really useful when dealing with unhandled exceptions on the AppDomain and WPF Dispatcher as Visual Studio always breaks too late.
Based from an article on Code Project, I have modified it that it outputs to the Console as a single block of text - rather than line-by-line - which was necessary I have logging also writing to the Console.
Usage
public void ReportException(Exception exception)
{
if (Debugger.IsAttached)
{
DebugHelper.PrintExceptionToConsole(exception);
Debugger.Break();
}
// ...
}
Source
public static class DebugHelper
{
// Original idea taken from the CodeProject article
// http://www.codeproject.com/Articles/21400/Navigating-Exception-Backtraces-in-Visual-Studio
private static readonly string StarSeparator = new String('*', 80);
private static readonly string DashSeparator = new String('-', 80);
private const string TabString = " ";
/// <summary>
/// Prints the exception using a format recognized by the Visual Studio console parser.
/// Allows for quick navigation of exception call stack.
/// </summary>
/// <param name="exception">The exception.</param>
public static void PrintExceptionToConsole(Exception exception)
{
using (var indentedTextWriter = new IndentedTextWriter(Console.Out, TabString))
{
var indentLevel = 0;
while (exception != null)
{
indentedTextWriter.Indent = indentLevel;
indentedTextWriter.Write(FormatExceptionForDebugLineParser(exception));
exception = exception.InnerException;
indentLevel++;
}
}
}
private static string FormatExceptionForDebugLineParser(Exception exception)
{
StringBuilder result = new StringBuilder();
result.AppendLine(StarSeparator);
result.AppendLineFormat(" {0}: \"{1}\"", exception.GetType().Name, exception.Message);
result.AppendLine(DashSeparator);
// Split lines into method info and filename / line number
string[] lines = exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.Where(x => !String.IsNullOrEmpty(x))
.ToArray();
foreach (var line in lines)
{
string[] parts = line.Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
string methodInfo = parts[0];
if (parts.Length == 2)
{
string[] subparts = parts[1].Split(new string[] { ":line " }, StringSplitOptions.RemoveEmptyEntries);
result.AppendLineFormat(" {0}({1},1): {2}", subparts[0], Int32.Parse(subparts[1]), methodInfo);
}
else
result.AppendLineFormat(" {0}", methodInfo);
}
result.AppendLine(StarSeparator);
return result.ToString();
}
}
To use the above, as is, you will also need the Extension Method below and add the System.CodeDom.Compiler namespace for IndentedTextWriter.
Extension Method
/// <summary>
/// Appends the string returned by processing a composite format string followed by the default line terminator.
/// </summary>
/// <param name="sb">The StringBuilder.</param>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
public static void AppendLineFormat(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
You can use the DebuggerNonUserCode Attribute.
See http://blogs.msdn.com/b/jmstall/archive/2007/02/12/making-catch-rethrow-more-debuggable.aspx
The example becomes like this:
namespace ExceptionTest
{
class Program
{
static void ThrowException()
{
throw new System.Exception(); // The line that I WANT the debugger to show.
}
[DebuggerNonUserCode()]
static void Main(string[] args)
{
try
{
ThrowException();
}
catch (System.Exception)
{
System.Console.WriteLine("An exception was thrown.");
throw; // The line that the debugger ACTUALLY shows.
}
}
}
}
Incidentally, in vb.net, one can use exception filters in some situations like this where one knows one isn't really interested in catching an exception--just finding out that it happened. If the code were written in vb.net and used a filter to capture the exception (probably doing the output itself within the 'finally' block) there wouldn't be a "catch and rethrow"--the cursor would jump to the source of the original exception (as a bonus, vs would interrupt the program flow before any stack unwinding took place). Note that one can opt to have vs trap every time a particular exception is thrown, whether or not it will be caught, but sometimes one is only interested in some of the places an exception is thrown, rather than all of them.

The uncatchable exception, pt 2

Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details
If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!
Ok I've done some testing and I've reduced the problem to something very simple:
i. Create a method in a new class that throws an exception:
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
ii. Create a MethodInfo that points to this method somewhere else:
Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );
iii. Wrap a call to Invoke() in a try/catch block:
try {
method.Invoke( obj, null ); // exception is not being caught!
} catch {
}
iv. Run the program without the debugger (works fine).
v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)
In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]
This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.
I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.
This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(
One thing I can not reproduce, though, is tripping the crash handler. Here's my program:
namespace trash {
public class Class1 {
public void CallMe() {
string blah = null;
blah.ToLower();
}
}
class Program {
static void Main(string[] args) {
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
var class1 = typeof(Class1);
var method = class1.GetMethod("CallMe");
try {
var obj = new Class1();
method.Invoke(obj, null); // exception is not being caught!
}
catch (System.Reflection.TargetInvocationException) {
Console.Write("what you would expect");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Console.Write("it would be horrible if this got tripped but it doesn't!");
}
}
}
You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).
Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.

Categories

Resources