g_data_set_internal: avoid use-after-free if datalist is in dataset
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Tue, 13 Dec 2011 14:44:18 +0000 (14:44 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 14 Dec 2011 12:26:17 +0000 (12:26 +0000)
Removing the last thing in a dataset frees the dataset, and if the
datalist was in a dataset, we can't safely unlock it after the dataset
has been freed. Unlock it sooner.

Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=666113
Reviewed-by: Matthias Clasen <mclasen@redhat.com>
glib/gdataset.c

index 554c6c5..df5203e 100644 (file)
@@ -387,6 +387,10 @@ g_data_set_internal (GData   **datalist,
                    {
                      G_DATALIST_SET_POINTER (datalist, NULL);
                      g_free (d);
+                     /* datalist may be situated in dataset, so must not be
+                      * unlocked after we free it
+                      */
+                     g_datalist_unlock (datalist);
 
                      /* the dataset destruction *must* be done
                       * prior to invocation of the data destroy function
@@ -394,8 +398,10 @@ g_data_set_internal (GData   **datalist,
                      if (dataset)
                        g_dataset_destroy_internal (dataset);
                    }
-
-                 g_datalist_unlock (datalist);
+                 else
+                   {
+                     g_datalist_unlock (datalist);
+                   }
 
                  /* We found and removed an old value
                   * the GData struct *must* already be unlinked