After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 372071 - gstbasesrc : race condition upon gst_base_src_deactivate crashes in gst_base_src_get_range
gstbasesrc : race condition upon gst_base_src_deactivate crashes in gst_base_...
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
git master
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
Depends on:
Blocks:
 
 
Reported: 2006-11-07 16:12 UTC by vanista
Modified: 2006-11-13 17:58 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description vanista 2006-11-07 16:12:20 UTC
Overview Description:

A crash can occur in gstbasesrc when a pipeline is interupted before normal EOS by changing its state to NULL.

The unprotected call to gst_pad_stop_task in gst_base_src_deactivate can lead to unrefs of member objects still used in another thread.


Steps to Reproduce:

This was tested with gstreamer-0.10.6, but the behaviour hasn't changed in HEAD so the problem should remain...

This is impossible to reproduce using gst-launch-0.10, it occurs in the scope of a program which dynamically builds a pipeline, runs, and halts it upon receiving the first buffers from a fakesink's handoff callback. The program uses gstreamer for media analysis by peeking a few decoded buffers and their caps.

The main thread of the program has the same behaviour as gst-launch-0.10 for polling the bus in a loop. When the loop catches and EOS message, it stops and changes the state of the pipeline bin to NULL.

The callback function, when deciding it has received enough buffers will post and EOS message on the bus. This way, no change state is triggered within any thread.

1) As the state is changed to NULL, a pipeline containing a filesrc will call gst_base_src_deactivate. This will unref the mmap objects of the filesrc, regardless of what it's currently doing.

2) On some rare occasion, the loop thread of a demuxer will execute gst_base_src_get_range at the exact same time, pass the checks for pad activity and end-up with an unreffed buffer moments later. 


Actual Results:

This of course leads to various side effects ranging from gst and glib warnings to plain seg fault.


Expected Results:

All data flow handling should be protected from element state changes.


Patch/Fix:

Locking the basesrc object before triggering gst_pad_stop_task fixes the problem...

This simple patch has been created for HEAD :


--- original/gstbasesrc.c	2006-11-07 10:36:53.000000000 -0500
+++ patched/gstbasesrc.c	2006-11-07 10:36:01.000000000 -0500
@@ -1872,7 +1872,9 @@
   result = gst_base_src_unlock (basesrc);

   /* step 2, make sure streaming finishes */
+  GST_OBJECT_LOCK(basesrc);
   result &= gst_pad_stop_task (pad);
+  GST_OBJECT_UNLOCK(basesrc);

   return result;
 }





Debug Traces:

(gdb) bt
  • #0 gst_file_src_create
    at gstfilesrc.c line 602
  • #1 gst_base_src_get_range
    at gstbasesrc.c line 1269
  • #2 gst_base_src_pad_get_range
    at gstbasesrc.c line 1337
  • #3 gst_pad_get_range
    at gstpad.c line 3492
  • #4 gst_pad_pull_range
    at gstpad.c line 3574
  • #5 gst_qtdemux_loop
    at qtdemux.c line 1296
  • #6 gst_task_func
    at gsttask.c line 193
  • #7 g_thread_pool_thread_proxy
    at gthreadpool.c line 114
  • #8 g_thread_create_proxy
    at gthread.c line 564
  • #9 start_thread
    from /lib/tls/i686/cmov/libpthread.so.0
  • #10 clone
    from /lib/tls/i686/cmov/libc.so.6
  • #0 __kernel_vsyscall
  • #1 __lll_mutex_lock_wait
    from /lib/tls/i686/cmov/libpthread.so.0
  • #2 _L_mutex_lock_33
    from /lib/tls/i686/cmov/libpthread.so.0
  • #3 ??
  • #4 g_thread_equal_posix_impl
    at gthread-posix.c line 412
  • #5 IA__g_static_rec_mutex_lock
    at gthread.c line 280
  • #6 gst_pad_stop_task
    at gstpad.c line 3989
  • #7 gst_base_src_deactivate
    at gstbasesrc.c line 1771
  • #8 gst_pad_activate_pull
    at gstpad.c line 720
  • #9 gst_pad_activate_pull
    at gstpad.c line 706
  • #10 gst_pad_set_active
    at gstpad.c line 647
  • #11 activate_pads
    at gstelement.c line 2254
  • #12 gst_iterator_fold
    at gstiterator.c line 503
  • #13 iterator_fold_with_resync
    at gstelement.c line 2272
  • #14 gst_element_pads_activate
    at gstelement.c line 2309
  • #15 gst_element_change_state_func
    at gstelement.c line 2370
  • #16 gst_qtdemux_change_state
    at qtdemux.c line 910
  • #17 gst_element_change_state
    at gstelement.c line 2177
  • #18 gst_element_set_state_func
    at gstelement.c line 2139
  • #19 gst_element_set_state
    at gstelement.c line 2049
  • #20 gst_bin_change_state_func
    at gstbin.c line 1754
  • #21 gst_pipeline_change_state
    at gstpipeline.c line 492
  • #22 gst_element_change_state
    at gstelement.c line 2177
  • #23 gst_element_change_state
    at gstelement.c line 2217
  • #24 gst_element_set_state_func
    at gstelement.c line 2139
  • #25 gst_element_set_state
    at gstelement.c line 2049

Comment 1 vanista 2006-11-07 17:29:30 UTC
Okay the fix was a bit hasty, I retested for a while and the problem still happened, only much less often... Locking the mutex like this much change the timing a lot.

I'm investigating locking the pad in gst_base_src_get_range instead since it's this object the gst_pad_pause_task will try to lock first. Will test throughly and post a new patch if things look better.
Comment 2 Wim Taymans 2006-11-08 00:51:34 UTC
you are not allowed to change the state of a plugin/pipeline from the streaming thread. we try to catch and warn for those cases but it's not always possible. please use the gstbus to marshall the state change to the main thread.
Comment 3 vanista 2006-11-08 13:07:10 UTC
Yes, that's how it's implemented in my app. From the callback I post an EOS message to the bus, the message is caught in the main thread then the change state is called. I know changing the state of an element from a thread poses problems...

I've retested much with GStreamer CVS HEAD and could not reproduce. However I didn't see a significant change since 10.6 in gstbasesrc.c which could have fixed this, conceptualy speaking the problem looks to be still there, unless the fix lays at a different level.
Comment 4 Wim Taymans 2006-11-13 17:58:36 UTC
OK, then it should work fine, it might be related to other problems indeed (like a sink not changing state properly).

Also conceptually it is not possible to have a problem since the resources are only freed when the streaming task is finished. This is ensured by grabbing the stream lock before calling _stop().

I'm closing, please reopen if there is still a problem.