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 645015 - Crash in g_object_unref, image_download_cb
Crash in g_object_unref, image_download_cb
Status: RESOLVED FIXED
Product: rhythmbox
Classification: Other
Component: general
0.13.x
Other All
: Normal critical
: ---
Assigned To: RhythmBox Maintainers
RhythmBox Maintainers
: 650954 652815 652989 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2011-03-17 13:22 UTC by Stanislav Brabec
Modified: 2011-08-15 16:22 UTC
See Also:
GNOME target: ---
GNOME version: 2.31/2.32


Attachments
audioscrobbler: ensure RBAudioscrobblerUserData stays alive for image download (14.24 KB, patch)
2011-06-20 17:02 UTC, Jamie Nicol
committed Details | Review
audioscrobbler: keep RBAudioscrobblerUserData alive for image download (16.58 KB, patch)
2011-06-20 22:32 UTC, Jamie Nicol
rejected Details | Review

Description Stanislav Brabec 2011-03-17 13:22:01 UTC
Version: 0.13.3

What were you doing when the application crashed?
Starting session, saved session contained rhythmbox


Distribution: openSUSE 11.4 (x86_64)
Gnome Release: 2.32.1 (null) (SUSE)
BugBuddy Version: 2.32.0

System: Linux 2.6.37.1-1.2-desktop #1 SMP PREEMPT 2011-02-21 10:34:10 +0100 x86_64
X Vendor: The X.Org Foundation
X Vendor Release: 10903000
Selinux: No
Accessibility: Disabled
GTK+ Theme: Gilouche
Icon Theme: Gilouche
GTK+ Modules: gnomesegvhandler, canberra-gtk-module

Memory status: size: 909955072 vsize: 909955072 resident: 62144512 share: 28778496 rss: 62144512 rss_rlim: 18446744073709551615
CPU usage: start_time: 1300367964 rtime: 102 utime: 79 stime: 23 cutime:0 cstime: 0 timeout: 0 it_real_value: 0 frequency: 100

Backtrace was generated from '/usr/bin/rhythmbox'

[Thread debugging using libthread_db enabled]
[New Thread 0x7f0feba0d700 (LWP 4392)]
[New Thread 0x7f0feb20c700 (LWP 4365)]
[New Thread 0x7f0fdeeeb700 (LWP 4327)]
[New Thread 0x7f0fdf6ec700 (LWP 4326)]
[New Thread 0x7f0fdfeed700 (LWP 4325)]
[New Thread 0x7f0fe06ee700 (LWP 4324)]
[New Thread 0x7f0fe0eef700 (LWP 4323)]
[New Thread 0x7f0fe16f0700 (LWP 4322)]
[New Thread 0x7f0fe1ef1700 (LWP 4321)]
[New Thread 0x7f0fe26f2700 (LWP 4320)]
[New Thread 0x7f0fe2ef3700 (LWP 4319)]
[New Thread 0x7f0fe36f4700 (LWP 4318)]
[New Thread 0x7f0ff6823700 (LWP 4114)]
0x00007f1004820e6d in __libc_waitpid (pid=<value optimized out>, stat_loc=<value optimized out>, options=<value optimized out>) at ../sysdeps/unix/sysv/linux/waitpid.c:41
	in ../sysdeps/unix/sysv/linux/waitpid.c

Thread 1 (Thread 0x7f1006b95800 (LWP 4089))

  • #0 __libc_waitpid
    at ../sysdeps/unix/sysv/linux/waitpid.c line 41
  • #1 g_spawn_sync
    at gspawn.c line 392
  • #2 g_spawn_command_line_sync
    at gspawn.c line 706
  • #3 run_bug_buddy
    at gnome-segvhanlder.c line 240
  • #4 bugbuddy_segv_handle
    at gnome-segvhanlder.c line 191
  • #5 <signal handler called>
  • #6 g_object_unref
    at gobject.c line 2668
  • #7 image_download_cb
    at rb-audioscrobbler-user.c line 1607
  • #8 complete_in_idle_cb
    at gsimpleasyncresult.c line 757
  • #9 g_main_dispatch
    at gmain.c line 2440
  • #10 g_main_context_dispatch
    at gmain.c line 3013
  • #11 g_main_context_iterate
    at gmain.c line 3091
  • #12 g_main_loop_run
    at gmain.c line 3299
  • #13 IA__gtk_main
    at gtkmain.c line 1237
  • #14 main
    at main.c line 336

	Inferior 1 [process 4089] will be detached.

Quit anyway? (y or n) [answered Y; input not from terminal]


---- Critical and fatal warnings logged during execution ----

** GLib-GObject **: g_object_unref: assertion `G_IS_OBJECT (object)' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 
** GdkPixbuf **: gdk_pixbuf_new_from_file_at_scale: assertion `filename != NULL' failed 


----------- .xsession-errors ---------------------
Missing separate debuginfo for /usr/lib64/python2.7/lib-dynload/zlib.so
Try: zypper install -C "debuginfo(build-id)=42167cb089d4579637b654e4a658058706eef9ae"
Missing separate debuginfo for /usr/lib64/python2.7/lib-dynload/_io.so
Try: zypper install -C "debuginfo(build-id)=fd12fa5504b3694c3f0a6a1bfdafde5724c889a1"
Missing separate debuginfo for /usr/lib64/python2.7/site-packages/gtk-2.0/gnomekeyring.so
Try: zypper install -C "debuginfo(build-id)=cb01ab29619e6839202b7e4fbce49d531b9fe505"
Missing separate debuginfo for /usr/lib64/python2.7/lib-dynload/grp.so
Try: zypper install -C "debuginfo(build-id)=2baf5609989edfca3c449ae553a88c90c66910af"
Missing separate debuginfo for /usr/lib64/libmtp.so.8
Try: zypper install -C "debuginfo(build-id)=f999ca3627b01f27e7c54d3f2143fecfb2d9beb3"
Missing separate debuginfo for /usr/lib64/libusb-0.1.so.4
Try: zypper install -C "debuginfo(build-id)=780d855a97565edf4c744f7dd69595a5f4f7d776"
Missing separate debuginfo for /usr/lib64/libusb-1.0.so.0
Try: zypper install -C "debuginfo(build-id)=7a7220cc354fd81578f4de64ecd6281f176809e6"
41	../sysdeps/unix/sysv/linux/waitpid.c: Adresář nebo soubor neexistuje.
--------------------------------------------------
Comment 1 Jonathan Matthew 2011-03-19 10:28:51 UTC
Jamie, any ideas about this?  It's not immediately obvious why it'd be crashing, and I can't see why we'd be calling gdk_pixbuf_new_from_file_at_scale with a bad filename either.
Comment 2 Jamie Nicol 2011-03-21 01:09:41 UTC
Not got a clue. I can't pretend that that's a particularly well written function (or entire file), but I don't understand why this crash has happened.

I'm going to be crazy busy this next week--my uni project is due on friday--but after that I can try to give it a more in depth look.

On the off-chance that the reporter hasn't used last.fm in rhythmbox since the crash happened, perhaps the contents of ~/.cache/rhythmbox could be useful.
Comment 3 Stanislav Brabec 2011-03-21 15:14:41 UTC
I used rhythmbox after that crash.

I just disabled booklet plugin and not seen crash any more. Now I re-enabled it and it does not crash as well, however some images are not found and waiting animation is displayed.

So the crash is not reproducible.

Note that I don't have any last.fm profile photo uploaded.

Log shows lots of these errors:
(rhythmbox:31971): Rhythmbox-WARNING **: eel_strdup_strftime does not support non-standard escape code %e
Comment 4 Akhil Laddha 2011-05-24 15:07:05 UTC
*** Bug 650954 has been marked as a duplicate of this bug. ***
Comment 5 Fabio Durán Verdugo 2011-06-17 13:22:35 UTC
*** Bug 652815 has been marked as a duplicate of this bug. ***
Comment 6 Jamie Nicol 2011-06-17 22:28:26 UTC
Spent some time with my brother thinking this through and I think we've found the problem:

We initially make an array of RBAudioscrobblerUserData, eg my top tracks, from either the cache or a request to last.fm. If a track is missing an image a download is started.

Suppose whilst the image is downloading the profile gets refreshed. A new top tracks request is sent.

In top_tracks_response_cb (or equivalent): the old array of data is freed so the new array can be stored. The image being downloaded is for an RBAudioscrobblerUserData which no longer exists.

image_download_cb: Image download finishes, looks up data in file_to_data_map, but this is now garbage. Meaning data->image could be non-null but also not a valid gobject => g_object_unref segfaults.

calculate_cached_image_path: data is garbage meaning that data->type could be anything. The lack of a default block means image path remains NULL. This explains the warnings from GdkPixbuf.

Fixes I can think of are: a) Cancel the download before the RBAudioscrobblerUserData is freed. b) Again, before the RBAudioscrobblerUserData is freed, remove the download file from the file_to_data_map. Then in the callback handle such a case properly (by not crashing). The second has the advantage that the download is allowed to finish.

If this sounds sensible then patch forthcoming.
Comment 7 Jonathan Matthew 2011-06-18 01:43:55 UTC
Yes, that sounds sensible.  I think allowing the download to finish would be better.  Looking at this code again, I suspect we're leaking a reference to the source file for the downloads too.
Comment 8 Jamie Nicol 2011-06-19 18:19:21 UTC
In download_image (), where I've written

	src_file = g_file_new_for_uri (image_url);

	/* only start a download if the file is not already being downloaded */
	if (g_hash_table_lookup (user->priv->file_to_data_map, src_file) == NULL) {
		<snip>
	}

does that actually make any sense? Even if that image url is being downloaded already, it'll be a different GFile object surely?

But suppose we were to actually do what this line is intended to, by having a url to gfile map and checking if a url lookup succeeds. Then if we were to do something along the lines of:

	/* only start a download if the file is not already being downloaded */
	src_file = g_hash_table_lookup (user->priv->url_to_file_map, image_url)
	if (src_file == NULL) {
		/* download file */
	} else {
		/* file's old data points to garbage. replace with new one */
		g_hash_table_insert (user->priv->file_to_data_map, src_file, data);
	}

I think this would also fix the bug, but I'm not 100% confident, and it's making my head hurt.
The callback wouldn't need to be edited (except to unref src_file, as you mentioned), nor would the array deletion code.

What do you think?
Comment 9 Jonathan Matthew 2011-06-20 10:23:00 UTC
(In reply to comment #8)
> In download_image (), where I've written
> 
>     src_file = g_file_new_for_uri (image_url);
> 
>     /* only start a download if the file is not already being downloaded */
>     if (g_hash_table_lookup (user->priv->file_to_data_map, src_file) == NULL) {
>         <snip>
>     }
> 
> does that actually make any sense? Even if that image url is being downloaded
> already, it'll be a different GFile object surely?

Yes.. we could use g_file_hash and g_file_equal as the hash and equal functions for this hash table.  Probably use g_object_unref as the key destroy function too.

> But suppose we were to actually do what this line is intended to, by having a
> url to gfile map and checking if a url lookup succeeds. Then if we were to do
> something along the lines of:
> 
>     /* only start a download if the file is not already being downloaded */
>     src_file = g_hash_table_lookup (user->priv->url_to_file_map, image_url)
>     if (src_file == NULL) {
>         /* download file */
>     } else {
>         /* file's old data points to garbage. replace with new one */
>         g_hash_table_insert (user->priv->file_to_data_map, src_file, data);
>     }
> 
> I think this would also fix the bug, but I'm not 100% confident, and it's
> making my head hurt.
> The callback wouldn't need to be edited (except to unref src_file, as you
> mentioned), nor would the array deletion code.
> 
> What do you think?

I think we aren't guaranteed that an image that was needed before the top tracks response (or whatever) would be needed afterwards, so this wouldn't be enough by itself.

It seems like making RBAudioscrobblerUserData reference counted would fix this - the pointer arrays would have one reference, the download map would have another.  The download callback could check if the other reference was still alive before emitting the updated signals etc.
Comment 10 André Klapper 2011-06-20 11:18:02 UTC
*** Bug 652989 has been marked as a duplicate of this bug. ***
Comment 11 Jamie Nicol 2011-06-20 17:02:36 UTC
Created attachment 190294 [details] [review]
audioscrobbler: ensure RBAudioscrobblerUserData stays alive for image download

Make RBAudioscrobblerUserData refcounted and give the download map a reference.
Also make download maps responsible for unreffing their keys and values, and
fix a couple leaks.
Comment 12 Jamie Nicol 2011-06-20 17:15:25 UTC
Oops. Just to explain the patch a bit more in depth. I've basically done what you suggested in comment 9, and a couple other memory management fixes.

I have not done what I suggested in comment 8 as there can be more than one valid Data for each src_file. To fix this properly I think file_to_data_map would need its values to be lists of RBAudioscrobblerUserDatas rather than single ones. When the hash table lookup is succesful in download_image, append the data to the list. And in image_download_cb update the pixbuf and emit signals for each element (with refcount > 1).

For the time being though this should stop the segfault, but images will be missing for items if they were not the first item to require a download of the same image.
Comment 13 Jamie Nicol 2011-06-20 22:32:00 UTC
Created attachment 190321 [details] [review]
audioscrobbler: keep RBAudioscrobblerUserData alive for image download

Alternatively this patch keeps the hash tables using g_direct_hash instead of g_file_hash. The hash table lookup in download image is removed as it doesn't work with direct hash. Refcounting should fix the bug, and every item with an available image will download and display it. There will be multiple downloads of the same image, however.
Comment 14 Jonathan Matthew 2011-07-18 22:05:13 UTC
I'm OK with either of these, but I think I prefer the first one.
Comment 15 Jonathan Matthew 2011-07-18 22:05:41 UTC
Review of attachment 190321 [details] [review]:

ok
Comment 16 Jonathan Matthew 2011-07-18 22:05:56 UTC
Review of attachment 190294 [details] [review]:

also ok
Comment 17 Jamie Nicol 2011-07-21 09:25:11 UTC
I'm backpacking at the moment and my only internet access is the occasional internet cafe. So I wont be able to commit anything for the next 3 or 4 weeks.
Comment 18 Jamie Nicol 2011-08-14 12:27:29 UTC
I've just pushed the first patch to master. I don't have permissions to mark the patches appropriately or close the bug, however.
Comment 19 Christophe Fergeau 2011-08-14 13:19:50 UTC
Jamie, you should now be able to mark the patches as committed and to close the bug
Comment 20 Jamie Nicol 2011-08-15 16:22:29 UTC
Thanks! 1st patch commited, 2nd rejected. Bug fixed.