GNOME Bugzilla – Bug 642203
Gtk::Builder & sigc::bind interaction around actions causes crash in dtor
Last modified: 2011-03-30 09:39:35 UTC
Created attachment 180752 [details] testcase; see description for compile command line & valgrind options The circumstances are rather specific, so please bear with me here: Binding a RefPtr <ToggleAction> to the signal handler for the SlotActivate for an action in an actiongroup which gets added to a widget created by Gtk::Builder will result in a crash in the dtor for the containing widget. More verbosely: 1. I create a Gtk::ToggleAction and add it to a Gtk::ActionGroup, using sigc::bind to arrange to pass the RefPtr for the action as an argument to the handler, like so: actiongp->add (action, sigc::bind <const char *, Glib::RefPtr <Gtk::ToggleAction> > (sigc::mem_fun (*this, actionfunc), name, action)); 2. I use Gtk::UIManager to create a menubar referencing this action, and add that menubar to a widget created by Gtk::Builder. 3. I crash in the dtor for the top-level widget, apparently because (according to Valgrind) sigc is reading memory inside a block it had previously freed. See valgrind output quoted below for the attached testcase. 4. If I remove the menubar from the widget before reaching the end of the explicit code for my dtor, then all is well (as long as I don't delete the menubar). See attached testcase for details. It's fairly short (188 lines). Valgrind 3.6.0 on Ubuntu 10.10 (I love Valgrind) says: ==27508== Invalid read of size 8 ==27508== at 0x68DD050: sigc::internal::slot_rep::disconnect() (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x68DD0AE: sigc::internal::slot_rep::notify(void*) (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x68DCB9E: sigc::internal::trackable_callback_list::~trackable_callback_list() (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x68DCC80: sigc::trackable::notify_callbacks() (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x407145: MyWin::~MyWin() (problem-110212.cpp:172) ==27508== by 0x405DEE: main (problem-110212.cpp:185) ==27508== Address 0xce1fe88 is 40 bytes inside a block of size 112 free'd ==27508== at 0x4C27A83: operator delete(void*) (vg_replace_malloc.c:387) ==27508== by 0x649CD09: Glib::SignalProxyConnectionNode::destroy_notify_handler(void*, _GClosure*) (in /usr/lib/libglibmm-2.4.so.1.3.0) ==27508== by 0x85005AA: g_closure_unref (in /usr/lib/libgobject-2.0.so.0.2600.0) ==27508== by 0x85156CC: g_signal_handlers_destroy (in /usr/lib/libgobject-2.0.so.0.2600.0) ==27508== by 0x850282C: ??? (in /usr/lib/libgobject-2.0.so.0.2600.0) ==27508== by 0x8502999: g_object_unref (in /usr/lib/libgobject-2.0.so.0.2600.0) ==27508== by 0x4071E2: Glib::RefPtr<Gtk::ToggleAction>::~RefPtr() (refptr.h:184) ==27508== by 0x4060EB: sigc::bound_argument<Glib::RefPtr<Gtk::ToggleAction> >::~bound_argument() (bound_argument.h:51) ==27508== by 0x406109: sigc::bind_functor<-1, sigc::bound_mem_functor2<void, MyWin, char const*, Glib::RefPtr<Gtk::ToggleAction> >, char const*, Glib::RefPtr<Gtk::ToggleAction>, sigc::nil, sigc::nil, sigc::nil, sigc::nil, sigc::nil>::~bind_functor() (bind.h:136) ==27508== by 0x407A33: sigc::internal::typed_slot_rep<sigc::bind_functor<-1, sigc::bound_mem_functor2<void, MyWin, char const*, Glib::RefPtr<Gtk::ToggleAction> >, char const*, Glib::RefPtr<Gtk::ToggleAction>, sigc::nil, sigc::nil, sigc::nil, sigc::nil, sigc::nil> >::destroy(void*) (slot.h:61) ==27508== by 0x68DD0A6: sigc::internal::slot_rep::notify(void*) (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x68DCB9E: sigc::internal::trackable_callback_list::~trackable_callback_list() (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x68DCC80: sigc::trackable::notify_callbacks() (in /usr/lib/libsigc-2.0.so.0.0.0) ==27508== by 0x407145: MyWin::~MyWin() (problem-110212.cpp:172) ==27508== by 0x405DEE: main (problem-110212.cpp:185) To compile & run under valgrind: g++ -ggdb3 -pthread -o problem-110212 problem-110212.cpp `pkg-config --cflags --libs gtkmm-2.4` && valgrind --read-var-info=yes --tool=memcheck --num-callers=50 ./problem-110212
I suggest that this bug is made a duplicate of bug 564005. Copied from bug 564005 comment 8: What makes the test case special is that 'action' has two roles: 1. It's the receiver of signal_activate. 2. It's bound to a slot which is connected to the signal. In this case the trouble is caused by the double use of 'action' in actiongp->add (action, sigc::bind <const char *, Glib::RefPtr <Gtk::ToggleAction> > (sigc::mem_fun (*this, actionfunc), name, action)); If another ToggleAction instance, or no ToggleAction instance, is bound then valgrind does not complain. When the statement top_vbox->remove (*menubar); in MyWin::~MyWin() is activated, valgrind does not report errors, but gdb shows that menubar is not deleted. (MenuBar::~MenuBar is not called.) Strange though that valgrind does not report more leaked memory in this case.
(In reply to comment #1) > I suggest that this bug is made a duplicate of bug 564005. Agreed, it does appear to be the same issue.
(In reply to comment #2) > (In reply to comment #1) > > I suggest that this bug is made a duplicate of bug 564005. > > Agreed, it does appear to be the same issue. Can't you as the reporter of this bug mark it as a duplicate yourself? Concerning your question in bug 564005 comment 9 (Any hope of a fix?), my guess is that it can take a long long time. There is also the glibmm bug 154498, filed in the year 2004, probably describing the same error. The error is most probably in libsigc++. It is a fairly small module, but it's tricky.
*** This bug has been marked as a duplicate of bug 564005 ***