Re: [sigc] SEGV while using libsigc++ in an apparently legit way



On Thu, 2005-03-03 at 11:40 -0800, R�s 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,
[murrayc murrayclaptop ~]$ 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> (_A_action= 0xbfffcd04,
>      _A_functor= 0x100e3740) 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> (_A_action= 0xbfffcd04,
>      _A_target= 0x100e3740) 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> > 
> (_A_action= 0xbfffcd04, _A_target= 0x80a6998) 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> > > (
>      _A_action= 0x100e3740, _A_functor= 0x80a6998) 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
murrayc murrayc com
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;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]