Segfault when passing socket connection through property

, ,

Hi fellas,

Heads up - this is my first time ever posting on something like this, so I’m not really sure if this is the right place for it.

Basically, I have a GSocketConnection * that I pass from a GtkApplicationWindow via a signal to the GtkApplication class. I’m inheriting the classes as is done in the Getting Started GTK4 documentation. I pass the object plainly via the signal and then in the application class, I initialize another GtkApplicationWindow and have attempted to pass the socket connection object as a property in many different ways.

However, while sometimes it goes through without warning, the line I use to test the object is valid:

g_print ("%b\n", g_socket_connection_is_connected (G_SOCKET_CONNECTION (g_value_get_pointer (&sock_val))));

Always segfaults. That’s just an example of the line. Currently, I am making a reference with g_object_ref and storing that pointer in a GValue and then passing it and unwrapping it with g_value_get_pointer, but I have also tried just passing it cleanly, i.e. the GSocketConnection* object itself - still segfaults. I have tried putting the socket connection in a GValue but that also fails.

My last issue is that the constructed method that I override is being ran before my properties are set.

I know this is a lot of issues to ask for help with, and so I would be immensely grateful to anyone that could help me out. At the root of it, I just want to know how to pass my GSocketConnection* object to another class and use it without segfaulting.

Thank you.

I suspect you’ll need to post a minimal, complete code sample that shows the issue - otherwise readers will have to do a lot of guessing, which is rarely productive.

application.c

static void connection_made (ChatAppApplication *app, GSocketConnection *conn,
    gpointer data)
{
  g_print ("Application notified that socket connection made!\n");

  if (conn)
  {
    GSocketAddress *addr =
      g_socket_connection_get_remote_address (conn, NULL);
    GSocketFamily fam = g_socket_address_get_family (addr);
    if (fam == G_SOCKET_FAMILY_IPV4)
      g_print ("IPV4 socket\n");
    else
      g_print ("IPv6 socket\n");
  }

  g_print ("Got nickname: %s\n", (const char*)data);

  gtk_window_close (GTK_WINDOW (app->setup_window));

  GValue sock_val = G_VALUE_INIT;
  g_value_init (&sock_val, G_TYPE_SOCKET_CONNECTION);
  g_value_set_object (&sock_val, conn);

  app->main_window = chatapp_mainwindow_new (app,
       g_object_ref (conn), data);
}

mainwindow

struct _ChatAppMainWindow
{
  GtkApplicationWindow parent_instance;

  GtkEntry *msg_entry;
  GtkTextView *messages_textview;
  GtkLabel *nickname_label;
  GtkButton *send_btn;

  GSocketConnection *conn_socket;
  gchar *nickname;
};


static void
chatapp_mainwindow_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
{
  ChatAppMainWindow *self = CHATAPP_MAINWINDOW (object);

  if (property_id == PROP_CONNSOCKET)
  {
    self->conn_socket = (GSocketConnection*)g_value_get_pointer (value);
    g_print ("Got socket! %b\n", g_socket_connection_is_connected (self->conn_socket));
  } else if (property_id == PROP_NICKNAME) {
    g_print ("Attempting to set nickname: %s\n", g_value_get_string (value));
    self->nickname = g_value_dup_string (value);
    g_print ("Set nickname to %s\n", self->nickname);

      } else {
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  }
}

ChatAppMainWindow *
chatapp_mainwindow_new (ChatAppApplication *app, GSocketConnection *conn, const gchar *nickname)
{
  GValue sock_val = G_VALUE_INIT;
  g_value_init (&sock_val, G_TYPE_POINTER);
  g_value_set_pointer (&sock_val, conn);
  g_print ("%b\n", g_socket_connection_is_connected (G_SOCKET_CONNECTION (g_value_get_pointer (&sock_val))));
  return CHATAPP_MAINWINDOW (g_object_new (CHATAPP_TYPE_MAINWINDOW, "application", app,
        "connsocket", sock_val, "nickname", nickname, NULL));
}

We lack the definition of your property (in _class_init()), which should be of type POINTER as you use it in set_property() – but you should really verify if you shuoldn’t make it type G_TYPE_SOCKET_CONNECTION.

But we can already see you have a problem: you need not build GValues manually for passing g_object_new(); it does that for you automatically depending on the relevant property type. What is happening here is that you’re effectively passing in a GValue (by value even!!) and use it on the other end as a pointer. That would only be appropriate for a property of type G_TYPE_VALUE – which would be fairly weird.

Basically, remove all manual GValue creation (in chatapp_mainwindow_new() especially), and pass conn directly as the argument after "connsocket".
One easy way to see the mistake is how you pass in the other properties: you don’t manually create GValues for them, you just rely on g_object_new() to do that behind the scenes.

2 Likes

Hi, thanks for replying, and thanks for going through my spaghetti code!

Below is the initialization of the properties in the init method:

GObjectClass *object_class = G_OBJECT_CLASS (klass);
  object_class->constructed  = chatapp_mainwindow_constructed;
  object_class->set_property = chatapp_mainwindow_set_property;
  object_class->get_property = chatapp_mainwindow_get_property;

  obj_properties[PROP_NICKNAME] =
    g_param_spec_string ("nickname",
        "Nickname", "The nickname of the user",
        NULL, G_PARAM_READWRITE);

  obj_properties[PROP_CONNSOCKET] =
    g_param_spec_string ("connsocket",
        "ConnectionSocket", "The socket to the server",
        NULL, G_PARAM_READWRITE);

  g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);

I changed the code to pass the GSocketConnection* directly and removed all GValue object creation code:

ChatAppMainWindow *
chatapp_mainwindow_new (ChatAppApplication *app, GSocketConnection *conn, const gchar *nickname)
{
  return CHATAPP_MAINWINDOW (g_object_new (CHATAPP_TYPE_MAINWINDOW, "application", app,
        "connsocket", conn, "nickname", nickname, NULL));
}

But the code still segfaults when I try to check the socket’s connection status.
I get the following warning in console:

g_value_get_object: assertion 'G_VALUE_HOLDS_OBJECT (value)' failed

Perhaps I’m not getting the object out of the GValue correctly?
I’m using the following call in set_property:

self->conn_socket = g_value_get_object (value);

Use g_param_spec_object() for GObjects:

  obj_properties[PROP_CONNSOCKET] =
    g_param_spec_object ("connsocket",
        "ConnectionSocket", "The socket to the server",
        G_TYPE_SOCKET_CONNECTION, G_PARAM_READWRITE);

You can use g_value_dup_object() in the setter to take a reference before the GValue is freed and drops its own reference.

3 Likes

Oh damn, thank you for you help everybody.

And apologies for wasting everybody’s time with such a simple silly mistake of just not reading the

g_param_spec_XXXXXX

I probably copied the code and just changed the arguments, not paying attention to the meaning of the function at all. :neutral_face:

Again, thanks for your help everybody :+1:

2 Likes

I just want to add if anybody by any chance comes here with this issue:

My last issue is that the constructed method that I override is being ran before my properties are set.

This is because you need to add the G_PARAM_CONSTRUCT flag in the g_param_spec_XXXXX function call.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.