Bug#996805: nemo: Freezes when opening a folder that contains a large GIF file

2021-10-22 Thread Fabio Fantoni

Control: affects -1 + gdk-pixbuf

Il 22/10/2021 05:21, Johan Croft ha scritto:

Hello,

I decided to take another shot at this and I still can't believe it, 
but I actually ended up fixing it.


Hooking a debugger to Nemo and stopping it in the middle of the freeze 
shows that it's hanging inside libgdk_pixbuf-2.0.so. More 
specifically, once Nemo calls gdk_pixbuf_loader_write() inside 
get_pixbuf_for_content() (in nemo-directory-async.c) the function 
takes a very long time to return or never returns at all for very 
large GIFs. Most likely, this means there's a regression inside 
libgdk_pixbuf-2.0.so, which also makes sense in the context of my 
original report: the bug is present in Debian 11 and Arch (both use 
version 2.42), but not in Debian 10 (which uses version 2.38) nor in 
Mint 20.1 (which uses version 2.40). The code of 
get_pixbuf_for_content() between Debian and Mint's source packages is 
also the same, and doesn't change for Nemo 5.0.3 either, so the whole 
picture is congruent. I tried "forward-porting" Buster's libgdk_pixbuf 
just for confirmation, but unfortunately that doesn't seem compatible 
with the rest of the system.


When looking at get_pixbuf_for_content(), there's a comment mentioning 
the need to call gdk_pixbuf_loader_write() with chunks of the file to 
process, however Nemo's implementation doesn't actually do this and 
shoves the whole file in one go at gdk_pixbuf_loader_write() which 
then seems to choke on it. Making slight adjustments so that the file 
is actually served in chunks as the comment mentions actually fixes 
the whole issue. I recompiled Nemo with such changes and the fix seems 
to hold.


Nemo's original get_pixbuf_for_content() is pretty self-contained so 
it can be extracted into a standalone program of just a handful of 
lines as a minimal reproducible example. I did it and tried it both on 
Debian 11 and Mint 20.1 and the behavior is as expected: it freezes on 
Debian but works on Mint. I also tested the changes in this way to 
take time measurements for different chunk sizes and compare 
performance between the fixed version and the original one on Mint.


I'm attaching a patch for Nemo's get_pixbuf_for_content() as well as 
the examples mentioned (which aren't very nice, but should be good 
enough to illustrate). I hope this is useful. This is my first time 
reporting an issue on and making a submission to an open source 
project, so I apologize if something doesn't turn out to be tidy enough.


My only other question is whether there's any chance of seeing this 
properly fixed for Bullseye in some way in the future.



Thanks for your contribution, I don't have time to look better to this 
now, I think will be better to check on gdk-pixbuf if a better fix is 
needed on it




OpenPGP_0x680668AE907F101D.asc
Description: OpenPGP public key


OpenPGP_signature
Description: OpenPGP digital signature


Bug#996805: nemo: Freezes when opening a folder that contains a large GIF file

2021-10-22 Thread Johan Croft
Hello,

I decided to take another shot at this and I still can't believe it, but I 
actually ended up fixing it.

Hooking a debugger to Nemo and stopping it in the middle of the freeze shows 
that it's hanging inside libgdk_pixbuf-2.0.so. More specifically, once Nemo 
calls gdk_pixbuf_loader_write() inside get_pixbuf_for_content() (in 
nemo-directory-async.c) the function takes a very long time to return or never 
returns at all for very large GIFs. Most likely, this means there's a 
regression inside libgdk_pixbuf-2.0.so, which also makes sense in the context 
of my original report: the bug is present in Debian 11 and Arch (both use 
version 2.42), but not in Debian 10 (which uses version 2.38) nor in Mint 20.1 
(which uses version 2.40). The code of get_pixbuf_for_content() between Debian 
and Mint's source packages is also the same, and doesn't change for Nemo 5.0.3 
either, so the whole picture is congruent. I tried "forward-porting" Buster's 
libgdk_pixbuf just for confirmation, but unfortunately that doesn't seem 
compatible with the rest of the system.

When looking at get_pixbuf_for_content(), there's a comment mentioning the need 
to call gdk_pixbuf_loader_write() with chunks of the file to process, however 
Nemo's implementation doesn't actually do this and shoves the whole file in one 
go at gdk_pixbuf_loader_write() which then seems to choke on it. Making slight 
adjustments so that the file is actually served in chunks as the comment 
mentions actually fixes the whole issue. I recompiled Nemo with such changes 
and the fix seems to hold.

Nemo's original get_pixbuf_for_content() is pretty self-contained so it can be 
extracted into a standalone program of just a handful of lines as a minimal 
reproducible example. I did it and tried it both on Debian 11 and Mint 20.1 and 
the behavior is as expected: it freezes on Debian but works on Mint. I also 
tested the changes in this way to take time measurements for different chunk 
sizes and compare performance between the fixed version and the original one on 
Mint.

I'm attaching a patch for Nemo's get_pixbuf_for_content() as well as the 
examples mentioned (which aren't very nice, but should be good enough to 
illustrate). I hope this is useful. This is my first time reporting an issue on 
and making a submission to an open source project, so I apologize if something 
doesn't turn out to be tidy enough.

My only other question is whether there's any chance of seeing this properly 
fixed for Bullseye in some way in the future.--- ../original/nemo-4.8.6/libnemo-private/nemo-directory-async.c	2021-03-05 08:57:48.0 -0500
+++ libnemo-private/nemo-directory-async.c	2021-10-21 22:27:11.0 -0400
@@ -3902,7 +3902,7 @@
 	gboolean res;
 	GdkPixbuf *pixbuf, *pixbuf2;
 	GdkPixbufLoader *loader;
-	gsize chunk_len;
+	gsize chunk_len = 1;
 	pixbuf = NULL;
 	
 	loader = gdk_pixbuf_loader_new ();
@@ -3912,12 +3912,20 @@
 
 	/* For some reason we have to write in chunks, or gdk-pixbuf fails */
 	res = TRUE;
-	while (res && file_len > 0) {
+	while (res && file_len > chunk_len) {
+		res = gdk_pixbuf_loader_write (loader, (guchar *) file_contents, chunk_len, NULL);
+		file_contents += chunk_len;
+		file_len -= chunk_len;
+	}
+
+	if (res && file_len != 0)
+	{
 		chunk_len = file_len;
 		res = gdk_pixbuf_loader_write (loader, (guchar *) file_contents, chunk_len, NULL);
 		file_contents += chunk_len;
 		file_len -= chunk_len;
 	}
+
 	if (res) {
 		res = gdk_pixbuf_loader_close (loader, NULL);
 	}
//needs libgdk-pixbuf2.0-dev installed.
//Compile with g++ mre_original.cpp -L/usr/lib/x86_64-linux-gnu/  -lgdk_pixbuf-2.0 -lglib-2.0 -lgobject-2.0 -I/usr/include/gdk-pixbuf-2.0/gdk-pixbuf/ -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -o original


#include 
#include 

#include "gdk-pixbuf.h"

#include 

using namespace std;

static GdkPixbuf *
get_pixbuf_for_content (int file_len,
			char *file_contents);

int main(int argc, char *argv[])
{
	if(argc != 2)
	{
		printf("wrong number of arguments\n");
		exit(123);
	}

	char *filePath=argv[1];

	FILE *fp = fopen(filePath, "rb");

	if(fp==nullptr)
	{
		printf("error openning file\n");
		exit(123);
	}

	fseek(fp, 0, SEEK_END);

	int size = ftell(fp);

	fseek(fp, 0, SEEK_SET);

	std::vector fileContents;

	fileContents.resize(size);

	char * ptr = fileContents.data();

	int readQty = fread(ptr, 1, size, fp);
	fclose(fp);

	if(readQty != size)
	{
		printf("error reading file: read: %d, size: %d\n", readQty, size);
		exit(123);
	}

	get_pixbuf_for_content(size, ptr);

	return 0;
}



static GdkPixbuf *
get_pixbuf_for_content (int file_len,
			char *file_contents)
{
	gboolean res;
	GdkPixbuf *pixbuf, *pixbuf2;
	GdkPixbufLoader *loader;
	gsize chunk_len;
	pixbuf = NULL;

	loader = gdk_pixbuf_loader_new ();

	/* For some reason we have to write in chunks, or gdk-pixbuf fails */
	res = TRUE;
	while (res && file_len > 0) {
		chunk_len = file_len;
		res = 

Bug#996805: nemo: Freezes when opening a folder that contains a large GIF file

2021-10-19 Thread Johan Croft
Package: nemo
Version: 4.8.6-2
Severity: normal
X-Debbugs-Cc: jcdeb...@protonmail.ch

Dear Maintainer,


   * What led up to the situation?
After Upgrading to Debian 11, opening a folder that contained a big GIF 
file caused all open Nemo windows to freeze. Opening a single folder with a 
10MB GIF causes every opened Nemo window to freeze for about 20 seconds and to 
use 100% of a processor core on a Ryzen 5900X system. This only happens when 
using Icon view for the folder in question and only when using the maximum zoom 
available. It does not happen in List view nor in Compact view nor at smaller 
zoom levels. It did not happen on Debian 10. The bigger the GIF file the more 
Nemo takes to unfreeze. I have a directory with a few much bigger GIF files in 
it and I cannot visit it on my system, while other folders with smaller GIFs 
take many seconds to load.
   * What exactly did you do (or not do) that was effective (or
 ineffective)?
I tried a clean installation of Debian 11 on a virtual machine to rule 
out configuration issues with my system, and I was able to reproduce the issue 
on the VM as well. I also upgraded the VM to testing (which has Nemo 5.0.3), 
and it seems it is also affected by the issue.

I looked for a solution online and found a Linux Mint bugtracker issue 
regarding slowdowns when icon captions are enabled, but disabling them did not 
change anything. It is worth noting however that it is coincidentally at the 
maximum zoom level that more captions show. There is additionally an issue on 
their bugtracker describing the same problem I am reporting, reported by an 
Arch user (see https://github.com/linuxmint/nemo/issues/2756), however it seems 
the Mint team was unable to reproduce it. I proceeded to make a VM with Linux 
Mint 20.1 and I could not reproduce the issue either despite the fact that Mint 
20.1 ships with the same Nemo version as Debian 11 (Nemo 4.8.6), so it seems 
this might be an issue with other distributions.

Disabling thumbnails effectively makes the issue disappear. Nemo uses 
gdk-pixbuf-thumbnailer to generate thumbnails for GIF files, but running the 
same command Nemo uses to create a thumbnail for a big GIF on the command line 
exits immediately with success. I attempted to configure ffmpegthumbnailer to 
be used for GIF files thumbnail generation and it didn't seem to have any 
effect on Nemo freezing either.

Running nemo --debug on a folder with a large GIF file does not seem to 
provide any hints. Running strace on nemo in the same conditions shows nemo 
hangs in a loop calling mmap/mremap, however that's not very helpful. I'm out 
of ideas on how to debug further. Considering the ease of reproduction and that 
the logs don't seem to point to anything evident, I'm not including them in 
this report, but I can include them later on if necessary.
   * What was the outcome of this action?
Nothing really worked. The only solution is to dodge the issue by 
disabling thumbnails or using other view styles or zoom levels.
   * What outcome did you expect instead?
The folder with the large GIF file to open in a reasonable amount of 
time with no system effort.

Test GIFs of different sizes can be generated with ease from any video 
with ffmpeg (e.g. ffmpeg -t 5 -i  output.gif). Every one I tried 
caused the same issue.

-- System Information:
Debian Release: 11.1
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable-security'), (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 5.10.0-9-amd64 (SMP w/2 CPU threads)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages nemo depends on:
ii  cinnamon-desktop-data  4.8.1-2
ii  desktop-file-utils 0.26-1
ii  gsettings-desktop-schemas  3.38.0-2
ii  gvfs   1.46.2-1
ii  libatk1.0-02.36.0-2
ii  libc6  2.31-13+deb11u2
ii  libcairo-gobject2  1.16.0-5
ii  libcairo2  1.16.0-5
ii  libcinnamon-desktop4   4.8.1-2
ii  libexempi8 2.5.2-1
ii  libexif12  0.6.22-3
ii  libgail-3-03.24.24-4
ii  libgdk-pixbuf-2.0-02.42.2+dfsg-1
ii  libglib2.0-0   2.66.8-1
ii  libglib2.0-data2.66.8-1
ii  libgtk-3-0 3.24.24-4
ii  libnemo-extension1 4.8.6-2
ii  libnotify4 0.7.9-3
ii  libpango-1.0-0 1.46.2-3
ii  libpangocairo-1.0-01.46.2-3
ii  libselinux13.1-3
ii  libx11-6   2:1.7.2-1
ii  libxapp1   2.0.7-1
ii  libxml22.9.10+dfsg-6.7
ii  nemo-data  4.8.6-2
ii  shared-mime-info   2.0-1

Versions of packages nemo recommends:
ii  cinnamon-l10n4.8.3-1
ii  gvfs-backends