Search code examples
linuxmemory-managementgdbusudisks

How to correctly manage references returned by g_dbus_interface_get_object()


I have an application in which I'm using UDisks to handle some drives and partitions. In my application I have a situation where I have a pointer to a UDisksDrive that I need to convert to a UDisksObject pointer through which I can access other interfaces later. I'm quite unclear as to what objects I should unreference and when. In one function, I currently do:

    UDisksDrive* drive = udisks_client_get_drive_for_block(client, block);
    if(drive == NULL) {
        g_object_unref(block);
        return NULL;
    }

    UDisksObject* driveObject = (UDisksObject*) g_dbus_interface_get_object(G_DBUS_INTERFACE(drive));
    g_object_unref(drive);
    return driveObject;

But I don't know if this is right. It works, but I know that might not necessarily mean anything. The gdbus documentation for g_dbus_interface_get_object() reads like I shouldn't be unreferencing the returned driveObject variable when the receiving function is done with it, but I'm not sure. I feel like I should be unreferencing block before the functions returns too, but I don't know why I'm not. This is a project I only get time to work on here and there, and I feel like perhaps I'd tried it and it caused a crash or exception.

Most of my other code involving UDisks is pretty straight-forward. I _get_ something, use it, and unreference it. It's this stuff that involves interface swapping that I'm a little fuzzy on.


Solution

  • Time to think, research, and a brief chat on IRC has resulted in the following:

    Yes, I definitely need to free (unreference) block before the function returns. Also, g_dbus_interface_get_object() is the wrong function for this situation. Because I don't care about drive and just want to returns driveObject, I need to use g_dbus_interface_dup_object() instead, which allows the returned pointer to own it's own reference. That makes it so that the caller can free driveObject safely when it's done with it. So the updated code snippet looks like this:

        UDisksDrive* drive = udisks_client_get_drive_for_block(client, block);
        if(drive == NULL) {
            g_object_unref(blockObject);
            g_object_unref(block);
            return NULL;
        }
    
        UDisksObject* driveObject = (UDisksObject*) g_dbus_interface_dup_object(G_DBUS_INTERFACE(drive));
        g_object_unref(block);
        g_object_unref(drive);
        g_object_unref(blockObject);
    
        return driveObject;