Skip to content
This repository has been archived by the owner on Feb 8, 2024. It is now read-only.

Fix no stack trace on windows #85

Merged
merged 2 commits into from
Jan 20, 2017
Merged

Fix no stack trace on windows #85

merged 2 commits into from
Jan 20, 2017

Conversation

xiren7
Copy link

@xiren7 xiren7 commented Jan 13, 2017

Tested in win32 and win64 with '-g' option.

(I did not touch the assembly code but the code modified automaticly.)

Update:
The added code is simply copied from _d_throw_exception(druntime/src/ldc/eh/libunwind.d)

Update2:
win32 must with '-g -disable-fp-elim' option

Update3:
druntime/src/core/runtime.d

@@ -377,14 +383,14 @@ void msvc_eh_terminate() nothrow
mov RBX, 0xFFFFFF;
and RDX, RBX;
cmp RDX, 0xC48348; // add ESP,nn (debug UCRT libs)
je L_addESP_found;
je L_addESP_found;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, I'll test it over the weekend. All changes starting with this one seem to be different line endings only. Could you please fix that (for the whole file)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just edit the file on the github (using the chrome browser), I really do not know why the line endings changed?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mixture of line endings is probably my fault. Even with the editorconfig plugin VS seems to produce these quite often. I suppose the chrome editor has converted everything to unix-style (which is ok).

exceptionStack.push(throwable);

if (throwable.info is null && cast(byte*)throwable !is typeid(throwable).init.ptr)
throwable.info = _d_traceContext();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this is the behaviour used on other platfroms or in dmd, I don't think it should be encouraged: it can make exceptions unusable slow, even if only used in rare cases. The trace should only be created with the catch statement that actually wants to print it. That's quite a bit more difficult to implement, though...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting info, thanks. I'd rather have Windows streamlined with the other platforms though (and create an enhancement issue wrt. performance and your idea how to improve on it), don't you agree?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe need a option to let user choose not to generate the stack traceback, like this:
throw Exception("", stackTrace=false)

Copy link
Member

@kinke kinke Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When constructing the exception, the user generally doesn't have any idea about where it's going to unwind to and whether there are catch handlers interested in the trace. throw -> _d_throw_exception() could check for registered handlers at runtime though, but it would also require compiler support to register the handlers while in a try scope.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't you agree?

I'm ok with streamlining for now. Disabling the stack trace generation could be done through a -DRT-option for exception heavy applications.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your idea how to improve on it

I lost a branch of druntime in a SSD crash that had that for dmd's Win32 exception handling: The type of the d_run_main catch handler had a specific type that was detected during the search phase of the exception unwinding when the stack of the throw was still available. I guess this is not so easily integrated into the MS C++ runtime without being able to modify it...

Copy link
Member

@kinke kinke Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I lost a branch of druntime in a SSD crash

Sorry to hear that :/ - you got me slightly worried about my SSD and my reluctance to backups now. ;)

I'm ok with streamlining for now.

Perfect.

Disabling the stack trace generation could be done through a -DRT-option for exception heavy applications.

You mean as CMake option to be forwarded as -d-version=... when compiling your own speedy-Gonzalez druntime? Or more fine-grained by extending _d_throw_exception() by a compile-time bool depending on LDC switch, to allow compiling specific modules with no stack traces attached to thrown exceptions?
Edit: In that case, we could also introduce a pragma/UDA controlling the stack trace generation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--DRT- refers to process command line arguments implicitly picked up by druntime.

Copy link
Member

@kinke kinke Jan 13, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see, thanks, never heard of this before. Disabling it per process sounds very reasonable.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--DRT options can also be embedded in the executable or picked up from the environment. See https://dlang.org/spec/garbage.html#gc_config

@kinke
Copy link
Member

kinke commented Jan 20, 2017

Thanks, works fine with -g on Win64. For the record: the frame offset of 1 is to skip _d_throw_exception(). I haven't tested Win32, I'll let CI do that via test in ldc-developers/ldc#1976.

The stack trace is excellent on Win64 now:

object.Exception@exception_stack_trace.d(12): lala
----------------
0x00007FF70BF61091 in exception_stack_trace.bar at C:\LDC\ldc\tests\debuginfo\exception_stack_trace.d(12)
0x00007FF70BF610A9 in exception_stack_trace.foo at C:\LDC\ldc\tests\debuginfo\exception_stack_trace.d(18)
0x00007FF70BF610C7 in D main at C:\LDC\ldc\tests\debuginfo\exception_stack_trace.d(24)
0x00007FF70BF68195 in d_run_main
0x00007FF70BF61195 in __entrypoint.main at C:\LDC\ldc\tests\debuginfo\__entrypoint.d(8)
0x00007FF70BF788A5 in __scrt_common_main_seh at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl(253)
0x00007FFC2A638364 in BaseThreadInitThunk
0x00007FFC2C2570D1 in RtlUserThreadStart

On Ubuntu 16.04 it's pretty bad though:

object.Exception@exception_stack_trace.d(12): lala
----------------
exception_stack_trace.d:12 [0x400b6d]
exception_stack_trace.d:17 [0x400b78]
exception_stack_trace.d:24 [0x400b8c]
??:? _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv [0x64873c7e]
??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x64873bc3]
??:? _d_run_main [0x64873aec]
__entrypoint.d:8 [0x400ce4]
??:? __libc_start_main [0x6442a82f]
??:? [0x4009e8]

@kinke
Copy link
Member

kinke commented Jan 21, 2017

@xiren7: The stack trace is empty on Win32, even with -g -disable-fp-elim:

object.Exception@exception_stack_trace.d(17): lala
----------------

@xiren7
Copy link
Author

xiren7 commented Jan 21, 2017

The FIRSTFRAME should be 2 on win32, and 1 on win64.

When with -link-debuglib:
The FIRSTFRAME should be 1(or 0?) on win32, and 3 on win64.

But when on win32 with -link-debuglib, it still misses the top frame(see below).

The probability when the stack trace is empty on win32 is about 10%(why?), but can not reproduce with -link-debuglib, so I can not trace into druntime.
(use vscode with cpptools extension to debug)

ldc(win32)

// druntime/src/core/runtime.d
static enum FIRSTFRAME = 2; 
ldc2 app.d -m32 -g -disable-fp-elim

console output(no stack trace):

object.Exception@app.d(20): 2
----------------

debugger output(no stack trace):

...
The thread 23076 has exited with code 0 (0x0).
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: object.Exception at memory location 0x00BAF9D4.
Unloaded 'C:\Windows\SysWOW64\dbghelp.dll'.
The thread 10572 has exited with code 1 (0x1).
The thread 22436 has exited with code 1 (0x1).
The thread 20316 has exited with code 1 (0x1).
The thread 22440 has exited with code 1 (0x1).
The program '[21888] app.exe' has exited with code 1 (0x1).

console output(has stack trace):

object.Exception@app.d(20): 2
----------------
0x00D310AC in app.foo at D:\d\test\app.d(21)
0x00D31102 in D main at D:\d\test\app.d(26)
0x00D58E5C in _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv
0x00D58CE7 in _d_run_main
0x00D32EBE in __entrypoint.main at D:\d\test\__entrypoint.d(8)
0x00D69DA1 in __scrt_common_main_seh at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl(253)
0x73C262C4 in BaseThreadInitThunk
0x77100FD9 in RtlSubscribeWnfStateChangeNotification
0x77100FA4 in RtlSubscribeWnfStateChangeNotification

debugger output(has stack trace):

...
The thread 22556 has exited with code 0 (0x0).
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: object.Exception at memory location 0x0115F8CC.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6C4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E674.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E654.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6F4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6C4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6C4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6F4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6F4.
Exception thrown at 0x74C4A832 in app.exe: Microsoft C++ exception: core.demangle.Demangle.ParseException at memory location 0x0115E6F4.
Unloaded 'C:\Windows\SysWOW64\dbghelp.dll'.
The thread 23392 has exited with code 1 (0x1).
The thread 23184 has exited with code 1 (0x1).
The thread 20472 has exited with code 1 (0x1).
The thread 23244 has exited with code 1 (0x1).
The program '[22220] app.exe' has exited with code 1 (0x1).

dmd(win32)

dmd -g -debug app.d

console output:

object.Exception@test\app.d(20): 2
----------------
0x00402057 in void app.foo(int) at D:\d\test\app.d(21)
0x00402073 in _Dmain at D:\d\test\app.d(26)
0x00404057 in D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv
0x0040401B in void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()
0x00403F1C in _d_run_main
0x00403C24 in main at D:\d\test\app.d(7)
0x004275F5 in mainCRTStartup
0x73C262C4 in BaseThreadInitThunk
0x77100FD9 in RtlSubscribeWnfStateChangeNotification
0x77100FA4 in RtlSubscribeWnfStateChangeNotification
Program exited with code 1

debugger output:

...
The thread 20944 has exited with code 0 (0x0).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x02723000).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Exception thrown at 0x74C4A832 (KernelBase.dll) in app.exe: 0xE0440001 (parameters: 0x00439D90).
Unloaded 'C:\Windows\SysWOW64\dbghelp.dll'.
The thread 5016 has exited with code 1 (0x1).
The thread 19464 has exited with code 1 (0x1).
The thread 8164 has exited with code 1 (0x1).
The thread 22700 has exited with code 1 (0x1).
The program '[18552] app.exe' has exited with code 1 (0x1).

ldc(win32, link-debuglib, FIRSTFRAME = 2)

ldc2 app.d -m32 -g -disable-fp-elim -link-debuglib

console output:

object.Exception@app.d(20): 2
----------------
0x01085BB1 in rt.dmain2._d_run_main.runAll.__lambda1 at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
0x01085B26 in rt.dmain2._d_run_main.runAll at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
...

ldc(win32, link-debuglib, FIRSTFRAME = 1)

object.Exception@app.d(20): 2
----------------
0x00F41102 in D main at D:\d\test\app.d(26)
0x00F95BB1 in rt.dmain2._d_run_main.runAll.__lambda1 at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
0x00F95B26 in rt.dmain2._d_run_main.runAll at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
...

The missed top frame:

0x00D310AC in app.foo at D:\d\test\app.d(21)

ldc(win32, link-debuglib, FIRSTFRAME = 0)

object.Exception@app.d(20): 2
----------------
0x00B23FC9 in core.sys.windows.stacktrace.StackTrace.this at D:\d\ldc\runtime\druntime\src\core\sys\windows\stacktrace.d(66)
0x00AB1102 in D main at D:\d\test\app.d(26)
0x00B05BB1 in rt.dmain2._d_run_main.runAll.__lambda1 at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
0x00B05B26 in rt.dmain2._d_run_main.runAll at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
...

ldc(win64, link-debuglib, FIRSTFRAME = 1)

object.Exception@app.d(20): 2
----------------
0x00007FF7063E6B08 in rt.dmain2._d_traceContext at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(269)
0x00007FF7063E235E in ldc.eh.msvc._d_throw_exception at D:\d\ldc\runtime\druntime\src\ldc\eh\msvc.d(118)
0x00007FF7063910A8 in app.foo at D:\d\test\app.d(20)
0x00007FF7063910F6 in D main at D:\d\test\app.d(26)
0x00007FF7063E761A in rt.dmain2._d_run_main.runAll.__lambda1 at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474) 0x00007FF7063E7491 in rt.dmain2._d_run_main.tryExec at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(449)
0x00007FF7063E7563 in rt.dmain2._d_run_main.runAll at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
...

ldc(win64, link-debuglib, FIRSTFRAME = 3)

object.Exception@app.d(20): 2
----------------
0x00007FF7063910A8 in app.foo at D:\d\test\app.d(20)
0x00007FF7063910F6 in D main at D:\d\test\app.d(26)
0x00007FF7063E761A in rt.dmain2._d_run_main.runAll.__lambda1 at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474) 0x00007FF7063E7491 in rt.dmain2._d_run_main.tryExec at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(449)
0x00007FF7063E7563 in rt.dmain2._d_run_main.runAll at D:\d\ldc\runtime\druntime\src\rt\dmain2.d(474)
...

@kinke
Copy link
Member

kinke commented Jan 21, 2017

Confirmed, -link-debuglib makes the trace available on Win32 and affects the number of frames due to inlining in release libs, thanks for pointing that out. I guess the optimal unified offset for now is the minimum of the debug/release one, which should normally be the release one; the Win32 implementation definitely seems to have a problem somewhere, but keeping FIRSTFRAME = 1 seems appropriate for now.

@dnadlinger
Copy link
Member

dnadlinger commented Jan 22, 2017

Rather than hardcoding FIRSTFRAME, can't we do something like on DWARF instead where _d_throw_exception is detected by name? I don't think the small performance cost would be significant compared to the rest of EH/backtracing.

@kinke
Copy link
Member

kinke commented Jan 22, 2017

Implemented by 6d4cf2f.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants