Hello,
After a few hours of investigation I've tracked down this bug. At least I've
discovered what code causes Xserver to leak memory, when the bug is
"exploited" by gpdf. It's as simple as the following:
cursor = gdk_cursor_new_for_display(display, GDK_WATCH);
// ... //
gdk_cursor_unref(cursor);
This code gets repeated approx. twice as many times as there are pages in the
pdf (when processing both bookmarks and thumbnails). While this is the bug in
the gpdf itself (the cursor should not be set so many times), it reveals
the bug in the X server. X footprint keeps growing because of repeatable
memory allocations for the cursor and gdk_cursor_unref() failures to free that
memory. However, this doesn't happen with all types of cursors. Only
*animated* ones are affected (I base this hypothesis on my tests). Memory
occupied by static cursors gets freed properly by the gdk_cursor_unref()
routine. This explains why other people are not suffering from this bug.
I've made a simple gtk program, which starts executing the code above infinite
number times once you press the "Test memleak!" button (thus you will need to
use CTRL+C or `kill` to terminate the program). Here it's the step-by-step
guide to reproduce the memleak:
1. Make sure your "watch" cursor is the animated one or change the argument 2
of the gdk_cursor_new_for_display() accordingly to the cursor which is
animated in the theme you're using. If neither is animated, you can obtain one
from [1] or other source. I extracted the "watch" cursor from this theme and
put it on my web site[2]. Simply place it into ~/.icons/<your current xcursor
theme name (in case of "core", use "default")>/cursors/watch This should be
enough to reproduce the bug without restarting X.
2. Compile memleak.c from [3] with the following command (you will need
libgtk2.0-dev and its dependences for this):
gcc memleak.c -o memleak -I/usr/include/gtk-2.0 -I/usr/include/glib-2.0
-I/usr/lib/gtk-2.0/include -I/usr/lib/glib-2.0/include
-I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -L/usr/lib -lgtk-x11-2.0
and start the program.
3. Press the "Test memleak!" button in the GUI and observe X server memory
usage ("RES" field with `top`). If you have a fast pc, X should consume
hundreds MBs of memory *very* quickly.
4. To kill the program use CTRL+C or `kill` (it's my first gtk program ever,
so I haven't invested more time in making termination more sophisticated)
Another interesting thing is that X seems to reuse the allocated memory for
sequent cursor allocations in other programs (like another instance of
`memleak`) once the program triggering the bug gets terminated. Test this by
running several instances of `memleak` one after another.
So for now till someone with more knowlegde of XFree86 code fixes the bug a
simple workaround is to avoid animated cursors. There may be a bug in
gdk_cursor_unref() too, I haven't checked the code. In any case, I think it's
a big (security?) problem in the X server code, because any malicious app can
make X server (which is generally running as root on most systems with DM)
use large amounts of memory by repeatedly allocating memory for the cursor
and not freeing it aftwerwards.
It would be great if someone could test this test case on Xorg. Lots of
distros include animated watch cursors by default these days, and if these
are big, lots of people might be suffering from this bug.
The "fixed" gpdf (with the offensive code commented out) is available here[4]
(the binary for i386, provided there, is compiled w/o optimizations and
debugging symbols are unstripped)
Related bugs in other locations (neither of which is marked as fixed):
https://bugs.freedesktop.org/show_bug.cgi?id=1043
http://bugs.gentoo.org/show_bug.cgi?id=31982
[1]. http://www.kde-look.org/content/show.php?content=18214
[2]. http://mif.vu.lt/~mova3971/xf/watch
[3]. http://mif.vu.lt/~mova3971/xf/memleak.c
[4]. http://mif.vu.lt/~mova3971/xf/gpdf
Attachment:
pgp7m0kffffdI.pgp
Description: PGP signature