On Thu, 2005-03-03 at 11:40 -0800, RÃgis Duchesne wrote: > Folks, > > I'm reporting this issue both to the GCC people and the libsigc++ > people, because the issue could be in either of them or both. On the > surface, it looks like a g++ issue, but when you look deeper, libsigc++ > might be relying on a behavior that is unspecified by any C++ standard. > > Input > ----- > File test1.cc is attached.
A simplified test case is attached. It does not need 3 base classes to crash. However, we'd rather have a libsigc++-only test case rather than one that uses gtkmm too, and the g++ developers would want one that did not involve even libsigc++. > Command line > ------------ > g++ -v -save-temps -O -g `pkg-config --cflags --libs gtkmm-2.4` test1.cc > -o test1 I left out the "-v -save-temps -O -g". They aren't necessary to make it crash. [snip] > o Binary output > When running the binary, a window pops up on the screen. In that window, > there is a button. Click on the button. The binary gets a SEGV. This is > the issue. > > Why it could be a g++ issue > --------------------------- > If you remove -O from the command line, then the binary does not get a > SEGV, which is the expected behavior. It segfaults for me, on Fedora Core 3, [EMAIL PROTECTED] ~]$ g++ --version g++ (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3) The valgrind output is attached, from after pressing the Discard button. I used valgrind --tool=memcheck --num-callers=20 ./a.out > Why it could be a libsigc++ issue > --------------------------------- > o Here is the relevant backtrace at the time of the SEGV > > #0 0x406730f2 in sigc::trackable::callback_list () > from /usr/lib/libsigc-2.0.so.0 > #1 0x4067306f in sigc::trackable::remove_destroy_notify_callback () > from /usr/lib/libsigc-2.0.so.0 > #2 0x0804d253 in > sigc::visit_each<sigc::internal::limit_derived_target<sigc::trackable*, > sigc::internal::slot_do_unbind>, Dlg> ([EMAIL PROTECTED], > [EMAIL PROTECTED]) at slot_base.h:166 > #3 0x0804d216 in > sigc::visit_each<sigc::internal::limit_derived_target<sigc::trackable*, > sigc::internal::slot_do_unbind>, void, Dlg> ([EMAIL PROTECTED], > [EMAIL PROTECTED]) at mem_fun.h:1798 > #4 0x0804d1df in > sigc::visit_each<sigc::internal::limit_derived_target<sigc::trackable*, > sigc::internal::slot_do_unbind>, sigc::bound_mem_functor0<void, Dlg> > > ([EMAIL PROTECTED], [EMAIL PROTECTED]) at adaptor_trait.h:264 > #5 0x0804cec0 in sigc::visit_each_type<sigc::trackable*, > sigc::internal::slot_do_unbind, > sigc::adaptor_functor<sigc::bound_mem_functor0<void, Dlg> > > ( > [EMAIL PROTECTED], [EMAIL PROTECTED]) at visit_each.h:124 > #6 0x0804ce9d in > sigc::internal::typed_slot_rep<sigc::bound_mem_functor0<void, Dlg> > >::destroy (data=0x100e3740) at slot_base.h:160 > #7 0x40673a45 in sigc::internal::slot_rep::notify () > from /usr/lib/libsigc-2.0.so.0 > #8 0x4067323b in > sigc::internal::trackable_callback_list::~trackable_callback_list () > from /usr/lib/libsigc-2.0.so.0 > #9 0x406730ce in sigc::trackable::notify_callbacks () > from /usr/lib/libsigc-2.0.so.0 > #10 0x40672fcf in sigc::trackable::~trackable () from > /usr/lib/libsigc-2.0.so.0 > #11 0x0804d0b6 in ~Dlg (this=0x8097288) at test1.cc:14 > #12 0x0804d1c2 in Dlg::OnClicked (this=0xbfffcd04) at test1.cc:34 > #13 0x0804cfd4 in sigc::adaptor_functor<sigc::bound_mem_functor0<void, > Dlg> >::operator() (this=0xbfffcd04) at mem_fun.h:1781 > #14 0x0804cf9a in > sigc::internal::slot_call0<sigc::bound_mem_functor0<void, Dlg>, > void>::call_it (rep=0x80a6980) at slot.h:103 > #15 0x4065a44d in Glib::SignalProxyNormal::slot0_void_callback () > from /usr/lib/libglibmm-2.4.so.1 > ... > > o Explanation of the backtrace > > Essentially, we are inside the invokation of the sigc::mem_fun(this, > &Dlg::OnClicked) slot (frame 14) when we are deleting the Dlg instance > (frame 11). Destroying the Dlg instance destroys the button, but the > destruction of the sigc::mem_fun(this, &Dlg::OnClicked) slot is delayed > because we are in the middle of invoking it. Once the Dlg destructor has > finished, the sigc::trackable destructor is called (frame 10) because > Dlg inherits from Gtk::Window, which inherits from trackable. Because > the trackable is going away, it notifies all interested parties (frame > 8). One such party happens to be the sigc::mem_fun(this, > &Dlg::OnClicked) slot itself (frame 7), and in response to that > notification, the slot is telling all the trackables it is bound to that > it doesn't want to be notified by them anymore (frame 2). One such > trackable is the Dlg instance itself. But the first time the address of > the trackable is dereferenced (frame 0), the binary gets a SEGV because > it is dereferencing an invalid pointer in file trackable.cc: > > internal::trackable_callback_list* trackable::callback_list() const > { > if (!callback_list_) <--- *** SEGV occurs here ***--- > callback_list_ = new internal::trackable_callback_list; > > return callback_list_; > } > > o Possible explanation for the SEGV > > It seems that the address of the trackable is coming from this snippet > in visit_each.h: > > template <class T_type> struct with_type<true,T_type> > { static void execute_(const T_type& _A_type, const T_self& _A_action) > { _A_action.action_(&_A_type); } <--- Here > }; > > At that very moment, the type of '_A_type' is 'Dlg' as shown in frame 2, > and libsigc++ is trying to obtain a sigc::trackable pointer from it > by using the '&' operator. Apparently, because the 'Dlg' facet of the > object is already gone (we are in frames < 11), this confuses g++ big > time and the '&' operator returns an invalid value. Note that Dlg > inherits _virtually_ from Foo. It might be the cause of g++'s confusion. > > Conclusion > ---------- > We don't know if there is a bug in the g++ optimizer, or if what > libsigc++ is doing is unspecified by C++ standards. This probably belongs in bugzilla, where it can be explored more. You should give full details about your platform there. Sorry for not being more knowledgeable. -- Murray Cumming [EMAIL PROTECTED] www.murrayc.com www.openismus.com
#include <gtkmm.h> class Bar { public: virtual ~Bar() { } }; class Dlg : public Bar, public Gtk::Window { public: Dlg() { Gtk::Button *button = new Gtk::Button("Discard"); button->show(); add(*Gtk::manage(button)); button->signal_clicked().connect(sigc::mem_fun(this, &Dlg::OnClicked)); } private: void OnClicked() { delete this; } }; int main(int argc, char *argv[]) { Gtk::Main kit(argc, argv); Dlg *toplevel = new Dlg(); toplevel->show(); kit.run(); return 0; }
_______________________________________________ libsigc-list mailing list libsigc-list@gnome.org http://mail.gnome.org/mailman/listinfo/libsigc-list