GNOME Bugzilla – Bug 145571
sigc::connection::disconnect() causes crash
Last modified: 2004-12-22 21:47:04 UTC
I've recently ported an application to gtkmm 2.4 from gtkmm 2.2 and have started experiencing crashes in the preferences window in the code that let users choose keyboard keys. The idea in that code is to use Gtk::Buttons to represent keys - when a button is pressed, the focus is grabbed until a new key is pressed which then replaces the contents of the button. More specifically, I connect a handler to the clicked signal of a button. That handler clears the text of the button, adds a modal grab and installs a callback on the signal_key_press_event(), saving the sigc::connection. The callback then removes the modal grab, calls the disconnect() method on the saved connection and puts a textual representation of the pressed key inside the button (so it is a one-shot callback). The problem is that the above has stopped working in gtkmm 2.4 - instead it seems to cause memory corruption. The attached test program shows this. I had to allocate the button dynamically for the error to show up. Compile it with g++ base.cc -o base -g -Wall `pkg-config --libs --cflags gtkmm-2.4` run it with ./base and it crashes horribly. This is with gtkmm-2.4.4 and sigc++-2.0.3 on Debian unstable. I have no idea where the problem is. The backtrace is pretty boring: (gdb) run Starting program: /home/ole/tmp/base Button clicked Key event cb Program received signal SIGSEGV, Segmentation fault. 0x40666bd3 in sigc::slot_base::~slot_base () from /usr/lib/libsigc-2.0.so.0 (gdb) bt
+ Trace 47341
Created attachment 29319 [details] Test case that crashes
I can't reproduce the crash on debian testing, either with my built-from-source gtkmm, or with the libsigc++ 2.0.3 and gtkmm 2.4.2 debian packages that are in testing. I have tried clicking on the button and pressing keys. I guess it crashes for you whe you press a key. Valgrind also did not show anything interesting. Did you build libsigc++, glibmm, and gtkmm from source, or are you using the debian packages. If you built them from source, did you rebuild glibmm and gtkmm after you updated libsigc++? (an earlier version of libsigc++ 2.0.x was very broken) Or, can you tell us more about your architecture? Is this a regular x86 PC?
I'm using the Debian unstable packages on a Pentium III. The crash occurs if you start the program and press enter a couple of times (say four or five).
I didn't think of running it inside Valgrind. Good idea. Now it does not actually crash, but instead I get this when I hit enter twice: button_clicked key_event_cb ==2884== ==2884== Invalid read of size 4 ==2884== at 0x3C65FD6A: Glib::SignalProxyConnectionNode::destroy_notify_handler(void*, _GClosure*) (in /usr/lib/libglibmm-2.4.so.1.0.3) ==2884== by 0x3C779274: (within /usr/lib/libgobject-2.0.so.0.400.2) ==2884== by 0x3C77868D: g_closure_unref (in /usr/lib/libgobject-2.0.so.0.400.2) ==2884== by 0x3C78E50C: (within /usr/lib/libgobject-2.0.so.0.400.2) ==2884== Address 0x3D037A30 is 12 bytes inside a block of size 16 free'd ==2884== at 0x3C01FA3C: operator delete(void*) (vg_replace_malloc.c:129) ==2884== by 0x3C65FD34: Glib::SignalProxyConnectionNode::notify(void*) (in /usr/lib/libglibmm-2.4.so.1.0.3) ==2884== by 0x3C67C9E7: sigc::internal::slot_rep::disconnect() (in /usr/lib/libsigc-2.0.so.0.0.0) ==2884== by 0x3C67CDFB: sigc::slot_base::disconnect() (in /usr/lib/libsigc-2.0.so.0.0.0)
> The crash occurs if you start the program and press enter a couple of times (say four or five) Now, I see what you mean. Strangely, it crashes for me in my built-from-source environment, but not when I'm using the debian packages (all unstable + the gtkmm package from testing).
Created attachment 29377 [details] test_simpler.cc Here (test_simpler.cc) is a simpler test case. Even if it doesn't crash, it shows the error in valgrind, and that's what we need to deal with.
The valgrind output: ==29323== ==29323== Invalid read of size 4 ==29323== at 0x3C643D9A: Glib::SignalProxyConnectionNode::destroy_notify_handler(void*, _GClosure*) (signalproxy_connectionnode.cc:73) ==29323== by 0x3C75B984: closure_invoke_notifiers (gclosure.c:109) ==29323== by 0x3C75AD9D: g_closure_unref (gclosure.c:347) ==29323== by 0x3C770C1C: handler_unref_R (gsignal.c:590) ==29323== by 0x3C76EFF4: signal_emit_unlocked_R (gsignal.c:2567) ==29323== by 0x3C76E326: g_signal_emit_valist (gsignal.c:2195) ==29323== by 0x3C76E623: g_signal_emit (gsignal.c:2239) ==29323== by 0x3C3818B4: gtk_button_clicked (gtkbutton.c:719) ==29323== by 0x3C3828CA: gtk_real_button_released (gtkbutton.c:1220) ==29323== by 0x3C14F358: Gtk::Button_Class::released_callback(_GtkButton*) (button.cc:219) ==29323== by 0x3C76F860: g_cclosure_marshal_VOID__VOID (gmarshal.c:77) ==29323== by 0x3C75B6C6: g_type_class_meta_marshal (gclosure.c:514) ==29323== by 0x3C75B32F: g_closure_invoke (gclosure.c:437) ==29323== by 0x3C76EB8D: signal_emit_unlocked_R (gsignal.c:2366) ==29323== by 0x3C76E326: g_signal_emit_valist (gsignal.c:2195) ==29323== by 0x3C76E623: g_signal_emit (gsignal.c:2239) ==29323== by 0x3C381804: gtk_button_released (gtkbutton.c:711) ==29323== by 0x3C38274A: gtk_button_button_release (gtkbutton.c:1136) ==29323== by 0x3C1F5371: Gtk::Widget_Class::button_release_event_callback(_GtkWidget*, _GdkEventButton*) (widget.cc:3798) ==29323== by 0x3C43D603: _gtk_marshal_BOOLEAN__BOXED (gtkmarshalers.c:82) ==29323== Address 0x3CFC8D70 is 12 bytes inside a block of size 16 free'd ==29323== at 0x3C01FA3C: operator delete(void*) (vg_replace_malloc.c:129) ==29323== by 0x3C643D64: Glib::SignalProxyConnectionNode::notify(void*) (signalproxy_connectionnode.cc:60) ==29323== by 0x3C661A77: sigc::internal::slot_rep::disconnect() (slot_base.cc:37) ==29323== by 0x3C661E8B: sigc::slot_base::disconnect() (slot_base.cc:142) ==29323== by 0x3C6619AB: sigc::connection::disconnect() (connection.cc:83) ==29323== by 0x804DDE6: Test::button_clicked() (in /home/murrayc/a.out) ==29323== by 0x804E3C8: sigc::bound_mem_functor0<void, Test>::operator()() const (in /home/murrayc/a.out) ==29323== by 0x804E253: sigc::adaptor_functor<sigc::bound_mem_functor0<void, Test> >::operator()() const (in /home/murrayc/a.out) ==29323== by 0x804E23D: sigc::internal::slot_call0<sigc::bound_mem_functor0<void, Test>, void>::call_it(sigc::internal::slot_rep*) (in /home/murrayc/a.out) ==29323== by 0x3C643BDC: Glib::SignalProxyNormal::slot0_void_callback(_GObject*, void*) (slot.h:426) ==29323== by 0x3C76F860: g_cclosure_marshal_VOID__VOID (gmarshal.c:77) ==29323== by 0x3C75B32F: g_closure_invoke (gclosure.c:437) ==29323== by 0x3C76F1E4: signal_emit_unlocked_R (gsignal.c:2506) ==29323== by 0x3C76E326: g_signal_emit_valist (gsignal.c:2195) ==29323== by 0x3C76E623: g_signal_emit (gsignal.c:2239) ==29323== by 0x3C3818B4: gtk_button_clicked (gtkbutton.c:719) ==29323== by 0x3C3828CA: gtk_real_button_released (gtkbutton.c:1220) ==29323== by 0x3C14F358: Gtk::Button_Class::released_callback(_GtkButton*) (button.cc:219) ==29323== by 0x3C76F860: g_cclosure_marshal_VOID__VOID (gmarshal.c:77) ==29323== by 0x3C75B6C6: g_type_class_meta_marshal (gclosure.c:514)
This might be caused by the fact that destroy_notify callbacks are not called during GTK+ signal disconnection if the callback is running - destroy_notify callbacks are then called after the callback has returned. I'm working on a patch.
I think I have fixed this in cvs - now we always let the ConnectionNode be deleted in destroy_notify, because that is always called. I can't find any leaks caused by this. Thanks a lot for the test case.