www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Collateral exceptions seem to be broken

reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
import std.stdio;
import std.conv;
import std.exception;

void main()
{
    try
    {
        foo();
    }
    catch (Exception e)
    {
        for (Throwable t = e; t !is null; t = t.next)
        {
            writeln(t);
        }
    }
}

void foo()
{
    try
    {
        throw new Exception("thrown from foo");
    }
    finally
    {
        bar(3);
    }
}

void bar(int x)
{
    try
    {
        throw new Exception(text("thrown from bar #", x));
    }
    finally
    {
        if (x > 1)
        {
            bar(x - 1);
        }
    }
}

DMD 2.052, XP 32bit:

object.Exception test.d(26): thrown from foo
object.Exception test.d(38): thrown from bar #3
object.Exception test.d(38): thrown from bar #2
object.Exception test.d(38): thrown from bar #1
object.Exception test.d(38): thrown from bar #3
object.Exception test.d(38): thrown from bar #2
object.Exception test.d(38): thrown from bar #1
object.Exception test.d(38): thrown from bar #2
object.Exception test.d(38): thrown from bar #1
object.Exception test.d(38): thrown from bar #1

Simply calling writeln(e) will work:
void main()
{
    try
    {
        foo();
    }
    catch (Exception e)
    {
        writeln(e);
    }
}

writes:
object.Exception test.d(27): thrown from foo
object.Exception test.d(39): thrown from bar #3
object.Exception test.d(39): thrown from bar #2
object.Exception test.d(39): thrown from bar #1

However that doesn't help if you want to iterate through the
exceptions one at a time.
May 08 2011
next sibling parent KennyTM~ <kennytm gmail.com> writes:
On May 9, 11 04:31, Andrej Mitrovic wrote:
 import std.stdio;
 import std.conv;
 import std.exception;

 void main()
 {
      try
      {
          foo();
      }
      catch (Exception e)
      {
          for (Throwable t = e; t !is null; t = t.next)
          {
              writeln(t);
          }
      }
 }

 void foo()
 {
      try
      {
          throw new Exception("thrown from foo");
      }
      finally
      {
          bar(3);
      }
 }

 void bar(int x)
 {
      try
      {
          throw new Exception(text("thrown from bar #", x));
      }
      finally
      {
          if (x>  1)
          {
              bar(x - 1);
          }
      }
 }

 DMD 2.052, XP 32bit:

 object.Exception test.d(26): thrown from foo
 object.Exception test.d(38): thrown from bar #3
 object.Exception test.d(38): thrown from bar #2
 object.Exception test.d(38): thrown from bar #1
 object.Exception test.d(38): thrown from bar #3
 object.Exception test.d(38): thrown from bar #2
 object.Exception test.d(38): thrown from bar #1
 object.Exception test.d(38): thrown from bar #2
 object.Exception test.d(38): thrown from bar #1
 object.Exception test.d(38): thrown from bar #1

 Simply calling writeln(e) will work:
 void main()
 {
      try
      {
          foo();
      }
      catch (Exception e)
      {
          writeln(e);
      }
 }

 writes:
 object.Exception test.d(27): thrown from foo
 object.Exception test.d(39): thrown from bar #3
 object.Exception test.d(39): thrown from bar #2
 object.Exception test.d(39): thrown from bar #1

 However that doesn't help if you want to iterate through the
 exceptions one at a time.

Not reproducible on OS X with druntime on git master. I get object.Exception y.d(24): thrown from foo ---------------- 5 y 0x000020b6 void y.foo() + 86 6 y 0x00002036 _Dmain + 14 <<rest of stack trace omitted>> object.Exception y.d(36): thrown from bar #3 ---------------- 5 y 0x00002141 void y.bar(int) + 105 6 y 0x000020d0 void y.foo() + 112 7 y 0x00002036 _Dmain + 14 <<rest of stack trace omitted>> object.Exception y.d(36): thrown from bar #2 ---------------- 5 y 0x00002141 void y.bar(int) + 105 6 y 0x00002160 void y.bar(int) + 136 7 y 0x000020d0 void y.foo() + 112 8 y 0x00002036 _Dmain + 14 <<rest of stack trace omitted>> object.Exception y.d(36): thrown from bar #1 ---------------- 5 y 0x00002141 void y.bar(int) + 105 6 y 0x00002160 void y.bar(int) + 136 7 y 0x00002160 void y.bar(int) + 136 8 y 0x000020d0 void y.foo() + 112 9 y 0x00002036 _Dmain + 14 <<rest of stack trace omitted>>
May 08 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Yeah it seems to be fixed in 2.053 beta.

But why is the stack trace printed out? Is that the new norm when
printing caught exceptions with write()?

Regardless of that, I don't get any symbols printed out when building
with dmd -g -debug:

C:\dmd2\windows\bin>dmd -debug -g test.d
C:\dmd2\windows\bin>test
object.Exception test.d(24): thrown from foo
----------------
42BA60
42B8D7
40203E
4059B8
4059F7
4055F3
45BEED
object.Exception test.d(36): thrown from bar #3
----------------
42BA60
42B8D7
402115
40203E
4059B8
4059F7
4055F3
45BEED
object.Exception test.d(36): thrown from bar #2
----------------
42BA60
42B8D7
4021D6
402115
40203E
4059B8
4059F7
4055F3
45BEED
object.Exception test.d(36): thrown from bar #1
----------------
42BA60
42B8D7
...

Where are the symbols? :o
May 08 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 Yeah it seems to be fixed in 2.053 beta.
 
 But why is the stack trace printed out? Is that the new norm when
 printing caught exceptions with write()?
 
 Regardless of that, I don't get any symbols printed out when building
 with dmd -g -debug:
 
 C:\dmd2\windows\bin>dmd -debug -g test.d
 C:\dmd2\windows\bin>test
 object.Exception test.d(24): thrown from foo
 ----------------
 42BA60
 42B8D7
 40203E
 4059B8
 4059F7
 4055F3
 45BEED
 object.Exception test.d(36): thrown from bar #3
 ----------------
 42BA60
 42B8D7
 402115
 40203E
 4059B8
 4059F7
 4055F3
 45BEED
 object.Exception test.d(36): thrown from bar #2
 ----------------
 42BA60
 42B8D7
 4021D6
 402115
 40203E
 4059B8
 4059F7
 4055F3
 45BEED
 object.Exception test.d(36): thrown from bar #1
 ----------------
 42BA60
 42B8D7
 ...
 
 Where are the symbols? :o

Recent work has been done on chained exceptions, so that could definitely change their behavior. And you should definitely get the symbols on Linux if you compile with the standard dmd.conf. If you aren't doing that for some reason, then you need to make sure that you use -L--export-dynamic. - Jonathan M Davis
May 08 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
No, I'm on Windows. And I can't get any symbols unless I run cv2pdb
(http://www.dsource.org/projects/cv2pdb) on the executable.

Here's my console log:

D:\dev\code\d_code>type test.d
import std.exception;

void main()
{
    foo();
}

void foo()
{
    throw new Exception("foo");
}

D:\dev\code\d_code>dmd -debug -g test.d

D:\dev\code\d_code>test
object.Exception test.d(10): foo
----------------
414280
4140F7
402018
4025B8
4025F7
4021F3
45D5E9
45D540
----------------

D:\dev\code\d_code>cv2pdb test.exe test.exe

D:\dev\code\d_code>test
object.Exception test.d(10): foo
----------------
D:\dev\code\d_code\test.d(5): D main
----------------
May 08 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 No, I'm on Windows. And I can't get any symbols unless I run cv2pdb
 (http://www.dsource.org/projects/cv2pdb) on the executable.

There was a discussion on that recently. From what I understand, your build has to have debug symbols for you to get any function names (otherwise, it won't have any function names to show), and Sean may have to make additional changes to get it properly show names. I don't know if you can currently get it to show function names on Windows. - Jonathan M Davis
May 08 2011
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
You mean my build of DMD/Phobos?

Well the debug symbols are definitely shown after I run cv2pdb on the
executable (it makes a .pdb file with all the symbols which get loaded
at runtime by the exe).

Perhaps displaying names is just unimplemented yet in 2.053 for
Windows. Using cv2pdb is not a problem for me (and it allows me to use
VisualD's debugger, which is nice).
May 08 2011
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
Andrej Mitrovic wrote:
 You mean my build of DMD/Phobos?
 
 Well the debug symbols are definitely shown after I run cv2pdb on the
 executable (it makes a .pdb file with all the symbols which get loaded
 at runtime by the exe).
 
 Perhaps displaying names is just unimplemented yet in 2.053 for
 Windows. Using cv2pdb is not a problem for me (and it allows me to use
 VisualD's debugger, which is nice).

It is implemented, but there are currently a few problems: - the stacktrace uses dbghelp.dll to get symbol information for a code address. This often doesn't work with the debug information emitted by dmd/optlink. You have to convert it with cv2pdb to make it digestable to dbghelp. - creating the stack trace uses core.demangle on each symbol, but any symbol that cannot be demangled causes exceptions when trying to demangle it, resulting in recursive attempts to dump the stack. These symbols include C-style, compressed and "SHA'd" symbols. - thus, core.demangle should have a simple check to reject any symbol that does not start with _D<digit>. This does not exclude invalid, compressed and SHA'd symbols, but it works for most symbols. - a recent change in dmd causes debug symbols to be written unmangled, not with mangled names adding all symbols to the list of symbols causing trouble. This helps debuggers to display sensible names without the need to be able to demangle names. Additionally, it allows inspecting globals without knowing the mangled name. But with this change in place, it is no longer necessary to try demangling the names. The change might break some tools that rely on mangled names, though. Does this raise a red flag for someone? - cv2pdb demangles names and converts '.' to ' '. The '.' inside symbols confuses the Microsoft debuggers, e.g. you can no longer inspect the members of a class instance because of the '.' in the class name. Unfortunately, the ' ' seems to confuse dbghelp.dll, causing it to output just the part of the symbol until the first ' '. Maybe I should switch to '_', it even looks better than ' ' but it introduces ambiguities. - it also helps to use a debug build of phobos. Otherwise you won't get any symbolic information for phobos-functions on the stack. Missing symbols might even cause the stack walker to be unable to unwind the proper call stack. I suggest to even add debug symbols to the release build of phobos, as you also don't have debug info for non-template classes and structs declared inside phobos, even if your application is built with -g. Rainer
May 09 2011
next sibling parent KennyTM~ <kennytm gmail.com> writes:
On May 10, 11 02:05, Rainer Schuetze wrote:
 - creating the stack trace uses core.demangle on each symbol, but any
 symbol that cannot be demangled causes exceptions when trying to
 demangle it, resulting in recursive attempts to dump the stack. These
 symbols include C-style, compressed and "SHA'd" symbols.

I ain't using D on Windows. In the OSX version the stack trace are demangled (as I've shown in the post above) and I didn't notice any problems. The specific exceptions that core.demangle.Demangler generates are all caught in opCall, how will that matter? Is it only a Windows problem? (Or Demangler could be rewritten to not rely on exceptions, but that's troublesome :).)
May 09 2011
prev sibling next sibling parent Rainer Schuetze <r.sagitario gmx.de> writes:
Rainer Schuetze wrote:
 
 Andrej Mitrovic wrote:
 You mean my build of DMD/Phobos?

 Well the debug symbols are definitely shown after I run cv2pdb on the
 executable (it makes a .pdb file with all the symbols which get loaded
 at runtime by the exe).

 Perhaps displaying names is just unimplemented yet in 2.053 for
 Windows. Using cv2pdb is not a problem for me (and it allows me to use
 VisualD's debugger, which is nice).

It is implemented, but there are currently a few problems: - the stacktrace uses dbghelp.dll to get symbol information for a code address. This often doesn't work with the debug information emitted by dmd/optlink. You have to convert it with cv2pdb to make it digestable to dbghelp.

I stand corrected here. What you need is a newer version of dbghelp.dll than the one found on XP. You can find one in a newer Windows SDK or the "Debugging Tools for Windows" from Microsoft.
 
 - a recent change in dmd causes debug symbols to be written unmangled,
 not with mangled names adding all symbols to the list of symbols causing
 trouble. This helps debuggers to display sensible names without the need
 to be able to demangle names. Additionally, it allows inspecting globals
 without knowing the mangled name.
 But with this change in place, it is no longer necessary to try
 demangling the names. The change might break some tools that rely on 
 mangled names, though. Does this raise a red flag for someone?

I have to correct myself again: The debug info has both versions now in two seperate places. The call stack uses the global symbol table and its symbols are still mangled.
May 09 2011
prev sibling parent reply Stephan <spam extrawurst.org> writes:
On 09.05.2011 20:05, Rainer Schuetze wrote:
 I suggest to even add debug symbols to the release build of phobos, as
 you also don't have debug info for non-template classes and structs
 declared inside phobos, even if your application is built with -g.

 Rainer

That is a excellent idea. Can you post that on the beta mailing list so that it gets attention ? Stephan
May 10 2011
parent Rainer Schuetze <r.sagitario gmx.de> writes:
Stephan wrote:
 On 09.05.2011 20:05, Rainer Schuetze wrote:
 I suggest to even add debug symbols to the release build of phobos, as
 you also don't have debug info for non-template classes and structs
 declared inside phobos, even if your application is built with -g.

 Rainer

That is a excellent idea. Can you post that on the beta mailing list so that it gets attention ? Stephan

Probably not ready for prime time yet: When building the std.algorithm unittests against a runtime library with debug symbols (both release or debug builds) I'm getting crashes in optlink. I'll create a bug report...
May 14 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On 2011-05-08 15:57, Andrej Mitrovic wrote:
 You mean my build of DMD/Phobos?
 
 Well the debug symbols are definitely shown after I run cv2pdb on the
 executable (it makes a .pdb file with all the symbols which get loaded
 at runtime by the exe).
 
 Perhaps displaying names is just unimplemented yet in 2.053 for
 Windows. Using cv2pdb is not a problem for me (and it allows me to use
 VisualD's debugger, which is nice).

I don't know exactly what works and what needs to be ironed out with regards to stack traces on Windows. I know that there is some further work that needs to be done to properly deal with displaying symbols, but I don't normally use Windows, and I didn't pay a lot of attention to the discussions on the issues with stack traces on it. Regardless, they're very recently added, so it's not altogether surprising if they're somewhat buggy still. - Jonathan M Davis
May 08 2011
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
On May 8, 2011, at 3:57 PM, Andrej Mitrovic wrote:
 
 Perhaps displaying names is just unimplemented yet in 2.053 for
 Windows. Using cv2pdb is not a problem for me (and it allows me to use
 VisualD's debugger, which is nice).

This should be implemented in the 2.053 beta.
May 09 2011