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



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.

Command line
------------
g++ -v -save-temps -O -g `pkg-config --cflags --libs gtkmm-2.4` test1.cc -o test1

Where `pkg-config --cflags --libs gtkmm-2.4` expands to:
-DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API -I/usr/include/gtkmm-2.4 -I/usr/lib/gtkmm-2.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/gdkmm-2.4 -I/usr/lib/gdkmm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/include/atkmm-1.6 -I/usr/include/gtk-2.0 -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/include/atk-1.0 -Wl,--export-dynamic -lgtkmm-2.4 -lgdkmm-2.4 -latkmm-1.6 -lgtk-x11-2.0 -lpangomm-1.4 -lglibmm-2.4 -lsigc-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0

Command line output
-------------------
o TTY output:
Reading specs from /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/specs
Configured with: ../gcc-3.3.4/configure --prefix=/usr --enable-shared --enable-threads=posix --enable-__cxa_atexit --disable-checking --with-gnu-ld --verbose --target=i486-slackware-linux --host=i486-slackware-linux
Thread model: posix
gcc version 3.3.4
/usr/lib/gcc-lib/i486-slackware-linux/3.3.4/cc1plus -E -D__GNUG__=3 -quiet -v -I/usr/include/gtkmm-2.4 -I/usr/lib/gtkmm-2.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/glibmm-2.4/include -I/usr/include/gdkmm-2.4 -I/usr/lib/gdkmm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/include/atkmm-1.6 -I/usr/include/gtk-2.0 -I/usr/include/sigc++-2.0 -I/usr/lib/sigc++-2.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/lib/gtk-2.0/include -I/usr/X11R6/include -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/include/freetype2/config -I/usr/include/atk-1.0 -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=4 -D_GNU_SOURCE -DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API test1.cc -O test1.ii
ignoring nonexistent directory "/usr/include/freetype2/config"
ignoring nonexistent directory "/usr/i486-slackware-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/include/gtkmm-2.4
 /usr/lib/gtkmm-2.4/include
 /usr/include/glibmm-2.4
 /usr/lib/glibmm-2.4/include
 /usr/include/gdkmm-2.4
 /usr/lib/gdkmm-2.4/include
 /usr/include/pangomm-1.4
 /usr/include/atkmm-1.6
 /usr/include/gtk-2.0
 /usr/include/sigc++-2.0
 /usr/lib/sigc++-2.0/include
 /usr/include/glib-2.0
 /usr/lib/glib-2.0/include
 /usr/lib/gtk-2.0/include
 /usr/X11R6/include
 /usr/include/pango-1.0
 /usr/include/freetype2
 /usr/include/atk-1.0
 /usr/lib/qt/include
 /usr/include/c++/3.3.4
 /usr/include/c++/3.3.4/i486-slackware-linux
 /usr/include/c++/3.3.4/backward
 /usr/local/include
 /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/include
 /usr/include
End of search list.
/usr/lib/gcc-lib/i486-slackware-linux/3.3.4/cc1plus -fpreprocessed test1.ii -quiet -dumpbase test1.cc -auxbase test1 -g -O -version -o test1.s
GNU C++ version 3.3.4 (i486-slackware-linux)
        compiled by GNU C version 3.3.4.
GGC heuristics: --param ggc-min-expand=90 --param ggc-min-heapsize=113063
usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../../../i486-slackware-linux/bin/as -V -Qy -o test1.o test1.s GNU assembler version 2.15.92.0.2 (i486-slackware-linux) using BFD version 2.15.92.0.2 20040927 /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test1 /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../../crt1.o /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../../crti.o /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/crtbegin.o -L/usr/lib/gcc-lib/i486-slackware-linux/3.3.4 -L/usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../../../i486-slackware-linux/lib -L/usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../.. --export-dynamic -lgtkmm-2.4 -lgdkmm-2.4 -latkmm-1.6 -lgtk-x11-2.0 -lpangomm-1.4 -lglibmm-2.4 -lsigc-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0 test1.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/crtend.o /usr/lib/gcc-lib/i486-slackware-linux/3.3.4/../../../crtn.o

o Pre-processed file output
A compressed (bzip2 -9) version of file test1.ii is attached.

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.

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.

Thanks,
--
Regis "HPReg" Duchesne
VMware, Inc.
#include <gtkmm/main.h>
#include <gtkmm/window.h>
#include <gtkmm/button.h>

class Foo
{
};

class Bar
{
public:
   virtual ~Bar()
   {
   }
};

class Dlg
   : virtual public Foo,
     public Bar,
     public Gtk::Window
{
public:
   Dlg(void)
   {
      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(void)
   {
      delete this;
   }
};

int main(int argc, char *argv[])
{
   Gtk::Main kit(argc, argv);

   Dlg *toplevel = new Dlg();
   toplevel->show();

   kit.run();

   return 0;
}

Attachment: test1.ii.bz2
Description: application/bzip



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