digitalmars.D - proposal(+working code): catch block callback before stack unwinds to
- Timothee Cour (59/59) Oct 27 2013 currently, there's no way to execute some function attached to a specifi...
- David Nadlinger (8/10) Oct 27 2013 Haven't looked at the proposal in any detail yet, but keep in
- Timothee Cour (24/35) Oct 27 2013 ideal syntax would be something along those lines:
- Iain Buclaw (7/30) Oct 28 2013 GDB has 'catch throw' and 'catch catch' as convenient C++ breakpoint
- Timothee Cour (9/49) Oct 28 2013 I'm worried about that from performance standpoint:
currently, there's no way to execute some function attached to a specific 'catch block' right before unwinding the stack, after a thrown exception/error. The only thing we can do is set a custom Runtime.traceHandler, but this cannot depend on the catch block (and doing so for every catch block would hurt performance) This prevents attaching a debugger right before stack unwinding at the root of the program in the following scenario: ---- void fun(){ try{...}catch{...} // code that may throw and is usually caught in normal setting // occasionally some unusual exceptions/errors won't be caught } void call_debugger(){ //raise signal so we can attach a debugger } void main(){ try{ fun(); } catch(Throwable t){ // we want to call call_debugger after an uncaught exception lands here but before stack unwinds, because most information is lost after stack unwinds // the other catch blocks should be unaffected, in particular call_debugger should only be called before landing on this specific catch block } } ---- I've modified rt/deh2.d to allow it, it works great, but my implementation is hacky, and I'd like to poke the newsgroup for a better design: class ThrowableSpecialUnwinding : Throwable {...} void main(){ try{...} catch(ThrowableSpecialUnwinding t){ //callbackBeforeUnwinding is called right before unwinding stack and entering this block // it doesn't affect other catch blocks nor assumes anything about the caught exception which could be any Throwable. // I've cheated here so casting back auto real_t=cast(Throwable)cast(void*)t; } } extern(C) void callbackBeforeUnwinding(Throwable t){ call_debugger; //this could be calling a function pointer modifyable at runtime } The hacky part is here: in rt/deh2.d, I changed: if (_d_isbaseof(ci, pcb.type) ) to : bool isSpecial = pcb.type== ThrowableSpecialUnwinding.classinfo && _d_isbaseof(ci, Throwable.classinfo); if(isSpecial) callbackBeforeUnwinding(cast(Throwable) *h); if (_d_isbaseof(ci, pcb.type) || isSpecial) {/*will stack unwind here*/}
Oct 27 2013
On Sunday, 27 October 2013 at 13:09:21 UTC, Timothee Cour wrote:The hacky part is here: in rt/deh2.d, I changed:Haven't looked at the proposal in any detail yet, but keep in mind that rt.deh2 is only used by DMD. GDC and LDC use GCC's libunwind for exception handling on most platforms. If the semantics of a feature are reasonable, it's probably possible to implement it on top of libunwind as well, but it's definitely something to keep in mind. David
Oct 27 2013
ideal syntax would be something along those lines: try{...} catch(SomeThrowableType e, &callback_before_unwinding){...} with callback_before_unwinding of type 'void function(Throwable t)' The semantics of which is: if 'e' is about to be caught in this particular catch block, call callback_before_unwinding(e) _before_ unwinding stack and entering catch block. Advantages are: * it allows one to, for example, attach a debugger before stack unwinds and entering this catch block * the debugger is only attached at that point, hence not making the regular program slower * it doesn't affect other catch blocks nor does it affect how exceptions/errors are thrown * it could even allow one to make speed up exception handling, by computing backtrace _only_ inside this callback_before_unwinding, so that usual exceptions (std.conv conversions etc) can be caught without any backtrace inside the main program while unusual unintended exceptions would be caught at the root and show proper stack trace. This saves a lot of time when debugging issues, at _zero_ cost in performance. Does libunwind allow that? Otherwise could it be adapted to do that? On Sun, Oct 27, 2013 at 6:27 AM, David Nadlinger <code klickverbot.at>wrote:On Sunday, 27 October 2013 at 13:09:21 UTC, Timothee Cour wrote:The hacky part is here: in rt/deh2.d, I changed:Haven't looked at the proposal in any detail yet, but keep in mind that rt.deh2 is only used by DMD. GDC and LDC use GCC's libunwind for exception handling on most platforms. If the semantics of a feature are reasonable, it's probably possible to implement it on top of libunwind as well, but it's definitely something to keep in mind. David
Oct 27 2013
On 27 October 2013 23:43, Timothee Cour <thelastmammoth gmail.com> wrote:ideal syntax would be something along those lines: try{...} catch(SomeThrowableType e, &callback_before_unwinding){...} with callback_before_unwinding of type 'void function(Throwable t)' The semantics of which is: if 'e' is about to be caught in this particular catch block, call callback_before_unwinding(e) _before_ unwinding stack and entering catch block. Advantages are: * it allows one to, for example, attach a debugger before stack unwinds and entering this catch block * the debugger is only attached at that point, hence not making the regular program slower * it doesn't affect other catch blocks nor does it affect how exceptions/errors are thrown * it could even allow one to make speed up exception handling, by computing backtrace _only_ inside this callback_before_unwinding, so that usual exceptions (std.conv conversions etc) can be caught without any backtrace inside the main program while unusual unintended exceptions would be caught at the root and show proper stack trace. This saves a lot of time when debugging issues, at _zero_ cost in performance. Does libunwind allow that? Otherwise could it be adapted to do that?GDB has 'catch throw' and 'catch catch' as convenient C++ breakpoint placeholders in the debugger. Can certainly implement them for D too. http://www.delorie.com/gnu/docs/gdb/gdb_31.html -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Oct 28 2013
On Mon, Oct 28, 2013 at 12:08 AM, Iain Buclaw <ibuclaw ubuntu.com> wrote:On 27 October 2013 23:43, Timothee Cour <thelastmammoth gmail.com> wrote:I'm worried about that from performance standpoint: * that implies running the normal program execution while attached to a debugger, which would be slower * catch throw will stop at every thrown exception as opposed to the ones that are caught at a certain 'root' point. In what I suggested (and implemented for dmd), it has 0 performance penalty and only triggers when a thrown exception is caught in a particular location; debugger isn't attached during normal program execution.ideal syntax would be something along those lines: try{...} catch(SomeThrowableType e, &callback_before_unwinding){...} with callback_before_unwinding of type 'void function(Throwable t)' The semantics of which is: if 'e' is about to be caught in this particular catch block, call callback_before_unwinding(e) _before_ unwinding stack and entering catch block. Advantages are: * it allows one to, for example, attach a debugger before stack unwindsandentering this catch block * the debugger is only attached at that point, hence not making theregularprogram slower * it doesn't affect other catch blocks nor does it affect how exceptions/errors are thrown * it could even allow one to make speed up exception handling, bycomputingbacktrace _only_ inside this callback_before_unwinding, so that usual exceptions (std.conv conversions etc) can be caught without any backtrace inside the main program while unusual unintended exceptions would becaughtat the root and show proper stack trace. This saves a lot of time when debugging issues, at _zero_ cost in performance. Does libunwind allow that? Otherwise could it be adapted to do that?GDB has 'catch throw' and 'catch catch' as convenient C++ breakpoint placeholders in the debugger. Can certainly implement them for D too. http://www.delorie.com/gnu/docs/gdb/gdb_31.html-- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0';
Oct 28 2013