streamcollection: fix racy user-after-free
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Fri, 31 Mar 2017 09:38:15 +0000 (10:38 +0100)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Fri, 31 Mar 2017 10:32:31 +0000 (11:32 +0100)
The issue happens when the structure is printed by the logging
subsystem: the object is included in the log, and this will cause the
full object printout to be done there. However, after dispose, the queue
was already cleared, so the access to it (to print the object) would
assert, as the queue was already freed. The patch changes it so that the
queue is merely empty, and only freed in _finalize.

https://bugzilla.gnome.org/show_bug.cgi?id=776293

gst/gststreamcollection.c

index df53c59..5ad8940 100644 (file)
@@ -68,6 +68,7 @@ enum
 static guint gst_stream_collection_signals[LAST_SIGNAL] = { 0 };
 
 static void gst_stream_collection_dispose (GObject * object);
+static void gst_stream_collection_finalize (GObject * object);
 
 static void gst_stream_collection_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
@@ -129,6 +130,7 @@ gst_stream_collection_class_init (GstStreamCollectionClass * klass)
       2, GST_TYPE_STREAM, G_TYPE_PARAM);
 
   gobject_class->dispose = gst_stream_collection_dispose;
+  gobject_class->finalize = gst_stream_collection_finalize;
 }
 
 static void
@@ -159,13 +161,23 @@ gst_stream_collection_dispose (GObject * object)
   if (collection->priv->streams) {
     g_queue_foreach (collection->priv->streams,
         (GFunc) release_gst_stream, collection);
-    g_queue_free (collection->priv->streams);
-    collection->priv->streams = NULL;
+    g_queue_clear (collection->priv->streams);
   }
 
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
+static void
+gst_stream_collection_finalize (GObject * object)
+{
+  GstStreamCollection *collection = GST_STREAM_COLLECTION_CAST (object);
+
+  if (collection->priv->streams)
+    g_queue_free (collection->priv->streams);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
 /**
  * gst_stream_collection_new:
  * @upstream_id: (allow-none): The stream id of the parent stream