Claudio Redi Claudio Redi - 2 months ago 29
C# Question

Wrong line number on stack trace

try
{
//AN EXCEPTION IS GENERATED HERE!!!
}
catch
{
SqlService.RollbackTransaction();
throw;
}



Code above is called in this code

try
{
//HERE IS CALLED THE METHOD THAT CONTAINS THE CODE ABOVE
}
catch (Exception ex)
{
HandleException(ex);
}



The exception passed as parameter to the method "HandleException" contains the line number of the "throw" line in the stack trace instead of the real line where the exception was generated. Anyone knows why this could be happening?

EDIT1
Ok, thanks to all for your answers. I changed the inner catch for


catch(Exception ex)
{
SqlService.RollbackTransaction();
throw new Exception("Enrollment error", ex);
}



Now I have the correct line on the stack trace, but I had to create a new exception. I was hoping to find a better solution :-(

EDIT2
Maybe (if you have 5 minutes) you could try this scenario in order to check if you get the same result, not very complicated to recreate.

Answer

Yes, this is a limitation in the exception handling logic. If a method contains more than one throw statement that throws an exception then you'll get the line number of the last one that threw. This example code reproduces this behavior:

using System;

class Program {
    static void Main(string[] args) {
        try {
            Test();
        }
        catch (Exception ex) {
            Console.WriteLine(ex.ToString());
        }
        Console.ReadLine();
    }
    static void Test() {
        try {
            throw new Exception();  // Line 15
        }
        catch {
            throw;                  // Line 18
        }
    }
}

Output:

System.Exception: Exception of type 'System.Exception' was thrown.
   at Program.Test() in ConsoleApplication1\Program.cs:line 18
   at Program.Main(String[] args) in ConsoleApplication1\Program.cs:line 6

The work-around is simple, just use a helper method to run the code that might throw an exception.

Like this:

static void Test() {
    try {
        Test2();                // Line 15
    }
    catch {
        throw;                  // Line 18
    }
}
static void Test2() {
    throw new Exception();      // Line 22
}

The underlying reason for this awkward behavior is that .NET exception handling is built on top of the operating system support for exceptions. Called SEH, Structured Exception Handling in Windows. Which is stack-frame based, there can only be one active exception per stack frame. A .NET method has one stack frame, regardless of the number of scope blocks inside the method. By using the helper method, you automatically get another stack frame that can track its own exception. The jitter also automatically suppresses the inlining optimization when a method contains a throw statement so there is no need to explicitly use the [MethodImpl] attribute.

Comments