Runtime: The throw keyword shows the wrong thrown exception line

Created on 8 Jan 2018  路  16Comments  路  Source: dotnet/runtime

_From @NicolasDorier on August 22, 2017 14:56_

Using .NETCore2.0, Win10, it seems the throw keywor

Using the throw keyword loose all the initial stacktrace information.
You can workaround with ExceptionDispatchInfo.Capture(ex).Throw();, but this seems like a bug to me.

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                DoStuff();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

        }

        private static void DoStuff()
        {
            try
            {
                throw new Exception("Boom!");
            }
            catch(Exception ex)
            {
                throw;
            }
        }
    }
}

Actual output: (Exception line 28)

   at ConsoleApp3.Program.DoStuff() in c:\users\nicolasdorier\documents\visual studio 2017\Projects\ConsoleApp3\ConsoleApp3\Program.cs:line 28
   at ConsoleApp3.Program.Main(String[] args) in c:\users\nicolasdorier\documents\visual studio 2017\Projects\ConsoleApp3\ConsoleApp3\Program.cs:line 11

Expected output: (Exception line 24)

   at ConsoleApp3.Program.DoStuff() in c:\users\nicolasdorier\documents\visual studio 2017\Projects\ConsoleApp3\ConsoleApp3\Program.cs:line 24
   at ConsoleApp3.Program.Main(String[] args) in c:\users\nicolasdorier\documents\visual studio 2017\Projects\ConsoleApp3\ConsoleApp3\Program.cs:line 11

Workaround using ExceptionDispatchInfo.Capture(ex).Throw();:

using System;
using System.Runtime.ExceptionServices;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                DoStuff();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }

        }

        private static void DoStuff()
        {
            try
            {
                throw new Exception("Boom!");
            }
            catch(Exception ex)
            {
                ExceptionDispatchInfo.Capture(ex).Throw();
                throw;
            }
        }
    }
}

_Copied from original issue: dotnet/corefx#23470_

enhancement up-for-grabs

Most helpful comment

_From @danmosemsft on December 6, 2017 23:35_

I don't think anyone wants the line number on the throw;, it is a bug, we would accept a fix for it, I think it is clearest to reopen this. The fix would be in CoreCLR.

All 16 comments

_From @Clockwork-Muse on August 22, 2017 16:1_

... this is the behavior of the standard framework, too, though (And I'm on Win7 at the moment). I'd consider this (mostly) expected behavior.

It might be better to restate this as a request along the lines of:

Consider making the re-throw shortcut contain the original trace information.

_From @danmosemsft on August 22, 2017 16:8_

I see the same behavior in desktop back to 2.0. Which isn't to say ideally it would be improved.

_From @danmosemsft on August 23, 2017 0:10_

In fact I remember logging this as a bug many years ago. @jkotas is this (reset of line number of frame in which throw; statement is) feasible to ever fix?

I do not see a fundamental problem with fixing it in .NET Core. The usual due-diligence with figuring out the breaking potential of the change would apply.

Do you happen to have the bug number that you have filled years ago?

Note that C# let's you write exception filters that solve the problem of catching exception conditionally as well. The filters give you even better diagnostic experience because of the crash dump will have the stacktrace of the original throw site preserved.

        {
...
        }
        catch (Exception e) when (....)
        {
...
        }

_From @NicolasDorier on August 23, 2017 1:59_

Really it is expected behavior? I am coding in .NET since 2007 or something... it turns out I only noticed out now...

Note that C# let's you write exception filters that solve the problem of catching exception conditionally as well. The filters give you even better diagnostic experience because of the crash dump will have the stacktrace of the original throw site preserved.

You solved another big mystery for me: I had no idea why Exception filter were useful.

_From @NicolasDorier on August 23, 2017 2:1_

@jkotas Ha, you are right, I thought it was specific to .NET Core, but it turns out it does not, it has always been that way.

https://www.thomaslevesque.com/2015/06/21/exception-filters-in-c-6/

_From @NicolasDorier on August 23, 2017 2:1_

You may close this issue or keep it open if you think improving it in .NET core in the future.

_From @joperezr on September 14, 2017 22:44_

Closing for now given the above discussion. Feel free to reopen if needed.

_From @danmosemsft on December 6, 2017 23:35_

I don't think anyone wants the line number on the throw;, it is a bug, we would accept a fix for it, I think it is clearest to reopen this. The fix would be in CoreCLR.

I can't believe this is really happening! 馃帀

@danmosemsft, will this change be included in .NET Core 2.1?
What about be ported to .NET Framework?

Thx!

Yes! That is what I immediately wanted to know! This would be very interesting to a large group of people.

@fujiy yes this will be in .NET Core 2.1, albeit not in the Preview 1 as that branched already. I don't think CoreFX ingested it yet, but in a few days, please try it in master.

For .NET Framework - it is marked netfx-port-consider for our next pass through potential ports. I can't give a timeframe for that.

@danmosemsft, @jkotas, @ateoi.

Considering the following example:

using System;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                DoStuff(); //line 11
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
            }
            Console.ReadLine();
        }

        private static void DoStuff()
        {
            try
            {
                throw new ArgumentNullException("Boom!"); //line 24
            }
            catch (ArgumentException)
            {
                throw; //line 28
            }
            catch(Exception)
            {
                throw;
            }
        }
    }
}

Wouldn't be better to keep both frames (the throwing and the re-throwing ones)? This way it would be easier to identify which catch block captured the exception in DoStuff() method.

In this case the output would be:

   at ConsoleApp3.Program.DoStuff() in C:\Users\fepessot\Source\ExceptionTest\Program.cs:line 24
   at ConsoleApp3.Program.DoStuff() in C:\Users\fepessot\Source\ExceptionTest\Program.cs:line 28
   at ConsoleApp3.Program.Main(String[] args) in C:\Users\fepessot\Source\ExceptionTest\Program.cs:line 11

instead of:

   at ConsoleApp3.Program.DoStuff() in C:\Users\fepessot\Source\ExceptionTest\Program.cs:line 24
   at ConsoleApp3.Program.Main(String[] args) in C:\Users\fepessot\Source\ExceptionTest\Program.cs:line 11

@danmosemsft did this end up getting ported to X version of the netfx? Is there a good way in general of telling which issues labelled 'netfx-port-consider' got addressed or not? Thanks!

It was not ported. The .NET Framework release notes list all changes that went into particular .NET Framework version, e.g. https://github.com/microsoft/dotnet/tree/master/releases/net48

Was this page helpful?
0 / 5 - 0 ratings