GNOME Bugzilla – Bug 700472
Memory leak during address translation
Last modified: 2013-06-08 23:37:50 UTC
I'm playing around with a gstreamer 0.10 playbin2 pipe which contains the gstsouphttpsrc, I see that every time I change the URI I get a memory leak (see valgrind trace below). This time I played four songs (4 leaked blocks). This is on debian unstable, libsoup2.4-1:amd64 2.42.2-3. ==27167== 432 (224 direct, 208 indirect) bytes in 4 blocks are definitely lost in loss record 9,191 of 9,746 ==27167== at 0x4C2BDEB: malloc (vg_replace_malloc.c:270) ==27167== by 0x62A8D30: g_malloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.3600.1) ==27167== by 0x62BDF92: g_slice_alloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.3600.1) ==27167== by 0x62BE4E5: g_slice_alloc0 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.3600.1) ==27167== by 0x58CE8A4: g_type_create_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.3600.1) ==27167== by 0x58B3757: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.3600.1) ==27167== by 0x58B4D20: g_object_newv (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.3600.1) ==27167== by 0x58B550F: g_object_new_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.3600.1) ==27167== by 0x58B5843: g_object_new (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.3600.1) ==27167== by 0xF53EFD9: g_socket_address_new_from_native (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.3600.1) ==27167== by 0xEF84B9C: next_address (soup-address.c:1099) ==27167== by 0xEF84CA9: got_addresses (soup-address.c:1131)
can you run valgrind with --num-callers=50 ?
Here you go! ==7446== 432 (224 direct, 208 indirect) bytes in 4 blocks are definitely lost in loss record 7,990 of 8,476 ==7446== at 0x4C2CD7B: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==7446== by 0x56A1CF0: g_malloc (gmem.c:159) ==7446== by 0x56B6EF2: g_slice_alloc (gslice.c:1003) ==7446== by 0x56B7445: g_slice_alloc0 (gslice.c:1029) ==7446== by 0x54348C4: g_type_create_instance (gtype.c:1897) ==7446== by 0x5419717: g_object_constructor (gobject.c:1855) ==7446== by 0x541ACE0: g_object_newv (gobject.c:1719) ==7446== by 0x541B4CF: g_object_new_valist (gobject.c:1836) ==7446== by 0x541B803: g_object_new (gobject.c:1551) ==7446== by 0x18466FA9: g_socket_address_new_from_native (gsocketaddress.c:231) ==7446== by 0x1816D3BF: got_addresses (in /usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1.6.0) ==7446== by 0x1816D7F7: complete_resolve_async (in /usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1.6.0) ==7446== by 0x1816D90C: lookup_resolved (in /usr/lib/x86_64-linux-gnu/libsoup-2.4.so.1.6.0) ==7446== by 0x1846DDFA: g_task_return_now (gtask.c:1105) ==7446== by 0x1846DE18: complete_in_idle_cb (gtask.c:1114) ==7446== by 0x569BF04: g_main_context_dispatch (gmain.c:3054) ==7446== by 0x569C247: g_main_context_iterate.isra.22 (gmain.c:3701) ==7446== by 0x569C6B9: g_main_loop_run (gmain.c:3895) ==7446== by 0x17AF3E6F: gst_soup_http_src_create (in /usr/lib/x86_64-linux-gnu/gstreamer-0.10/libgstsouphttpsrc.so) ==7446== by 0x17426FAB: gst_base_src_get_range (in /usr/lib/x86_64-linux-gnu/libgstbase-0.10.so.0.30.0) ==7446== by 0x174282BF: gst_base_src_loop (in /usr/lib/x86_64-linux-gnu/libgstbase-0.10.so.0.30.0) ==7446== by 0x51A0E33: gst_task_func (in /usr/lib/x86_64-linux-gnu/libgstreamer-0.10.so.0.30.0) ==7446== by 0x56C06F1: g_thread_pool_thread_proxy (gthreadpool.c:309) ==7446== by 0x56BFEB4: g_thread_proxy (gthread.c:798) ==7446== by 0x6E92F8D: start_thread (pthread_create.c:311) ==7446== by 0x66B3E1C: clone (clone.S:113)
hm... and no other libsoup objects show up as leaked? None of libsoup's own tests leak SoupAddresses, so it seems likely that the problem is that something else holding a ref on the address is getting leaked. Actually, maybe it's the GTask... (In reply to comment #0) > I'm playing around with a gstreamer 0.10 playbin2 pipe which contains the > gstsouphttpsrc What's the command you're running?
(In reply to comment #3) > hm... and no other libsoup objects show up as leaked? > > None of libsoup's own tests leak SoupAddresses, so it seems likely that the > problem is that something else holding a ref on the address is getting leaked. > > Actually, maybe it's the GTask... As far as I can see the libgstsouphttpsrc never touches the address, so to me it looks private to libsoup (and beneath). I don't have a clear picture of exactly what happens with the address returned by got_addresses. As far as I can see soup_socket_connect_async is used. Which creates a GSocketClient and uses g_socket_client_connect_async, so I guess the address is returned to the GSocketClient. I'll put some debug in glib and see if I can track it down. > > (In reply to comment #0) > > I'm playing around with a gstreamer 0.10 playbin2 pipe which contains the > > gstsouphttpsrc > > What's the command you're running? I have my own program creating a gstreamer pipe, basically a playbin2 element, to which I pass http url's. I unref the gstelement (checked ref counter on exit), and it is 1 before I deref it.
(In reply to comment #4) > > Actually, maybe it's the GTask... > > As far as I can see the libgstsouphttpsrc never touches the address, so to me > it looks private to libsoup (and beneath). gstsouphttpsrc keeps an internal main loop, which it starts and stops at various points. So there could be a problem where in some case, you create a src, do some stuff with it, and then destroy it, and at the point where you destroyed it, there was a callback pending on its internal main loop that was holding a ref on the SoupAddress, but which now never gets run. (Really, the gst soup stuff ought to be rewritten using the newer libsoup streaming APIs so it doesn't have to play these games... Though that would require depending on a much newer version of libsoup than it currently does.) There are no public APIs that would let you check if a GMainContext still has sources attached to it, but you could cheat by calling g_main_context_get_source_by_id() in a loop from 0 to 1000 or something like that... and if you find a source, g_source_get_name() will tell you a little bit about it...
(In reply to comment #5) > (In reply to comment #4) > > > Actually, maybe it's the GTask... > > > > As far as I can see the libgstsouphttpsrc never touches the address, so to me > > it looks private to libsoup (and beneath). > > gstsouphttpsrc keeps an internal main loop, which it starts and stops at > various points. So there could be a problem where in some case, you create a > src, do some stuff with it, and then destroy it, and at the point where you > destroyed it, there was a callback pending on its internal main loop that was > holding a ref on the SoupAddress, but which now never gets run. > > (Really, the gst soup stuff ought to be rewritten using the newer libsoup > streaming APIs so it doesn't have to play these games... Though that would > require depending on a much newer version of libsoup than it currently does.) > > There are no public APIs that would let you check if a GMainContext still has > sources attached to it, but you could cheat by calling > g_main_context_get_source_by_id() in a loop from 0 to 1000 or something like > that... and if you find a source, g_source_get_name() will tell you a little > bit about it... I have found the leak, it is a bug inside libsoup, actually in soup-socket.c, function soup_socket_get_http_proxy_uri. This is not very nice: addr = g_socket_get_remote_address (priv->gsock, NULL); if (!addr || !G_IS_PROXY_ADDRESS (addr)) return NULL; g_socket_get_remote_address returns an address with inc'ed ref counter, there should be an unref there.. like: addr = g_socket_get_remote_address (priv->gsock, NULL); if (!addr || !G_IS_PROXY_ADDRESS (addr)) { if (addr) g_object_unref(addr); return NULL; } A patch is attached.
Created attachment 244903 [details] [review] Fixes the ref leak
Ah! Thanks. Fixed in master, but I'm going to leave this bug open to remind me to add a test case that covers this code
Ha ha. Added the test case and it turns out there was a second leak. (The function was leaking on both success and failure.) Fixed now in master. Thanks again for the bug report.