www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GktD: exceptions in handlers cause segfaults.

reply Marco Leise <Marco.Leise gmx.de> writes:
I am trying to throw exceptions in gtk signal handlers, but I
am greeted with segfaults. What's the cause and are there
solutions?
(DMD 2.063.2 on Linux x86-64)

Here is some reduced code:

import gtk.Main;
import gtk.MainWindow;
import gdk.Event;
import gtk.Widget;

class TestWindow : MainWindow
{
	this(string a)
	{
		super(a);
		this.addOnButtonPress(&click);
	}

	bool click(Event, Widget)
	{
		throw new Exception("");
	}
}

int main(string[] args)
{
	try
	{
		Main.init(args);
		auto win = new TestWindow("bla");
		win.showAll();
		Main.run();
		return 0;
	}
	catch (Exception e)
	{
		writeln (e.msg);
		return 1;
	}
}

In gdb I get this (line numbers not matching with above
example):

Program received signal SIGSEGV, Segmentation fault.
0x00000000010f0b60 in rt.deh2.terminate() ()
(gdb) backtrace



_param_1=0x7ffff7f25800, _param_0=0x7ffff7f23c80) at main.d:589

(widgetStruct=0x16b9190, event=0x17dd5d0, _widget=0x7ffff7f25800) at
gtk/Widget.d:693


/usr/lib64/libgobject-2.0.so.0


/usr/lib64/libgobject-2.0.so.0






/usr/lib64/libglib-2.0.so.0











(gdb) disassemble
Dump of assembler code for function _D2rt4deh29terminateFZv:
   0x00000000010f0b5c <+0>:	push   %rbp
   0x00000000010f0b5d <+1>:	mov    %rsp,%rbp
=> 0x00000000010f0b60 <+4>:	hlt    
   0x00000000010f0b61 <+5>:	pop    %rbp
   0x00000000010f0b62 <+6>:	retq   
End of assembler dump.

-- 
Marco
Jul 19 2013
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 19 Jul 2013 11:10:04 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

dav1d gave me advice on rebuilding druntime with debug symbols.
That lead me to this "GitHub" stack trace:

https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L104
https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L201
https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L246
... back into my code where I throw the exception.

-- 
Marco
Jul 19 2013
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 19 Jul 2013 11:47:41 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 Am Fri, 19 Jul 2013 11:10:04 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:
 
 dav1d gave me advice on rebuilding druntime with debug symbols.
 That lead me to this "GitHub" stack trace:
 
 https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L104
 https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L201
 https://github.com/D-Programming-Language/druntime/blob/v2.063.2/src/rt/deh2.d#L246
 ... back into my code where I throw the exception.
dav1d also told me to watch the DConf 2013 presentation of Higgs where a similar problem with asserts in JIT generated code occurred. It turns out that what Walter explained is the key here, too. All my libraries are compiled without frame pointers, so the simple stack unwinding that D uses fails there. I recompiled glib and gtk+ with -fno-omit-frame-pointer specifically and from now on exception handling works again. Additional info on stack unwinding in the absence of a frame pointer: http://www.yosefk.com/blog/getting-the-call-stack-without-a-frame-pointer.html -- Marco
Jul 19 2013
parent reply Johannes Pfau <nospam example.com> writes:
Am Fri, 19 Jul 2013 12:38:45 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 It turns out that what Walter explained is the
 key here, too. All my libraries are compiled without frame
 pointers, so the simple stack unwinding that D uses fails
 there. I recompiled glib and gtk+ with -fno-omit-frame-pointer
 specifically and from now on exception handling works again.
Would be nice to know if this is working with gdc or ldc. In theory it should work as we use gcc's exception handling/stack unwinding so it's probably a dmd bug. Slightly off topic, but maybe interesting: Things can get really nasty if the GCC backend somehow decided a function is nothrow and you throw from there. Unless GTK uses some special __nothrow__ attributes that shouldn't happen in C, but I've seen D code that throws from nothrow functions and at least on ARM that crashes... Might be a gdc bug or a problem with the D language specification.
Jul 19 2013
parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Fri, 19 Jul 2013 21:43:38 +0200
schrieb Johannes Pfau <nospam example.com>:

 Am Fri, 19 Jul 2013 12:38:45 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:
 
 Would be nice to know if this is working with gdc or ldc. In theory it
 should work as we use gcc's exception handling/stack unwinding so it's
 probably a dmd bug.
That's good to know. Is it possible to port that code into DMD ? How many C libraries do you think are prepared for exceptions ? They might have to clean up memory or system resources.
 Slightly off topic, but maybe interesting:
 Things can get really nasty if the GCC backend somehow decided
 a function is nothrow and you throw from there. Unless GTK uses some
 special __nothrow__ attributes that shouldn't happen in C, but I've seen
 D code that throws from  nothrow functions and at least on ARM that
 crashes... Might be a gdc bug or a problem with the D language
 specification.
If with nothrow you mean the nothrow keyword, it has no value for compiler backends, because assert errors can be thrown anyways. But I probably misunderstood you. -- Marco
Jul 22 2013
parent Johannes Pfau <nospam example.com> writes:
Am Mon, 22 Jul 2013 19:28:10 +0200
schrieb Marco Leise <Marco.Leise gmx.de>:

 Am Fri, 19 Jul 2013 21:43:38 +0200
 schrieb Johannes Pfau <nospam example.com>:
 
 Am Fri, 19 Jul 2013 12:38:45 +0200
 schrieb Marco Leise <Marco.Leise gmx.de>:
 
 Would be nice to know if this is working with gdc or ldc. In theory
 it should work as we use gcc's exception handling/stack unwinding
 so it's probably a dmd bug.
That's good to know. Is it possible to port that code into DMD ?
Probably not. It's implemented in libgcc and I don't know if it's tied to the compiler code gen. Porting is probably not possible because of the license. GCC's exception handling also has its own problems: For example we don't implement exception chaining right now. I just had another look at this and my last statement was not 100% accurate. GCC uses unwind tables instead of frame pointers so it can indeed work without frame pointers. But for C unwind tables are not generated by default unless -fexceptions is used. Interestingly enough it always worked for me ;-)
 How many C libraries do you think are prepared for
 exceptions ? They might have to clean up memory or system
 resources.
Probably very few. I was only talking from the compiler/codegen point of view but any C library that doesn't explicitly allow throwing exceptions probably won't work.
 
 
 If with  nothrow you mean the nothrow keyword, it has no value
 for compiler backends, because assert errors can be thrown
 anyways. But I probably misunderstood you.
Yeah well that's the general perception in the D community. But we need an authoritative statement here. According to TDPL, chapter 9.4 page 307: "Essentially Throwable is considered unrecoverable, so the compiler is relieved of the responsibility of "thinking" of what should happen in case of an exception and consequently _optimizes code under the assumption that nothing is thrown_." That's probably why Iain implemented it so that we directly map nothrow to gcc attribute(__nothrow__). However, I think this statement is supposed to talk about skipping destructors not necessarily unwinding. I don't really have a strong opinion here but according to Walter the backend can optimize quite a lot if it knows for sure that a function can't throw. As asserts can be optimized away anyway it might be useful to rewrite throw(Error) statements in nothrow functions to simply dump a stack trace and message to the console instead of proper exception handling. But as I said I don't have a string opinion here.
Jul 23 2013