v4l2videdec: Fix race condition between drain and state changes
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Mon, 17 Jan 2022 16:44:47 +0000 (11:44 -0500)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 21 Jan 2022 16:36:50 +0000 (16:36 +0000)
This is due to an unsafe usage of the pad task. We didn't ensure proper
ownership of the task. That race involved the task being released too early,
and was detected, luckily, by the glib mutex implementationt that
reported the mutex being disposed while being locked.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1478>

subprojects/gst-plugins-good/sys/v4l2/gstv4l2videodec.c

index 097f3cae6ba34aae5cca947e740d54424ea92b20..abd01333cbe8d9ea3e009cc94e0981701578a405 100644 (file)
@@ -421,16 +421,26 @@ gst_v4l2_video_dec_finish (GstVideoDecoder * decoder)
   GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
 
   if (gst_v4l2_decoder_cmd (self->v4l2output, V4L2_DEC_CMD_STOP, 0)) {
-    GstTask *task = decoder->srcpad->task;
-
-    /* If the decoder stop command succeeded, just wait until processing is
-     * finished */
-    GST_DEBUG_OBJECT (self, "Waiting for decoder stop");
-    GST_OBJECT_LOCK (task);
-    while (GST_TASK_STATE (task) == GST_TASK_STARTED)
-      GST_TASK_WAIT (task);
-    GST_OBJECT_UNLOCK (task);
-    ret = GST_FLOW_FLUSHING;
+    GstTask *task;
+
+    GST_OBJECT_LOCK (decoder->srcpad);
+    task = GST_PAD_TASK (decoder->srcpad);
+    if (task)
+      gst_object_ref (task);
+    GST_OBJECT_UNLOCK (decoder->srcpad);
+
+    if (task) {
+      /* If the decoder stop command succeeded, just wait until processing is
+       * finished */
+      GST_DEBUG_OBJECT (self, "Waiting for decoder stop");
+      GST_OBJECT_LOCK (task);
+      while (GST_TASK_STATE (task) == GST_TASK_STARTED)
+        GST_TASK_WAIT (task);
+      GST_OBJECT_UNLOCK (task);
+
+      ret = GST_FLOW_FLUSHING;
+      gst_object_unref (task);
+    }
   } else {
     /* otherwise keep queuing empty buffers until the processing thread has
      * stopped, _pool_process() will return FLUSHING when that happened */