Search code examples
c++glibgiolibsigc++glibmm

Why does signal connection invalidate the SocketClient object?


I am trying to make a TCP / TLS connection with the SocketClient class from Gio via giomm.

Everything was fine, until I connected to the SocketClient::event_signal () signal with sigc::ptr_fun ().

Here is a trimmed down example code that demonstrates the problem:

#include <giomm/error.h>
#include <giomm/init.h>
#include <giomm/networkaddress.h>
#include <giomm/socketclient.h>
#include <glibmm/main.h>
#include <iostream>

void socket_client_event (Gio::SocketClientEvent event,
              const Glib::RefPtr<Gio::SocketConnectable> &connectable,
              const Glib::RefPtr<Gio::IOStream> &connection) {
}

int main () {
  auto loop = Glib::MainLoop::create ();
  Gio::init ();
  auto network_address = Gio::NetworkAddress::create ("www.example.org", 437);
  auto socket_client = Gio::SocketClient::create ();
  socket_client->set_tls (true);
  socket_client->signal_event ().connect (sigc::ptr_fun (&socket_client_event));
  Glib::RefPtr<Gio::SocketConnection> socket_connection;
  try {
    socket_connection = socket_client->connect (network_address);
  }
  catch (const Gio::TlsError &e) {
    std::cerr << e.what (). c_str () << std::endl;
    return 1;
  }
  catch (const Gio::Error &e) {
    std::cerr << e.what (). c_str () << std::endl;
    return 1;
  }

  loop->run ();
}

When the connect () method is called I get this console output:

(process:9046): GLib-GIO-CRITICAL **: g_socket_connection_connect: assertion 'G_IS_SOCKET_CONNECTION (connection)' failed

(process:9046): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

(process:9046): GLib-GObject-CRITICAL **: g_object_get_qdata: assertion 'G_IS_OBJECT (object)' failed

(process:9046): GLib-GObject-CRITICAL **: g_object_get_qdata: assertion 'G_IS_OBJECT (object)' failed

And then a segmentation fault makes the program die.

I have switched on G_DEBUG=all and stopped at the first error, but according to the backtrace this is somewhere inside the connect () method.

The curious thing is that commenting out the source line that connects the signal handler fixes the problem.

So what am I doing wrong when connecting the signal here? Why is the socket client invalid after connecting it?


Solution

  • There seems to be a bug in the reference counting in either glibmm or gio.

    If I reference the objects manually in the event the problem goes away:

    void socket_client_event (Gio::SocketClientEvent event,
                  const Glib::RefPtr<Gio::SocketConnectable> &connectable,
                  const Glib::RefPtr<Gio::IOStream> &connection) {
      // Workaround for reference counting problems
      if (connectable) {
        connectable->reference ();
      }
      if (connection) {
        connection->reference ();
      }
    }