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 762552 - Crash on repeated pipeline, bus and signal watch creation
Crash on repeated pipeline, bus and signal watch creation
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gstreamer (core)
1.6.3
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
: 785714 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2016-02-23 17:02 UTC by Xabier Rodríguez Calvar
Modified: 2018-11-03 12:33 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Test program (469 bytes, text/x-csrc)
2016-02-23 17:02 UTC, Xabier Rodríguez Calvar
  Details
bus: change GstBusSource to hold a weak ref to GstBus (3.37 KB, patch)
2016-02-24 14:10 UTC, Thiago Sousa Santos
none Details | Review
bus: change GstBusSource to hold a weak ref to GstBus (3.21 KB, patch)
2016-02-25 13:13 UTC, Thiago Sousa Santos
needs-work Details | Review
bus: change GstBusSource to hold a weak ref to GstBus (5.21 KB, patch)
2016-02-25 16:19 UTC, Thiago Sousa Santos
committed Details | Review

Description Xabier Rodríguez Calvar 2016-02-23 17:02:05 UTC
Created attachment 322010 [details]
Test program

If I run the attached test program, in the end I get:

...
times 32000

(a.out:29888): GStreamer-CRITICAL **: gst_poll_get_read_gpollfd: assertion 'set != NULL' failed

(a.out:29888): GStreamer-CRITICAL **: gst_bus_create_watch: assertion 'bus->priv->poll != NULL' failed

(a.out:29888): GLib-CRITICAL **: g_source_set_callback: assertion 'source != NULL' failed
Fallo de segmento («core» generado)
Comment 1 Xabier Rodríguez Calvar 2016-02-23 17:29:50 UTC
Backtrace:

  • #0 g_source_attach
    at gmain.c line 1163
  • #1 gst_bus_add_watch_full_unlocked
    at gstbus.c line 885
  • #2 gst_bus_add_signal_watch_full
    at gstbus.c line 1322
  • #3 main
    at test.c line 16

Comment 2 Sebastian Dröge (slomo) 2016-02-23 17:30:57 UTC
I guess something there is leaking fds and then at some point you can't create new fds. Either the bus is leaked here, or only the GSource of the watch.
Comment 3 Thiago Sousa Santos 2016-02-23 18:10:08 UTC
gst_bus_remove_watch() is not called automatically when disposing. Is this the application's job or should it be automatically removed when the bus is destroyed?
Comment 4 Sebastian Dröge (slomo) 2016-02-23 18:14:40 UTC
Is the bus actually destroyed then? Doesn't the GSource contain a reference to the bus?
Comment 5 Thiago Sousa Santos 2016-02-23 18:37:56 UTC
Indeed the main bus isn't ever destroyed.
Comment 6 Thiago Sousa Santos 2016-02-23 18:52:56 UTC
At the moment the application needs to remove the watch and it will run forever (left it running for 5 minutes here while previously it would only run for about 30s).

We could remove the watch from the pipeline dispose/finalize but it would be asymmetric as it would be added from the application code and disappear somewhere inside GStreamer. I'd prefer to make the application responsible for it. We could provide helper functions to add or remove watches for the pipeline bus.
Comment 7 Sebastian Dröge (slomo) 2016-02-23 22:18:15 UTC
Or we could make the GSource have a weak reference to the GstBus, and destroy it together with the bus.
Comment 8 Thiago Sousa Santos 2016-02-24 14:10:26 UTC
Created attachment 322244 [details] [review]
bus: change GstBusSource to hold a weak ref to GstBus

Patch to use weak refs. My concern here is if this could be racy if a dispatch
is being called at the same time the last bus reference is unrefd.

If you still have the mainloop running while you unref a GstPipeline, couldn't
this happen?
Comment 9 Sebastian Dröge (slomo) 2016-02-24 14:15:56 UTC
Use GWeakRef and let it give you a strong reference to the GstBus whenever needed... and if that gives you NULL you just don't do anything. However GWeakRef is also not threadsafe currently IIRC (but it should!).
Comment 10 Sebastian Dröge (slomo) 2016-02-24 14:28:17 UTC
Actually GWeakRef claims to be threadsafe now. Good :)
Comment 11 Thiago Sousa Santos 2016-02-24 15:15:46 UTC
Additionally I just found out that gst-play does this:


  play->bus_watch = gst_bus_add_watch (GST_ELEMENT_BUS (play->playbin),
      play_bus_msg, play);

and later:
  gst_object_unref (play->playbin);
  g_source_remove (play->bus_watch);


As the g_source_remove is done after the pipeline unref, the bus_watch id will be invalid.
Comment 12 Sebastian Dröge (slomo) 2016-02-25 09:25:01 UTC
I think you shouldn't remove the GSource but only let the GSource become useless and let the GstBus go away. It's the users responsibility to get rid of GSources that are not needed anymore.
Comment 13 Sebastian Dröge (slomo) 2016-02-25 09:48:21 UTC
Thiago, can you update the patch? That way we don't change any behaviour, continue to leak the GSource (well, the application is!) but don't leak our GstBus and its fds. The GSource is useless anyway if it's the only thing that still has a reference to the GstBus, nothing can ever post messages on it anymore.
Comment 14 Thiago Sousa Santos 2016-02-25 13:13:05 UTC
Created attachment 322367 [details] [review]
bus: change GstBusSource to hold a weak ref to GstBus

Updated to not destroy the GSource.

I think this will be racy if the mainloop is still running, the bus
can be freed while the _dispatch() is called and it will lead to
crashes.

IMHO if we are enforcing the application to unref its GSource then
it is better to let the GSource keep a regular ref. Having a leak
is better than causing crashes.
Comment 15 Sebastian Dröge (slomo) 2016-02-25 13:31:45 UTC
Comment on attachment 322367 [details] [review]
bus: change GstBusSource to hold a weak ref to GstBus

Use GWeakRef and the race conditions goes away
Comment 16 Thiago Sousa Santos 2016-02-25 16:19:09 UTC
Created attachment 322392 [details] [review]
bus: change GstBusSource to hold a weak ref to GstBus

Had not seen the new GWeakRef stuff, patch updated.
Comment 17 Sebastian Dröge (slomo) 2016-02-25 16:50:39 UTC
Comment on attachment 322392 [details] [review]
bus: change GstBusSource to hold a weak ref to GstBus

Great, I like this :) In the GST_WARNING() please also put that it's the application's job to destroy the GSource. Maybe even make this a g_warning()
Comment 18 Thiago Sousa Santos 2016-02-25 18:07:19 UTC
commit 894c67e642c0f858b5b18097fa7c995bf3cc50c1
Author: Thiago Santos <thiagoss@osg.samsung.com>
Date:   Wed Feb 24 10:56:24 2016 -0300

    bus: change GstBusSource to hold a weak ref to GstBus
    
    When holding a regular ref it will cause the GstBus to never
    reach 0 references and it won't be destroyed unless the application
    explicitly calls gst_bus_remove_signal_watch().
    
    Switching to weakref will allow the GstBus to be destroyed.
    The application is still responsible for destroying the
    GSource.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=762552
Comment 19 Sebastian Dröge (slomo) 2016-02-29 21:36:48 UTC
This and the commit from https://bugzilla.gnome.org/show_bug.cgi?id=762849#c5 were reverted now as they caused problems. Specifically the gst-rtsp-server unit tests were failing.

Let's revisit this for 1.9.
Comment 20 Sebastian Dröge (slomo) 2016-06-01 06:42:36 UTC
Anybody up for looking into this?
Comment 21 Tim-Philipp Müller 2016-11-11 18:48:36 UTC
1.11 then perhaps! :)
Comment 22 Thiago Sousa Santos 2016-11-12 13:44:48 UTC
The problem is that we do 'g_source_remove_poll' on a GSource that was destroyed by rtsp-media. Can't think on a thread-safe way to fix this.

rtsp creates a bus watch and then it has children added to it. When it destroy + unref it isn't the last reference because of the child. Later it will unref the bus and (as the gsource dispose wasn't called) the bus will try to remove the poll, but the gsource was destroyed so this fails.

The g_source_destroy has already removed the polls. We could check if the gsource was destroyed before removing polls but this isn't thread-safe. No idea how to properly fix this.
Comment 23 Sebastian Dröge (slomo) 2016-11-14 09:04:18 UTC
So the GSource with the polls is destroyed by RTSP, but references to it are still around. And when the source is actually unreffed for the last time, we try to remove the polls (which were already removed during destroy?). And there's no way of getting notified about destroy AFAICS.

Could we let the removal of the polls just always be handled by destroy and never do that ourselves?
Comment 24 Thiago Sousa Santos 2016-11-14 13:22:12 UTC
(In reply to Sebastian Dröge (slomo) from comment #23)
> So the GSource with the polls is destroyed by RTSP, but references to it are
> still around. And when the source is actually unreffed for the last time, we
> try to remove the polls (which were already removed during destroy?). And
> there's no way of getting notified about destroy AFAICS.

It actually happens when the GstBus is unref'd and we do g_source_remove_poll on the destroyed gsource.

> 
> Could we let the removal of the polls just always be handled by destroy and
> never do that ourselves?

Can we call destroy() from the gstbus dispose? What if the GSource is still in use by something else external?
Comment 25 Sebastian Dröge (slomo) 2016-11-14 13:25:28 UTC
(In reply to Thiago Sousa Santos from comment #24)

> Can we call destroy() from the gstbus dispose? What if the GSource is still
> in use by something else external?

That seems ok to do, yes.

If something else is still using it, it will just stop getting any "events" from it and it can't be added to a new main context anymore at that point. I don't see any problems here.
Comment 26 Thiago Sousa Santos 2016-11-15 22:30:52 UTC
I actually made a mistake debugging this. It is the g_source_attach that keeps a reference on the gsource, but the rest holds true.

Using g_source_destroy fixes the rtsp tests but breaks pipelines/gio in -base. It tries to do a g_source_remove after the bus has been destroyed. Not sure this is a valid usecase. Should users expect the GSource to outlive the GstBus?

"gstcheck.c:79:F:general:test_memory_stream:0: Unexpected critical/warning: Source ID 1 was not found when attempting to remove it"

I start to wonder if we are not creating more holes by fixing this and should just tell users to properly clean up the watches after they are not needed anymore.
Comment 27 Sebastian Dröge (slomo) 2016-11-17 07:59:38 UTC
Usually GSources that are created and returned to the caller (g_idle_source_new(), etc) are to be managed there. That is, the caller is responsible for attaching/removing them to a main context, the caller might have additional references to it around, etc.

Maybe there is just some API missing in GLib to allow doing something sensible here?
Comment 28 Sebastian Dröge (slomo) 2017-08-03 08:01:32 UTC
*** Bug 785714 has been marked as a duplicate of this bug. ***
Comment 29 GStreamer system administrator 2018-11-03 12:33:20 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/gstreamer/gstreamer/issues/159.