Bug 222951

Summary: gdk_pixbuf_loader_write() failure leaks memory
Product: [Fedora] Fedora Reporter: David Nečas <yeti>
Component: gtk+Assignee: Matthias Clasen <mclasen>
Status: CLOSED CURRENTRELEASE QA Contact: David Lawrence <dkl>
Severity: medium Docs Contact:
Priority: medium    
Version: 6   
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2007-02-25 16:14:11 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
test program C source none

Description David Nečas 2007-01-16 23:21:16 UTC
Description of problem:
GdkPixbufLoaders are closed when an error in gdk_pixbuf_loader_write() occurs.
And they leak memory when they do.

Version-Release number of selected component (if applicable):
gtk2-2.10.4-10.fc6

How reproducible:
Always.


Steps to Reproduce:
1. Consider the attached program that gets the list of pixbuf loaders,
instantiates them, writes some junk data to make them fail and then tries to
clean up.

2. Compile it
gcc -Wall -W -DOLD_STYLE_FINALIZATION $(pkg-config --cflags --libs
gdk-pixbuf-2.0) -o pixbuf-ctx-leak pixbuf-ctx-leak.c
and run
valgrind ./pixbuf-ctx-leak

3. Compile it
gcc -Wall -W $(pkg-config --cflags --libs gdk-pixbuf-2.0) -o pixbuf-ctx-leak
pixbuf-ctx-leak.c
and run
valgrind ./pixbuf-ctx-leak

  
Actual results:
In both cases 2 and 3:
==6619== Memcheck, a memory error detector.
==6619== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al.
==6619== Using LibVEX rev 1658, a library for dynamic binary translation.
==6619== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP.
==6619== Using valgrind-3.2.1, a dynamic binary instrumentation framework.
==6619== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al.
==6619== For more details, rerun with: -v
==6619== 
wbmp: gdk_pixbuf_loader_write() unexpectedly succeeded.
wmf: gdk_pixbuf_loader_write() unexpectedly succeeded.
ERROR: meta.c (179): wmf_header_read: this isn't a wmf file
jpeg: gdk_pixbuf_loader_write() failed (as expected): Error interpreting JPEG
image file (Not a JPEG file: starts with 0x44 0x6f)
ani: gdk_pixbuf_loader_write() failed (as expected): Invalid header in animation
bmp: gdk_pixbuf_loader_write() failed (as expected): Not enough memory to load
bitmap image
gif: gdk_pixbuf_loader_write() failed (as expected): File does not appear to be
a GIF file
ico: gdk_pixbuf_loader_write() unexpectedly succeeded.
pcx: gdk_pixbuf_loader_write() failed (as expected): Image has invalid width
and/or height
png: gdk_pixbuf_loader_write() failed (as expected): Fatal error reading PNG
image file: Not a PNG file
pnm: gdk_pixbuf_loader_write() failed (as expected): PNM file has an incorrect
initial byte
ras: gdk_pixbuf_loader_write() failed (as expected): RAS image has bogus header data
tga: gdk_pixbuf_loader_write() failed (as expected): TGA image type not supported
xbm: gdk_pixbuf_loader_write() unexpectedly succeeded.
tiff: gdk_pixbuf_loader_write() unexpectedly succeeded.
xpm: gdk_pixbuf_loader_write() unexpectedly succeeded.
svg: gdk_pixbuf_loader_write() failed (as expected): Error writing
==6619== 
==6619== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 1)
==6619== malloc/free: in use at exit: 327,835 bytes in 1,018 blocks.
==6619== malloc/free: 2,532 allocs, 1,514 frees, 1,636,349,655 bytes allocated.
==6619== For counts of detected errors, rerun with: -v
==6619== searching for pointers to 1,018 not-freed blocks.
==6619== checked 1,208,528 bytes.
==6619== 
==6619== LEAK SUMMARY:
==6619==    definitely lost: 166,739 bytes in 27 blocks.
==6619==      possibly lost: 5,648 bytes in 23 blocks.
==6619==    still reachable: 155,448 bytes in 968 blocks.
==6619==         suppressed: 0 bytes in 0 blocks.
==6619== Use --leak-check=full to see details of leaked memory.


Expected results:
Much less definitely lost memory in LEAK SUMMARY.  There is a small constant
amount (48 bytes on x86_64) that valgrind reports as lost due to an GObject
initialization trickery, but the rest seems to be a real leak.


Additional info:
Case 3 is clean up according to the documentation, case 2 is the traditional
clean up (see bug 220562).  They work identically now, they are listed both to
check they work identically also after the eventual fix.

Run valgrind with --leach-check=full to see all the strack traces, however the
individual leaks are similar and look like (FOO is the loader type):
==7651== 4,216 bytes in 1 block are definitely lost in loss record 158 of 177
==7651==    at 0x4A05879: malloc (vg_replace_malloc.c:149)
==7651==    by 0x6048E4A: gdk_pixbuf__FOO_image_begin_load (io-FOO.c:816)
==7651==    by 0x3956A091A3: gdk_pixbuf_loader_load_module (gdk-pixbuf-loader.c:374)
==7651==    by 0x3956A098C0: gdk_pixbuf_loader_new_with_type
(gdk-pixbuf-loader.c:533)
==7651==    by 0x400A14: main (pixbuf-ctx-leak.c:28)

The amount of memory lost increases linearly with the number of repetions of the
whole procedure (if one tries it) which indicates the leaks are real.

When the loaders are closed immediately, they do not leak memory (well, except
svg which seems to leak something and wmf which crashes, but they do not belong
to gtk2 package).

The test program is not capable of making all loaders to fail, some perhaps do
not support partial image loading and thus gdk_pixbuf_loader_write() never fails.

I would report it to GNOME bugzilla, but I'm confused which upstream version the
Fedora pixbuf loader code matches, if any...

Comment 1 David Nečas 2007-01-16 23:21:17 UTC
Created attachment 145755 [details]
test program C source

Comment 2 Matthias Clasen 2007-01-17 04:57:02 UTC
Thanks for that testcase. I think the right fix is to just call
gdk_pixbuf_loader_close instead of duplicating part of that function in the
error case in gdk_pixbuf_loader_write

Comment 3 Matthias Clasen 2007-02-25 16:14:11 UTC
This has been fixed in the meantime.