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 787144 - Memory leak in gstqtmux.c
Memory leak in gstqtmux.c
Status: RESOLVED OBSOLETE
Product: GStreamer
Classification: Platform
Component: gst-plugins-good
1.11.2
Other Linux
: Normal normal
: git master
Assigned To: GStreamer Maintainers
GStreamer Maintainers
: 787225 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2017-09-01 17:16 UTC by Anton Nikolaevsky
Modified: 2018-11-03 15:21 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
proposed fix (783 bytes, patch)
2017-09-01 17:16 UTC, Anton Nikolaevsky
rejected Details | Review
ASan report for crash on shutdown with EOS with patch applied (10.43 KB, text/plain)
2017-09-07 13:32 UTC, Anton Nikolaevsky
  Details

Description Anton Nikolaevsky 2017-09-01 17:16:11 UTC
Created attachment 358954 [details] [review]
proposed fix

Hello!

I have an application which takes video stream from IP camera and streams it as video/mp4 through web-server. The application uses the following pipeline to produce browsers-friendly mp4-stream:
    appsrc -> h264parse -> qtmux -> appsink

The problem is the application leaks GstBuffer-s steadily. AddressSanitizer reports the following 2 stacks with direct leaks:

Direct leak of 43792 byte(s) in 161 object(s) allocated from:
    #0 0x7f97ca5ba73f malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5473f)
    #1 0x7f978e613f16 in g_malloc glib-2.42.1/glib/gmem.c:97
    #2 0x7f978e64b4ec in g_slice_alloc glib-2.42.1/glib/gslice.c:1007
    #3 0x7f978edce8b3 in gst_buffer_new gstreamer-1.11.2/gst/gstbuffer.c:798
    #4 0x7f978edcea05 in gst_buffer_new_allocate gstreamer-1.11.2/gst/gstbuffer.c:846
    #5 0x7f97705743a8 in gst_h264_parse_wrap_nal gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:424
    #6 0x7f9770577c7b in gst_h264_parse_process_nal gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:889
    #7 0x7f977057a9e3 in gst_h264_parse_handle_frame gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:1222
    #8 0x7f9770863093 in gst_base_parse_handle_buffer gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:2145
    #9 0x7f977086ee72 in gst_base_parse_chain gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:3227
    #10 0x7f978ee6cd74 in gst_pad_chain_data_unchecked gstreamer-1.11.2/gst/gstpad.c:4205
    #11 0x7f978ee6e76d in gst_pad_push_data gstreamer-1.11.2/gst/gstpad.c:4457
    #12 0x7f978ee6f73c in gst_pad_push gstreamer-1.11.2/gst/gstpad.c:4576
    #13 0x7f97708aed19 in gst_base_src_loop gstreamer-1.11.2/libs/gst/base/gstbasesrc.c:2843
    #14 0x7f978eee4ede in gst_task_func gstreamer-1.11.2/gst/gsttask.c:335
    #15 0x7f978eee6e4f in default_func gstreamer-1.11.2/gst/gsttaskpool.c:69
    #16 0x7f978e667b9d in g_thread_pool_thread_proxy glib-2.42.1/glib/gthreadpool.c:307
    #17 0x7f978e666eb6 in g_thread_proxy glib-2.42.1/glib/gthread.c:764
    #18 0x7f97c3b05063 in start_thread /build/glibc-6V9RKT/glibc-2.19/nptl/pthread_create.c:309 (discriminator 2)

Direct leak of 8976 byte(s) in 33 object(s) allocated from:
    #0 0x7f97ca5ba73f malloc (/usr/lib/x86_64-linux-gnu/libasan.so.1+0x5473f)
    #1 0x7f978e613f16 in g_malloc glib-2.42.1/glib/gmem.c:97
    #2 0x7f978e64b4ec in g_slice_alloc glib-2.42.1/glib/gslice.c:1007
    #3 0x7f978edce8b3 in gst_buffer_new gstreamer-1.11.2/gst/gstbuffer.c:798
    #4 0x7f97708d109f in gst_byte_writer_reset_and_get_buffer gstreamer-1.11.2/libs/gst/base/gstbytewriter.c:244
    #5 0x7f9770581b0a in gst_h264_parse_handle_sps_pps_nals gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:2306
    #6 0x7f9770582ccf in gst_h264_parse_pre_push_frame gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:2417
    #7 0x7f9770866ead in gst_base_parse_push_frame gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:2455
    #8 0x7f9770865783 in gst_base_parse_handle_and_push_frame gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:2337
    #9 0x7f9770868e5a in gst_base_parse_finish_frame gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:2678
    #10 0x7f977057ac44 in gst_h264_parse_handle_frame gst-plugins-bad-1.11.2/gst/videoparsers/gsth264parse.c:1248
    #11 0x7f9770863093 in gst_base_parse_handle_buffer gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:2145
    #12 0x7f977086ee72 in gst_base_parse_chain gstreamer-1.11.2/libs/gst/base/gstbaseparse.c:3227
    #13 0x7f978ee6cd74 in gst_pad_chain_data_unchecked gstreamer-1.11.2/gst/gstpad.c:4205
    #14 0x7f978ee6e76d in gst_pad_push_data gstreamer-1.11.2/gst/gstpad.c:4457
    #15 0x7f978ee6f73c in gst_pad_push gstreamer-1.11.2/gst/gstpad.c:4576
    #16 0x7f97708aed19 in gst_base_src_loop gstreamer-1.11.2/libs/gst/base/gstbasesrc.c:2843
    #17 0x7f978eee4ede in gst_task_func gstreamer-1.11.2/gst/gsttask.c:335
    #18 0x7f978eee6e4f in default_func gstreamer-1.11.2/gst/gsttaskpool.c:69
    #19 0x7f978e667b9d in g_thread_pool_thread_proxy glib-2.42.1/glib/gthreadpool.c:307
    #20 0x7f978e666eb6 in g_thread_proxy glib-2.42.1/glib/gthread.c:764
    #21 0x7f97c3b05063 in start_thread /build/glibc-6V9RKT/glibc-2.19/nptl/pthread_create.c:309 (discriminator 2)

With help of additional logs in gst-plugins-good-1.11.2/gst/isomp4/gstqtmux.c it was noticed that the buffers leak when the pipeline is about to stop (on client disconnect) and there were some buffers in GstQTPad::fragment_buffers. Unfortunately, I was not able to find the easy way 
to reproduce such conditions with simple gst-launch command line use-case (tried filesrc and rtspsrc).

The proposed fix is attached.
Comment 1 Sebastian Dröge (slomo) 2017-09-02 08:29:21 UTC
Thanks for the patch! Please submit the patch against latest GIT master or 1.12 (yours does not apply anymore), and provide it as a "git format-patch" style patch. See https://gstreamer.freedesktop.org/documentation/contribute/index.html#how-to-submit-patches


The change itself looks correct.
Comment 2 Anton Nikolaevsky 2017-09-02 20:34:23 UTC
Hello Sebastian! 
Thanks for your reply.
I've just figured out that I forgot about qtmux attributes my application sets:  

    fragment-duration=100 faststart=1

So now I'm able to reproduce the leak with simple gst-launch command:

    gst-launch-1.0 rtspsrc location=rtsp://url ! queue ! rtph264depay ! h264parse config-interval=-1 ! qtmux fragment-duration=100 faststart=1 ! filesink location=out.mp4

Moreover, I've found that the leak does not reproduce when filesrc is used, i.e.:

    gst-launch-1.0 filesrc location=/home/builder/10.mp4 ! qtdemux ! h264parse config-interval=-1 ! qtmux fragment-duration=100 faststart=1 ! filesink location=out.mp4

It turned out that the difference was in EOS. filesrc sends EOS automatically on EOF. When pipeline with rtspsrc is interrupted with SIGINT, EOS is not sent by default and the leak is observed.
So the workaround is to force EOS generation on shut down:

    gst-launch-1.0 --eos-on-shutdown rtspsrc location=rtsp://url ! queue ! rtph264depay ! h264parse config-interval=-1 ! qtmux fragment-duration=100 faststart=1 ! filesink location=out.mp4

I've checked the originally proposed fix with gst-launch command. Unfortunately, gst-launch crashes with heap-use-after-free (on gst_buffer_unref called on already freed object). It looks like there is a data race around GstQTPad::fragment_buffers between gst_qt_mux_pad_reset invoked during pipeline shutdown chain and gst_qt_mux_pad_fragment_add_buffer still using it in different thread.
I believe the data race can be eliminated by making access to GstQTPad::fragment_buffers atomic either with proper synchronization or with some lock-free technique.
Comment 3 Sebastian Dröge (slomo) 2017-09-04 07:09:29 UTC
*** Bug 787225 has been marked as a duplicate of this bug. ***
Comment 4 Matej Knopp 2017-09-04 09:09:55 UTC
If those are indeed different thread than it means that gst_qt_mux_collected is called while GST_STATE_CHANGE_PAUSED_TO_READY, which, if happens, seams like a bigger problem than the original leak.

Or perhaps the state is changed from thread that has gst_qt_mux_pad_fragment_add_buffer in while the muxer sends out buffer? In which case the solution would perhaps be to copy the array content to stack before iterating over it in gst_qt_mux_pad_fragment_add_buffer and clear pad->fragment_buffers before sending out the first buffer.
Comment 5 Anton Nikolaevsky 2017-09-04 20:01:50 UTC
Please, ignore my previous statement regarding the data race I thought I'd found. Today I had time to investigate the problem more carefully. Unfortunately, I haven't kept original crash report so now I'm not sure whether I indeed saw gst_buffer_unref in the crash stack (I was in a little bit of hurry reporting the patch can lead to crash). All stacks I've collected today were triggered by gst_debug_print_object@gstreamer-1.11.2/gst/gstinfo.c:885 (i.e. by tracing routines, not the gst_buffer_unref call) and the guilty object turned out to be qtpad (not the leaking fragment buffer as I thought previously).

  • #0 __GI_raise
    at ../nptl/sysdeps/unix/sysv/linux/raise.c line 56
  • #1 __GI_abort
    at abort.c line 89
  • #2 ??
    from /usr/lib/x86_64-linux-gnu/libasan.so.1
  • #3 ??
    from /usr/lib/x86_64-linux-gnu/libasan.so.1
  • #4 ??
    from /usr/lib/x86_64-linux-gnu/libasan.so.1
  • #5 __asan_report_error
    from /usr/lib/x86_64-linux-gnu/libasan.so.1
  • #6 __asan_report_load8
    from /usr/lib/x86_64-linux-gnu/libasan.so.1
  • #7 g_type_check_instance_is_fundamentally_a
    at gtype.c line 3982
  • #8 gst_debug_print_object
    at gstinfo.c line 885
  • #9 gst_debug_log_default
    at gstinfo.c line 1159
  • #10 gst_debug_log_valist
    at gstinfo.c line 566
  • #11 gst_debug_log
    at gstinfo.c line 498
  • #12 gst_qt_mux_pad_reset
    at gstqtmux.c line 545
  • #13 gst_qt_mux_reset
    at gstqtmux.c line 606
  • #14 gst_qt_mux_change_state
    at gstqtmux.c line 5048
  • #15 gst_element_change_state
    at gstelement.c line 2743
  • #16 gst_element_set_state_func
    at gstelement.c line 2697
  • #17 gst_bin_element_set_state
    at gstbin.c line 2589
  • #18 gst_bin_change_state_func
    at gstbin.c line 2931
  • #19 gst_element_change_state
    at gstelement.c line 2743
  • #20 gst_element_set_state_func
    at gstelement.c line 2697
  • #21 main
    at gst-launch.c line 1216

... and nothing data race alike in different threads.

To be sure I've replaced GST_TRACE_OBJECT with GST_TRACE and got rid of qtpad reference and gst-launch has ceased to crash.
As for the crashing on accessing qtpad object I did not investigate further whether it is expected behavior at this point of a pipeline destruction. I suppose it might be so.

CONCLUSION: the patch I originally proposed should be rejected, without tracing line it must be safe enough - this is exactly what Matej posted at https://bugzilla.gnome.org/attachment.cgi?id=359046
Comment 6 Anton Nikolaevsky 2017-09-04 20:04:15 UTC
Review of attachment 358954 [details] [review]:

can lead to crash, but without tracing line it must be safe enough
Comment 7 Sebastian Dröge (slomo) 2017-09-07 09:53:02 UTC
The qtpad reference there must be valid, otherwise there is a bug elsewhere. This needs further debugging.
Comment 8 Anton Nikolaevsky 2017-09-07 13:32:31 UTC
Created attachment 359353 [details]
ASan report for crash on shutdown with EOS with patch applied

Got crash on gst_buffer_unref with the tracing-free patch applied :( To reproduce you need just to shutdown with EOS, i.e. to run the command that previously allowed to workaround the leak:
    gst-launch-1.0 --eos-on-shutdown rtspsrc location=rtsp://url ! queue ! rtph264depay ! h264parse config-interval=-1 ! qtmux fragment-duration=100 faststart=1 ! filesink location=out.mp4
Comment 9 Sebastian Dröge (slomo) 2017-09-11 09:22:04 UTC
Ok, so this is the actual buffer from h264parse that is unreffed twice. Once in qtmux (causing the problem), and previously the last time in basesink (where it was destroyed).

The reference counting of those buffers has to be double checked. Does qtmux actually keep a reference to them around (it should), or pass them all downstream / unref?
Comment 10 GStreamer system administrator 2018-11-03 15:21:46 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/gst-plugins-good/issues/399.