[gtkmm] Possible bug in SigC::Connection::disconnect()



I think I've encountered a possible bug with the disconnect() method of
SigC::Connection (after several days of headscratching :-) ) To me it
seems like disconnect() doesn't clean up properly, and causes future
emit()'s on the given signal to make valgrind spew out memory-errors --
at best, or, worse, which happened in my case under some circumstances,
results in a crash (segfault).

Below is the output from valgrind on the test-app involved. No errors
are issued when NO_WEIRD_BEHAVIOUR is defined (removing the disconnect()
call).

At the bottom is sourcecode for the test-app.

Ole André


==669== Memcheck, a.k.a. Valgrind, a memory error detector for
x86-linux.
==669== Copyright (C) 2002-2003, and GNU GPL'd, by Julian Seward.
==669== Using valgrind-2.0.0, a program supervision framework for
x86-linux.
==669== Copyright (C) 2000-2003, and GNU GPL'd, by Julian Seward.
==669== Estimated CPU clock rate is 2853 MHz
==669== For more details, rerun with: -v
==669== 
connected
send_cmd: sending 'hello'
recv_line: odd reply
handle_reply_a: odd reply
send_cmd: sending 'user'
handle_reply_b: odd reply
send_cmd: sending 'pass'
handle_reply_c: odd reply
recv_line: odd reply
==669== Invalid read of size 1
==669==    at 0x804A558: SigC::ConnectionNode::blocked() const (in
/home/zole/testapp/a.out)
==669==    by 0x8049DC7: SigC::Signal1<void, std::string,
SigC::Marshal<void> >::emit(std::string const&) (in
/home/zole/testapp/a.out)
==669==    by 0x80499EA: client::recv_idler() (in
/home/zole/testapp/a.out)
==669==    by 0x804A2BF: SigC::ObjectSlot0_<bool, client>::proxy(void*)
(in /home/zole/testapp/a.out)
==669==    Address 0x415756A4 is 8 bytes inside a block of size 36
free'd
==669==    at 0x40028DED: __builtin_delete (in
/usr/lib/valgrind/vgskin_memcheck.so)
==669==    by 0x40028E18: operator delete(void*) (in
/usr/lib/valgrind/vgskin_memcheck.so)
==669==    by 0x402C7556:
SigC::SignalConnectionNode::~SignalConnectionNode() (in
/usr/lib/libsigc-1.2.so.5.0.5)
==669==    by 0x402C715E: SigC::SignalNode::cleanup() (in
/usr/lib/libsigc-1.2.so.5.0.5)
==669== 
==669== Invalid read of size 4
==669==    at 0x804A3FE: SigC::Signal1<void, std::string,
SigC::Marshal<void> >::emit_(std::string const&, void*) (in
/home/zole/testapp/a.out)
==669==    by 0x8049DC7: SigC::Signal1<void, std::string,
SigC::Marshal<void> >::emit(std::string const&) (in
/home/zole/testapp/a.out)
==669==    by 0x80499EA: client::recv_idler() (in
/home/zole/testapp/a.out)
==669==    by 0x804A2BF: SigC::ObjectSlot0_<bool, client>::proxy(void*)
(in /home/zole/testapp/a.out)
==669==    Address 0x415756B8 is 28 bytes inside a block of size 36
free'd
==669==    at 0x40028DED: __builtin_delete (in
/usr/lib/valgrind/vgskin_memcheck.so)
==669==    by 0x40028E18: operator delete(void*) (in
/usr/lib/valgrind/vgskin_memcheck.so)
==669==    by 0x402C7556:
SigC::SignalConnectionNode::~SignalConnectionNode() (in
/usr/lib/libsigc-1.2.so.5.0.5)
==669==    by 0x402C715E: SigC::SignalNode::cleanup() (in
/usr/lib/libsigc-1.2.so.5.0.5)
handle_reply_c: odd reply
recv_line: odd reply
(...)


/*
 * "Simple" test-case to trigger a possible
SigC::Connection::disconnect() bug
 *
 * Compile with:
 *   g++ $(pkg-config --cflags --libs glibmm-2.0) -Wall
disconnect_bug.cpp -o disconnect_bug
 *
 * Run through valgrind to see the errors reported (which,
unfortunately,
 * doesn't make this simple app crash).
 *
 * Compile with DONT_WANT_WEIRD_BEHAVIOUR defined, run through valgrind
once
 * again and just watch the errors disappear.
 */

#include <iostream>
#include <string>
#include <sigc++/sigc++.h>
#include <glibmm.h>

using std::cout;
using std::endl;
using std::string;

class client : public SigC::Object {
public:
	client() {}
	~client() {}
	
	void connect();
	
	SigC::Signal1<void, string> recv_message;
private:
	SigC::Connection handler_conn;

	void send_cmd(string c, SigC::Slot1<void, string> handler);
	
	void handle_reply_a(string r);
	void handle_reply_b(string r);
	void handle_reply_c(string r);

	bool recv_idler();
};

void client::connect()
{
	cout << "connected" << endl;

	Glib::signal_idle().connect(SigC::slot(*this, &client::recv_idler));

	send_cmd("hello", SigC::slot(*this, &client::handle_reply_a));
}

void client::send_cmd(string c, SigC::Slot1<void, string> handler)
{
	cout << "send_cmd: sending '" << c << "'" << endl;

#ifndef NO_WEIRD_BEHAVIOUR
	if (handler_conn.connected())
		handler_conn.disconnect();
#endif
	
	handler_conn = recv_message.connect(handler);
}

void client::handle_reply_a(string r)
{
	cout << "handle_reply_a: " << r << endl;

	send_cmd("user", SigC::slot(*this, &client::handle_reply_b));
}

void client::handle_reply_b(string r)
{
	cout << "handle_reply_b: " << r << endl;
	
	send_cmd("pass", SigC::slot(*this, &client::handle_reply_c));
}

void client::handle_reply_c(string r)
{
	cout << "handle_reply_c: " << r << endl;
}

bool client::recv_idler()
{
	sleep(1);
	
	recv_message.emit("odd reply");

	return true;
}

void recv_line(string s)
{
	cout << "recv_line: " << s << endl;
}

int main(int argc, char *argv[])
{
	client c;
	Glib::RefPtr<Glib::MainLoop> loop = Glib::MainLoop::create();

	c.recv_message.connect(SigC::slot(recv_line));

	c.connect();

	loop->run();

	return 0;
}





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