OSDN Git Service

gobex: Protect against user callback freeing internal objects
authorJohan Hedberg <johan.hedberg@intel.com>
Wed, 31 Aug 2011 09:41:48 +0000 (12:41 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 4 Dec 2012 21:22:02 +0000 (22:22 +0100)
A user callback could potentially do things like g_obex_cancel_request
or g_obex_unref while we are inside the IO watch callback. It is
therefore important to ensure that we are in a consistent state when the
user callback returns.

gobex/gobex.c

index 97fb3c3..bfcf8b8 100644 (file)
@@ -625,9 +625,14 @@ static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
                err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
                                        "The operation was cancelled");
 
-       if (p->rsp_func)
+       if (p->rsp_func) {
                p->rsp_func(obex, err, rsp, p->rsp_data);
 
+               /* Check if user callback removed the request */
+               if (p != obex->pending_req)
+                       return;
+       }
+
        if (p->cancelled)
                g_error_free(err);
 
@@ -807,19 +812,24 @@ static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
        if (pkt == NULL)
                goto failed;
 
+       /* Protect against user callback freeing the object */
+       g_obex_ref(obex);
+
        if (obex->pending_req)
                handle_response(obex, NULL, pkt);
        else
                handle_request(obex, pkt);
 
+       obex->rx_data = 0;
+
+       g_obex_unref(obex);
+
        if (err != NULL)
                g_error_free(err);
 
        if (pkt != NULL)
                g_obex_packet_free(pkt);
 
-       obex->rx_data = 0;
-
        return TRUE;
 
 failed:
@@ -828,12 +838,17 @@ failed:
        obex->io_source = 0;
        obex->rx_data = 0;
 
+       /* Protect against user callback freeing the object */
+       g_obex_ref(obex);
+
        if (obex->pending_req)
                handle_response(obex, err, NULL);
 
        if (obex->disconn_func)
                obex->disconn_func(obex, err, obex->disconn_func_data);
 
+       g_obex_unref(obex);
+
        g_error_free(err);
 
        return FALSE;