www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - un-catched segfault exception

reply philippe quesnel <philippe.quesnel gmail.com> writes:
I have a bug that causes a segmentation fault (null object)...
but try/catch fails to catch it !! ??

even with
 catch (Exception e)
   ...
 catch (Error e)
   ...
 catch // "last catch"
   ...

I still cant catch the exception & the app crashes.

I'm on Windows (XP), with
gdc.exe (GCC) 3.4.5 (mingw special) (gdc 0.24, using dmd 1.020).

I must be missing some important point here .. this cant be the normal
behaviour !!??

any help / suggestions would be appreciated.
thank you
Philippe
Jan 09 2008
next sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
philippe quesnel wrote:
 I have a bug that causes a segmentation fault (null object)...
 but try/catch fails to catch it !! ??
 
 even with
  catch (Exception e)
    ...
  catch (Error e)
    ...
  catch // "last catch"
    ...
 
 I still cant catch the exception & the app crashes.
 
 I'm on Windows (XP), with
 gdc.exe (GCC) 3.4.5 (mingw special) (gdc 0.24, using dmd 1.020).
 
 I must be missing some important point here .. this cant be the normal
behaviour !!??
 
 any help / suggestions would be appreciated.
 thank you
 Philippe

This certainly can be normal behavior -- C++ does it this way, after all. A segfault is not an exception or an error; it's a signal. You can trap the segfault with a signal handler but you can't catch it in a try/catch block. With exceptions, your program essentially contains a try/catch block around all your code that terminates your program if you didn't handle the exception. That's probably not correct, but it's close enough for my purposes at the moment. With signals, the operating system essentially registers a signal handler; when it gets signal, it determines which application is responsible. If that application has a signal handler, that handler is called; otherwise, your program is toast. What you can do, though, is convert a signal to an exception. It's going to be a lot slower than just checking a pointer to see if it's null, but if you have traced exceptions, the debugging benefit is enormous. Someone else probably has a cleaner version, but here's something that I cooked up a couple weeks back. Tested on Linux, dmd1.023-ish; not guaranteed to work for you. It might destroy your computer, kill your firstborn, raise Cthulhu from the depths, overwrite your doctoral thesis with dancing hamsters, et cetera. The whole point of this code is getting a stack trace rather than an opaque segfault message (if you're using Tango, just inherit from TracedException rather than Exception and reference Flectioned by Thomas Kuehne). It is unreasonable to use anything like this as a regular means of flow control, due to performance reasons and the hideousness of using exceptions for flow control aside from error handling. /** Public domain. Traps SIGSEGV and throws an exception, so you should get a stack trace when you segfault. */ class NullReferenceException : Exception { this (char[] msg) { super(msg); } this () { super ("tried to dereference a pointer to a nonexistent memory region"); } } const int SA_SIGINFO = 4; const int SIGSEGV = 11; extern(C) { struct sig_action { // Dunno if a function* would work here... void* action; int flags; void* restorer; } int sigaction (int signal, sig_action* action, sig_action* oact); } void segv_throw (int i) { throw new NullReferenceException(); } static this () { sig_action act; act.action = &segv_throw; act.flags = SA_SIGINFO; sigaction(SIGSEGV, &act, null); } debug (SegvTest) { void main () { uint* p = null; uint k = *p; } }
Jan 09 2008
next sibling parent reply Hxal <hxal freenode.d.channel> writes:
Christopher Wright Wrote:
 What you can do, though, is convert a signal to an exception. It's going 
 to be a lot slower than just checking a pointer to see if it's null, but 
 if you have traced exceptions, the debugging benefit is enormous. 
 Someone else probably has a cleaner version, but here's something that I 
 cooked up a couple weeks back. Tested on Linux, dmd1.023-ish; not 
 guaranteed to work for you. It might destroy your computer, kill your 
 firstborn, raise Cthulhu from the depths, overwrite your doctoral thesis 
 with dancing hamsters, et cetera.

I have played with throwing exceptions out of signal handlers and it's not going to work in a reliable way at all, on Linux at least. The compiler doesn't generate exception handling frames for blocks of code it doesn't expect to throw an exception, and it doesn't expect single instructions to do so. AFAIK this is true for both dmd and gdc. When you throw an exception and the stack unwinding procedure doesn't find an EH frame, it will abort your application. gcc has two switches to remedy this: -fnon-call-exceptions that expects exceptions to be thrown from dereferences and arithmetics; and -fasynchronous-unwind-tables that generates EH frames encompassing all instructions. Alas gdc doesn't support these. I've played with this a bit in my own stacktracing module (which you can find at http://zygfryd.net/jive/). The same disclaimer applies. PS. Throwing exceptions across C code aborts too, you can however add one of the previously mentioned flags when compiling C code.
Jan 09 2008
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Hxal wrote:
 Christopher Wright Wrote:
 What you can do, though, is convert a signal to an exception. It's going 
 to be a lot slower than just checking a pointer to see if it's null, but 
 if you have traced exceptions, the debugging benefit is enormous. 
 Someone else probably has a cleaner version, but here's something that I 
 cooked up a couple weeks back. Tested on Linux, dmd1.023-ish; not 
 guaranteed to work for you. It might destroy your computer, kill your 
 firstborn, raise Cthulhu from the depths, overwrite your doctoral thesis 
 with dancing hamsters, et cetera.

I have played with throwing exceptions out of signal handlers and it's not going to work in a reliable way at all, on Linux at least. The compiler doesn't generate exception handling frames for blocks of code it doesn't expect to throw an exception, and it doesn't expect single instructions to do so. AFAIK this is true for both dmd and gdc. When you throw an exception and the stack unwinding procedure doesn't find an EH frame, it will abort your application. gcc has two switches to remedy this: -fnon-call-exceptions that expects exceptions to be thrown from dereferences and arithmetics; and -fasynchronous-unwind-tables that generates EH frames encompassing all instructions. Alas gdc doesn't support these. I've played with this a bit in my own stacktracing module (which you can find at http://zygfryd.net/jive/). The same disclaimer applies. PS. Throwing exceptions across C code aborts too, you can however add one of the previously mentioned flags when compiling C code.

I haven't had much need for this stuff yet -- I do mostly metaprogramming stuff -- but thanks for the link. Whenever I do applications work, I'll use your stuff.
Jan 09 2008
prev sibling next sibling parent reply BCS <BCS pathlink.com> writes:
Hxal wrote:
 
 
 I have played with throwing exceptions out of signal handlers and
 it's not going to work in a reliable way at all, on Linux at least.
 The compiler doesn't generate exception handling frames for blocks
 of code it doesn't expect to throw an exception, and it doesn't
 expect single instructions to do so.

I uses this approach and it works just fine. (DMD/Linux and IIRC DMD/Win)
 
 PS. Throwing exceptions across C code aborts too, you can however
 add one of the previously mentioned flags when compiling C code.
 

I've never seen this. OTOH I don't actually catch the exception as the only thing I actually uses the exception for is a poor man's stack trace: // add this at the top of all functions. scope(failure) writef(">>"__FILE__":"~itoa!(__LINE__)~\n);
Jan 10 2008
parent reply Hxal <hxal freenode.d.channel> writes:
BCS Wrote:

 I uses this approach and it works just fine. (DMD/Linux and IIRC DMD/Win)

My bad, I must have remembered wrong, it does indeed work fine with dmd/linux; there aren't even any calls to abort in deh2.d So the problem only applies to gdc, for which the runtime uses gcc's unwind procedure from libgcc_s.
Jan 10 2008
parent Hxal <hxal freenode.d.channel> writes:
 BCS Wrote:
 
 I uses this approach and it works just fine. (DMD/Linux and IIRC DMD/Win)

My bad, I must have remembered wrong, it does indeed work fine with dmd/linux; there aren't even any calls to abort in deh2.d

Actually, I remembered what is the problem with throwing exceptions out of signal handlers with dmd/linux. Such exceptions leak through immediate try-catch blocks. This example would print out "caught in segfault1". void segfault1 () { try { segfault2(); } catch { writefln ("caught in sefgault1"); } } void segfault2 () { try { int* a = cast(int*) 0xdeadc0de; *a = 1; } catch { writefln ("caught in sefgault2"); } }
Jan 11 2008
prev sibling next sibling parent Hxal <hxal freenode.d.channel> writes:
 PS. Throwing exceptions across C code aborts too, you can however
 add one of the previously mentioned flags when compiling C code.

Just a small correction: you need -fexceptions or -funwind-tables, -fnon-call-exceptions and -fasynchronous-unwind-tables aren't necessary unless you're throwing out of signal handlers. (Applies to gcc)
Jan 10 2008
prev sibling parent reply Jason House <jason.james.house gmail.com> writes:
Hxal Wrote:
 I've played with this a bit in my own stacktracing module
 (which you can find at http://zygfryd.net/jive/).
 The same disclaimer applies.

Your project looks interesting. I'd be especially interested in seeing some usage examples. I'll be extremely interested when the disclaimers for stacktrace are lessened. Specifically, linux-only and "doesn't work very well for either DMD or GDC". If they were gone, I'd be using this library tonight!
Jan 10 2008
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Jason House" <jason.james.house gmail.com> wrote in message 
news:fm65g8$p7j$1 digitalmars.com...
 Hxal Wrote:
 I've played with this a bit in my own stacktracing module
 (which you can find at http://zygfryd.net/jive/).
 The same disclaimer applies.

Your project looks interesting. I'd be especially interested in seeing some usage examples. I'll be extremely interested when the disclaimers for stacktrace are lessened. Specifically, linux-only and "doesn't work very well for either DMD or GDC". If they were gone, I'd be using this library tonight!

Well you're obviously using Tango; Tango's had traced exceptions for a while, just get flectioned and link it in when you compile your project.
Jan 10 2008
parent reply Jason House <jason.james.house gmail.com> writes:
Jarrett Billingsley wrote:

 "Jason House" <jason.james.house gmail.com> wrote in message
 news:fm65g8$p7j$1 digitalmars.com...
 Hxal Wrote:
 I've played with this a bit in my own stacktracing module
 (which you can find at http://zygfryd.net/jive/).
 The same disclaimer applies.

Your project looks interesting. I'd be especially interested in seeing some usage examples. I'll be extremely interested when the disclaimers for stacktrace are lessened. Specifically, linux-only and "doesn't work very well for either DMD or GDC". If they were gone, I'd be using this library tonight!

Well you're obviously using Tango; Tango's had traced exceptions for a while, just get flectioned and link it in when you compile your project.

Stupid question - what functionality will that get me? A full backtrace is only part of it. The other (bigger?) part is a way to capture seg faults reliably on all platforms. My project runs on windows, linux, mac, 32-bit, and 64-bit. I have yet to find a reliable way...
Jan 10 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
Jason House wrote:
 Jarrett Billingsley wrote:
 
 "Jason House" <jason.james.house gmail.com> wrote in message
 news:fm65g8$p7j$1 digitalmars.com...
 Hxal Wrote:
 I've played with this a bit in my own stacktracing module
 (which you can find at http://zygfryd.net/jive/).
 The same disclaimer applies.

some usage examples. I'll be extremely interested when the disclaimers for stacktrace are lessened. Specifically, linux-only and "doesn't work very well for either DMD or GDC". If they were gone, I'd be using this library tonight!

while, just get flectioned and link it in when you compile your project.

Stupid question - what functionality will that get me? A full backtrace is only part of it. The other (bigger?) part is a way to capture seg faults reliably on all platforms. My project runs on windows, linux, mac, 32-bit, and 64-bit. I have yet to find a reliable way...

Flectioned gives segfault tracing on Linux. If a Windows-compatible way could be found, it might not be too hard to hack in.
Jan 11 2008
prev sibling next sibling parent reply BCS <BCS pathlink.com> writes:
Christopher Wright wrote:
 What you can do, though, is convert a signal to an exception. It's going 
 to be a lot slower than just checking a pointer to see if it's null, but 
 if you have traced exceptions, the debugging benefit is enormous. 

Why would this be slow? seg-v are caused by hardware. When a seg-v is noticed it triggers an interrupt and the OS goes from there. Until you get a seg-v there should be NO cost at all. Am I missing something?
Jan 10 2008
parent reply Christopher Wright <dhasenan gmail.com> writes:
BCS wrote:
 Christopher Wright wrote:
 What you can do, though, is convert a signal to an exception. It's 
 going to be a lot slower than just checking a pointer to see if it's 
 null, but if you have traced exceptions, the debugging benefit is 
 enormous. 

Why would this be slow? seg-v are caused by hardware. When a seg-v is noticed it triggers an interrupt and the OS goes from there. Until you get a seg-v there should be NO cost at all. Am I missing something?

Handling an error will be slower. Handling a lack of an error will be faster.
Jan 10 2008
parent reply BCS <BCS pathlink.com> writes:
Christopher Wright wrote:
 BCS wrote:
 
 Christopher Wright wrote:

 What you can do, though, is convert a signal to an exception. It's 
 going to be a lot slower than just checking a pointer to see if it's 
 null, but if you have traced exceptions, the debugging benefit is 
 enormous. 

Why would this be slow? seg-v are caused by hardware. When a seg-v is noticed it triggers an interrupt and the OS goes from there. Until you get a seg-v there should be NO cost at all. Am I missing something?

Handling an error will be slower. Handling a lack of an error will be faster.

"Exceptions are a slow way to handle a seg-v's after it happens" Ok that makes a difference. I missed that because 1) I generally assume that performance after an errors is not an issue and 2) in general my programs respond to a seg-v by quitting (with an uncaught exception) on the assumption that their is nothing else it can safely do. I'd be interested in which of theses assumptions is erroneous in your case and why.
Jan 11 2008
parent Christopher Wright <dhasenan gmail.com> writes:
BCS wrote:
 Christopher Wright wrote:
 BCS wrote:

 Christopher Wright wrote:

 What you can do, though, is convert a signal to an exception. It's 
 going to be a lot slower than just checking a pointer to see if it's 
 null, but if you have traced exceptions, the debugging benefit is 
 enormous. 

Why would this be slow? seg-v are caused by hardware. When a seg-v is noticed it triggers an interrupt and the OS goes from there. Until you get a seg-v there should be NO cost at all. Am I missing something?

Handling an error will be slower. Handling a lack of an error will be faster.

"Exceptions are a slow way to handle a seg-v's after it happens" Ok that makes a difference. I missed that because 1) I generally assume that performance after an errors is not an issue and 2) in general my programs respond to a seg-v by quitting (with an uncaught exception) on the assumption that their is nothing else it can safely do. I'd be interested in which of theses assumptions is erroneous in your case and why.

I was speaking about the case where you're using exceptions as flow control rather than a means of error handling. So if you're just going to catch the segfault exception, log it, and quit, fine; performance doesn't matter. If you're going to do something else if you get a segfault and it isn't an error, that will be slower. Not to mention you'd get pwned in code review.
Jan 12 2008
prev sibling parent Michiel Helvensteijn <nomail please.com> writes:
Christopher Wright wrote:

 It might destroy your computer, kill your
 firstborn, raise Cthulhu from the depths, overwrite your doctoral thesis
 with dancing hamsters, et cetera.

Hehe. :-) That is all. -- Michiel
Jan 14 2008
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"philippe quesnel" <philippe.quesnel gmail.com> wrote in message 
news:fm3q1p$su3$1 digitalmars.com...
I have a bug that causes a segmentation fault (null object)...
 but try/catch fails to catch it !! ??

 even with
 catch (Exception e)
   ...
 catch (Error e)
   ...
 catch // "last catch"
   ...

 I still cant catch the exception & the app crashes.

 I'm on Windows (XP), with
 gdc.exe (GCC) 3.4.5 (mingw special) (gdc 0.24, using dmd 1.020).

 I must be missing some important point here .. this cant be the normal 
 behaviour !!??

 any help / suggestions would be appreciated.
 thank you
 Philippe

That's funny, cause on DMDWin you _can_ catch them.
Jan 09 2008
parent reply philippe.quesnel <philippe.quesnel gmail.com> writes:
Jarrett Billingsley Wrote:

 
 That's funny, cause on DMDWin you _can_ catch them. 
 
 

I just did a test C++ app in Windows (MsDev) .. and I do catch exceptions thrown by a null ptr reference. Which is what I was expecting to happen in D. Of course I can check for a NULL ptr ... but catching exceptions is for error handling too !! bugs happen ;-) One point I forgot to mention that might be important (??) : the D code is called by C(++) code (I'm using FLTK2 gui toolkit, calling D code on events) I'll do some tests to see if I the same thing happens under 'normal' situations... thx
Jan 10 2008
parent reply Sean Kelly <sean f4.ca> writes:
philippe.quesnel wrote:
 Jarrett Billingsley Wrote:
 
 That's funny, cause on DMDWin you _can_ catch them. 

I just did a test C++ app in Windows (MsDev) .. and I do catch exceptions thrown by a null ptr reference. Which is what I was expecting to happen in D.

Segfaults in Windows pass through the Structured Exception Handling mechanism, as do many other hardware-level errors. It's the Windows response to signals in Unix. And DMD is nice enough to turn these into D exceptions for you. It sounds like GDC does its exception handling another way however, and does not. Sean
Jan 10 2008
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Sean Kelly wrote:
 philippe.quesnel wrote:
 Jarrett Billingsley Wrote:

 That's funny, cause on DMDWin you _can_ catch them.

I just did a test C++ app in Windows (MsDev) .. and I do catch exceptions thrown by a null ptr reference. Which is what I was expecting to happen in D.

Segfaults in Windows pass through the Structured Exception Handling mechanism, as do many other hardware-level errors. It's the Windows response to signals in Unix. And DMD is nice enough to turn these into D exceptions for you. It sounds like GDC does its exception handling another way however, and does not. Sean

Any way to get Flectioned tracing them?
Jan 11 2008
parent Sean Kelly <sean f4.ca> writes:
Robert Fraser wrote:
 Sean Kelly wrote:
 philippe.quesnel wrote:
 Jarrett Billingsley Wrote:

 That's funny, cause on DMDWin you _can_ catch them.

I just did a test C++ app in Windows (MsDev) .. and I do catch exceptions thrown by a null ptr reference. Which is what I was expecting to happen in D.

Segfaults in Windows pass through the Structured Exception Handling mechanism, as do many other hardware-level errors. It's the Windows response to signals in Unix. And DMD is nice enough to turn these into D exceptions for you. It sounds like GDC does its exception handling another way however, and does not.

Any way to get Flectioned tracing them?

Generating a stack trace within a signal handler would probably work, though it isn't guaranteed to. I'd say it depends on how the OS handles hardware signals. Throwing exceptions from signal handlers has the same problem. Sean
Jan 11 2008
prev sibling parent philippe.quesnel <philippe.quesnel gmail.com> writes:
ok, it seems this is a Windows vs 'Unix' difference...
actually, more like a "Windows type" compiler vs GNU / 'Unix' compiler !

a simple C++ app that tries to write to a NULL ptr :
On Windows :
 - compiled w. MsDev6 : the 'exception' is "catch"ed
 - compiled w. mingw32 C++ : seg faults
  (same w. cygwin)

So depending on the compiler, the behaviour is different.

AND .. same difference between GDC & DMD !!
(as Jarrett mentionned)
the same code (Windows again) ..
 + compiled w. gdc does not catch the 'exception', (segfault)
 + compiled w. dmd DOES catch the error

niiiice .. NOT ;-)

I'll have to look into this signal stuff .. time to read those other posts
again !
thank you
Phil
Jan 10 2008