vfprintf() has a 4096-byte memory leak?

Dan Nelson dnelson at allantgroup.com
Sat Aug 2 13:51:05 PDT 2003


In the last episode (Aug 02), Ryan T. Dean said:
> Aha.  setbuf(stdout, NULL); does prevent the buffer from being
> allocated. However, in the case of stdout and stderr, if you don't
> setbuf() it to null, a buffer is malloc'd.  The corresponding free()
> is in fclose.  So, if you [f]printf() to stdout/stderr, and
> fclose(stdout/stderr), you are fine.  If, however, you don't know
> that buffers are being allocated for stdin/stdout and don't fclose()
> or setbuf() to NULL, a 4096-byte chunk of memory is allocated and
> never freed.  For shits and giggles, I checked a DeadRat 8 box - no
> buffering by default.  I guess the only reason I'm worried is the
> potential number of programs in the ports tree originally written on
> a system where stdout/stderr behave differently, or people (like
> myself) who didn't have a clue any sort of output buffering was
> enabled on stdout/stderr, and as a result have memory leaks.  If the
> porter did their job, it shouldn't be an issue (was caught, patched,
> and the patch submitted upstream), but, then, we never know, right?

A memory leak is memory allocated, used, then discarded by the program
without freeing, possibly repeatedly so you build up memory that the
program never uses and cannot reclaim.  These buffers /are/ used, every
time you use stdio to stdout or stderr, so it's not a leak.  They're
simply not freed on exit.

> int main (void)
> {
>   printf("Test\n");
>   return 0;
> }
> test1 memory debug output:
> 1059825156: 1: *** alloc: at 'ra=0x2816ee86' for 4096 bytes, got '0x804b008|s1'
> 1059825156: 1: top 10 allocations:
> 1059825156: 1:  total-size  count in-use-size  count  source
> 1059825156: 1:        4096      1        4096      1  ra=0x2816ee86
> 1059825156: 1:        4096      1        4096      1  Total of 1
> 1059825156: 1: dumping not-freed pointers changed since 0:
> 1059825156: 1:  not freed: '0x804b008|s1' (4096 bytes) from 'ra=0x2816ee86'
> 1059825156: 1:  total-size  count  source
> 1059825156: 1:        4096      1  ra=0x2816ee86
> 1059825156: 1:        4096      1  Total of 1
> 1059825156: 1:  unknown memory: 1 pointer, 4096 bytes

The stdio buffers are correctly flushed by exit(), but fclose() is not
called to free the buffers.  Why bother when the memory will be
deallocated in .0001 seconds when the process exits? :)  If you want,
you can swap the comment on the two lines in
src/lib/libc/stdio/findfp.c to close all open files on exit:

void
_cleanup()
{   
    /* (void) _fwalk(fclose); */
    (void) _fwalk(__sflush);        /* `cheating' */
}


-- 
	Dan Nelson
	dnelson at allantgroup.com


More information about the freebsd-current mailing list