[sigc] notify_callbacks problem?



  I've turned up a rather obscure way to cause memory corruption using 
libsigc++.  (the attached program crashes, but I originally only found the 
bug through valgrind)  Here's a short description:

  (1) Create a signal
  (2) Attach two callbacks holding references to the same trackable
      instance to this signal.  One of these callbacks should bind a
      value whose deletion triggers the clearing or deletion of the
      signal.
  (3) Delete the instance.

  What happens at step (3) is roughly:

  (a) The first attached callback is deleted from the signal.  The bound value
      is deleted, causing the signal to be cleared (all callbacks attached to
      it are deleted).
  (b) The second attached callback is deleted......oops.  If executed before
      (a), this simply seems to crash the program; otherwise it double-frees.

  Note that I am NOT deleting a signal while it's being emitted (which 
obviously is not a good idea); the problem occurs when you delete an object 
that has several callbacks connected to a single signal.

  On the one hand, I can see this being a weird corner case and maybe even an 
abuse of the library; on the other hand, if you have values that represent
counted references to objects (i.e., deleting them decrements a reference 
count), binding them as signal arguments seems like a logical way of ensuring 
that they don't die before the connection -- assuming, of course, that you 
avoid creating cycles.

  I've attached a stripped-down example case that illustrates what I'm talking 
about.  If this is an expected problem, I guess I can design around it.

  Daniel

-- 
/------------------- Daniel Burrows <dburrows debian org> ------------------\
|     Corporation: An ingenious device for obtaining individual profit      |
|                  without individual responsibility.                       |
|        -- Ambrose Bierce (1842-1914), "The Devil's Dictionary", 1911      |
\---------------- The Turtle Moves! -- http://www.lspace.org ---------------/
#include <sigc++/signal.h>
#include <sigc++/adaptors/bind.h>
#include <sigc++/functors/mem_fun.h>
#include <sigc++/trackable.h>

#include <iostream>

using namespace std;

class sillier;

class silly : virtual public sigc::trackable
{
  int a;
public:
  silly(int aInit) : a(aInit)
  {
  }

  void blah(sillier &)
  {
  }

  void foo()
  {
    cout << a << endl;
  }
};

class sillier
{
  sigc::signal0<void> &s;
public:
  sillier(sigc::signal0<void> &sInit) : s(sInit)
  {
  }

  ~sillier()
  {
    s.clear();
  }
};

int main(int argc, char **argv)
{
  sigc::signal0<void> some_signal;

  silly * s = new silly(5);

  sillier u(some_signal);

  some_signal.connect(sigc::mem_fun(*s, &silly::foo));
  some_signal.connect(sigc::bind(sigc::mem_fun(*s, &silly::blah),
				 u));

  some_signal();

  delete s;

  return 0;
}

Attachment: pgpUgxs8WFeNS.pgp
Description: PGP signature



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