Rethrowing an exception and preserving stack trace

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Lasse Vågsæther Karlsen

    Rethrowing an exception and preserving stack trace

    If I got the following code:

    try
    {
    // something that might throw an exception
    }
    catch (Exception ex)
    {
    // Log contents of ex here
    throw;
    }

    this will rethrow the exception after logging it, however the stack
    trace from there on will show the line of the "throw;" statement as the
    first entry. If I drop the try/catch block here then the actual line of
    code throwing the exception will be the first entry.

    Using either "throw;" or "throw ex;" produces the same result, the
    existing stack trace gets replaced with a new one starting with the
    re-throwing statement.

    Is there a way to fix this? Can I do something that will keep the
    existing stack trace? Wether the re-throwing statement line and file
    gets added to the stack trace or not is not important, I just don't want
    to loose the history from the stack trace to that point.

    Throwing a new exception and using the previous one as an InnerException
    does not change it as only the new exceptions stack trace is reset,
    however it seems a bit awkward to do this all over:

    throw new SomeExceptionHe re(ex.Message, ex);

    just to keep the stack trace, and of course I would have to unwind the
    tree of exceptions later on to rebuild the full stack trace anyway.

    --
    Lasse Vågsæther Karlsen

    mailto:lasse@vk arlsen.no
    PGP KeyID: 0x2A42A1C2
  • Jon Skeet [C# MVP]

    #2
    Re: Rethrowing an exception and preserving stack trace


    Lasse Vågsæther Karlsen wrote:[color=blue]
    > If I got the following code:
    >
    > try
    > {
    > // something that might throw an exception
    > }
    > catch (Exception ex)
    > {
    > // Log contents of ex here
    > throw;
    > }
    >
    > this will rethrow the exception after logging it, however the stack
    > trace from there on will show the line of the "throw;" statement as the
    > first entry. If I drop the try/catch block here then the actual line of
    > code throwing the exception will be the first entry.
    >
    > Using either "throw;" or "throw ex;" produces the same result, the
    > existing stack trace gets replaced with a new one starting with the
    > re-throwing statement.[/color]

    No - using throw; should be okay, but using throw ex; replaces the
    stack trace.

    Here's an example:

    using System;
    using System.Runtime. CompilerService s;

    class Test
    {
    [MethodImpl(Meth odImplOptions.N oInlining)]
    static void InnerCall()
    {
    throw new Exception();
    }

    [MethodImpl(Meth odImplOptions.N oInlining)]
    static void OuterCall()
    {
    try
    {
    InnerCall();
    }
    catch
    {
    throw;
    }
    }


    static void Main()
    {
    try
    {
    OuterCall();
    }
    catch (Exception e)
    {
    Console.WriteLi ne (e);
    }
    }
    }

    Output is:
    System.Exceptio n: Exception of type 'System.Excepti on' was thrown.
    at Test.InnerCall( )
    at Test.OuterCall( )
    at Test.Main()

    Changing the "throw;" to "throw ex;" (declaring the exception of
    course) changes the output to:

    System.Exceptio n: Exception of type 'System.Excepti on' was thrown.
    at Test.OuterCall( )
    at Test.Main()

    I've included some attributes to ensure the JIT doesn't inline things.
    They don't appear to make a difference in this case, but inlining may
    explain why you've seen it not work in the past.

    Jon

    Comment

    • Lasse Vågsæther Karlsen

      #3
      Re: Rethrowing an exception and preserving stack trace

      Jon Skeet [C# MVP] wrote:[color=blue]
      > Lasse Vågsæther Karlsen wrote:
      >[/color]

      <snip>
      [color=blue][color=green]
      >>this will rethrow the exception after logging it, however the stack
      >>trace from there on will show the line of the "throw;" statement as the
      >>first entry. If I drop the try/catch block here then the actual line of
      >>code throwing the exception will be the first entry.[/color][/color]

      <snip>
      [color=blue]
      > Changing the "throw;" to "throw ex;" (declaring the exception of
      > course) changes the output to:
      >
      > System.Exceptio n: Exception of type 'System.Excepti on' was thrown.
      > at Test.OuterCall( )
      > at Test.Main()
      >
      > I've included some attributes to ensure the JIT doesn't inline things.
      > They don't appear to make a difference in this case, but inlining may
      > explain why you've seen it not work in the past.
      >
      > Jon
      >[/color]

      Thanks, I notice the same when I add the attributes, so then I know what
      it is.


      --
      Lasse Vågsæther Karlsen

      mailto:lasse@vk arlsen.no
      PGP KeyID: 0x2A42A1C2

      Comment

      Working...