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 700472 - Memory leak during address translation
Memory leak during address translation
Status: RESOLVED FIXED
Product: libsoup
Classification: Core
Component: HTTP Transport
2.42.x
Other Linux
: Normal normal
: ---
Assigned To: libsoup-maint@gnome.bugs
libsoup-maint@gnome.bugs
Depends on:
Blocks:
 
 
Reported: 2013-05-16 16:52 UTC by Richard Röjfors
Modified: 2013-06-08 23:37 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Fixes the ref leak (704 bytes, patch)
2013-05-21 09:37 UTC, Richard Röjfors
none Details | Review

Description Richard Röjfors 2013-05-16 16:52:15 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)
Comment 1 Dan Winship 2013-05-16 17:19:37 UTC
can you run valgrind with --num-callers=50 ?
Comment 2 Richard Röjfors 2013-05-16 22:46:34 UTC
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)
Comment 3 Dan Winship 2013-05-17 10:58:30 UTC
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?
Comment 4 Richard Röjfors 2013-05-17 14:10:36 UTC
(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.
Comment 5 Dan Winship 2013-05-17 16:36:48 UTC
(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...
Comment 6 Richard Röjfors 2013-05-21 09:36:25 UTC
(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.
Comment 7 Richard Röjfors 2013-05-21 09:37:03 UTC
Created attachment 244903 [details] [review]
Fixes the ref leak
Comment 8 Dan Winship 2013-05-21 12:53:56 UTC
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
Comment 9 Dan Winship 2013-06-08 23:37:50 UTC
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.