From sean@farley.org  Tue Jan 28 10:27:39 2003
Return-Path: <sean@farley.org>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 0687C37B401
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 28 Jan 2003 10:27:39 -0800 (PST)
Received: from mail.farley.org (adsl-67-64-95-201.dsl.austtx.swbell.net [67.64.95.201])
	by mx1.FreeBSD.org (Postfix) with ESMTP id DE80843F43
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 28 Jan 2003 10:27:37 -0800 (PST)
	(envelope-from sean@farley.org)
Received: from thor.farley.org (781ievd6y4l1735r@thor.farley.org [192.168.1.5])
	by mail.farley.org (8.12.6/8.12.6) with ESMTP id h0SIRaAY062890
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 28 Jan 2003 12:27:37 -0600 (CST)
	(envelope-from sean@gw.farley.org)
Received: from thor.farley.org (localhost [127.0.0.1])
	by thor.farley.org (8.12.6/8.12.6) with ESMTP id h0SIRae1004043
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 28 Jan 2003 12:27:36 -0600 (CST)
	(envelope-from sean@thor.farley.org)
Received: (from sean@localhost)
	by thor.farley.org (8.12.6/8.12.6/Submit) id h0SIRadF004042;
	Tue, 28 Jan 2003 12:27:36 -0600 (CST)
	(envelope-from sean)
Message-Id: <200301281827.h0SIRadF004042@thor.farley.org>
Date: Tue, 28 Jan 2003 12:27:36 -0600 (CST)
From: "Sean C. Farley" <sean-freebsd@farley.org>
Reply-To: "Sean C. Farley" <sean-freebsd@farley.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: Memory leak on stdout
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         47599
>Category:       bin
>Synopsis:       Memory leak on stdout
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jan 28 10:30:01 PST 2003
>Closed-Date:    Tue Jan 28 12:40:35 PST 2003
>Last-Modified:  Tue Jan 28 17:40:10 PST 2003
>Originator:     Sean C. Farley
>Release:        FreeBSD 4.7-STABLE i386
>Organization:
>Environment:
System: FreeBSD thor.farley.org 4.7-STABLE FreeBSD 4.7-STABLE #13: Sat Jan 18 08:12:15 CST 2003 root@thor.farley.org:/usr/obj/usr/src/sys/THOR i386

>Description:

	When testing an application for memory leaks, I noticed one that
	I could not get rid of.  I happened to be allocated from
	/usr/src/lib/libc/stdio/makebuf.c on line 72, but only when
	printf() (or really any function) used stdout.  Adding an
	fclose(stdout) to the end of my application fixed the memory
	leak.

	I realize this is not much of a leak, but I thought it would be
	nice to have it either documented or fixed before others run
	into this confusing leak.

	Should standard I/O streams be closed automatically on exit?

>How-To-Repeat:
I used dmalloc (in the ports) for the testing.  The stdio source was
recompiled with dmalloc.h to give the line number and file where memory
was allocated.  If you recompile with fclose(stdout), the leak will go
away.

test.c:
#include <dmalloc.h>
#include <stdio.h>

int main(int argc,
         char **argv)
{
    printf("Hello, World\n");

    //fclose(stdout);

    exit(0);
}

Makefile for libstdio.a using sources from /usr/src/lib/libc/stdio:
CFLAGS=-include /usr/local/include/dmalloc.h -O -pipe -DLIBC_RCS -DSYSLIBC_RCS -I/usr/local/include -I/usr/src/lib/libc_r/../libc/include -DPTHREAD_KERNEL -D_THREAD_SAFE -I/usr/src/lib/libc_r/uthread -I/usr/src/lib/libc_r/../../include -D_LOCK_DEBUG -D_PTHREADS_INVARIANTS -D__DBINTERFACE_PRIVATE -DINET6 -DPOSIX_MISTAKE -I/usr/src/lib/libc_r/../libc/locale -DBROKEN_DES -DYP -DNDEBUG -g

LIB=	stdio
SRCS=  _flock_stub.c \
	asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c \
	fgetc.c fgetln.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \
	fprintf.c fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
	fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
	getc.c getchar.c gets.c getw.c makebuf.c mktemp.c perror.c \
	printf.c putc.c putchar.c puts.c putw.c refill.c remove.c rewind.c \
	rget.c scanf.c setbuf.c setbuffer.c setvbuf.c snprintf.c sprintf.c \
	sscanf.c stdio.c tempnam.c tmpfile.c tmpnam.c ungetc.c vasprintf.c \
	vfprintf.c vfscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c \
	vsscanf.c wbuf.c wsetup.c

.include <bsd.lib.mk>

compile application:
gcc -Wall -O -pipe -I/usr/local/include test.c stdio/libstdio.a -L/usr/local/lib -ldmalloc

configure dmalloc:
`dmalloc -l logfile -i 100 low`

run:
./a.out

output of logfile:
1043778209: 1: Dmalloc version '4.8.2' from 'http://dmalloc.com/'
1043778209: 1: flags = 0x4e40503, logfile 'logfile'
1043778209: 1: interval = 100, addr = 0, seen # = 0
1043778209: 1: starting time = 1043778209
1043778209: 1: free bucket count/bits: 
1043778209: 1: basic-block 4096 bytes, alignment 8 bytes, heap grows up
1043778209: 1: heap: 0x804f000 to 0x8052000, size 12288 bytes (3 blocks)
1043778209: 1: heap checked 0
1043778209: 1: alloc calls: malloc 1, calloc 0, realloc 0, free 0
1043778209: 1: alloc calls: recalloc 0, memalign 0, valloc 0
1043778209: 1:  total memory allocated: 4096 bytes (1 pnts)
1043778209: 1:  max in use at one time: 4096 bytes (1 pnts)
1043778209: 1: max alloced with 1 call: 4096 bytes
1043778209: 1: max alloc rounding loss: 4096 bytes (50%)
1043778209: 1: max memory space wasted: 0 bytes (0%)
1043778209: 1: final user memory space: basic 2, divided 0, 4096 bytes
1043778209: 1:  final admin overhead: basic 1, divided 0, 4096 bytes (33%)
1043778209: 1:  final external space: 0 bytes (0 blocks)
1043778209: 1: top 10 allocations:
1043778209: 1:  total-size  count in-use-size  count  source
1043778209: 1:        4096      1        4096      1  makebuf.c:72
1043778209: 1:        4096      1        4096      1  Total of 1
1043778209: 1: dumping not-freed pointers changed since 0:
1043778209: 1:  not freed: '0x8050008|s1' (4096 bytes) from 'makebuf.c:72'
1043778209: 1:  total-size  count  source
1043778209: 1:        4096      1  makebuf.c:72
1043778209: 1:        4096      1  Total of 1
1043778209: 1:  known memory: 1 pointer, 4096 bytes
1043778209: 1: ending time = 1043778209, elapsed since start = 0:00:00
>Fix:
>Release-Note:
>Audit-Trail:

From: David Schultz <dschultz@uclink.Berkeley.EDU>
To: "Sean C. Farley" <sean-freebsd@farley.org>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/47599: Memory leak on stdout
Date: Tue, 28 Jan 2003 12:11:45 -0800

 Thus spake Sean C. Farley <sean-freebsd@farley.org>:
 > 	When testing an application for memory leaks, I noticed one that
 > 	I could not get rid of.  I happened to be allocated from
 > 	/usr/src/lib/libc/stdio/makebuf.c on line 72, but only when
 > 	printf() (or really any function) used stdout.  Adding an
 > 	fclose(stdout) to the end of my application fixed the memory
 > 	leak.
 > 
 > 	I realize this is not much of a leak, but I thought it would be
 > 	nice to have it either documented or fixed before others run
 > 	into this confusing leak.
 
 I don't think it's a bug that libc lazily allocates memory for the
 three standard file descriptors.  I think you should consider this
 a false positive from dmalloc.

From: Sean Farley <sean-freebsd@farley.org>
To: David Schultz <dschultz@uclink.Berkeley.EDU>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/47599: Memory leak on stdout
Date: Tue, 28 Jan 2003 14:28:42 -0600 (CST)

 On Tue, 28 Jan 2003, David Schultz wrote:
 
 > Thus spake Sean C. Farley <sean-freebsd@farley.org>:
 > > 	When testing an application for memory leaks, I noticed one that
 > > 	I could not get rid of.  I happened to be allocated from
 > > 	/usr/src/lib/libc/stdio/makebuf.c on line 72, but only when
 > > 	printf() (or really any function) used stdout.  Adding an
 > > 	fclose(stdout) to the end of my application fixed the memory
 > > 	leak.
 > >
 > > 	I realize this is not much of a leak, but I thought it would be
 > > 	nice to have it either documented or fixed before others run
 > > 	into this confusing leak.
 >
 > I don't think it's a bug that libc lazily allocates memory for the
 > three standard file descriptors.  I think you should consider this a
 > false positive from dmalloc.
 
 Do you mean lazily deallocates memory?  I think the allocation is
 perfectly fine.  I was just wondering if there is a point at which libc
 was supposed to free the memory before exit.  A hook similar to
 atexit()?
 
 Sean
 -----------------------
 sean-freebsd@farley.org
State-Changed-From-To: open->closed 
State-Changed-By: wollman 
State-Changed-When: Tue Jan 28 12:38:48 PST 2003 
State-Changed-Why:  
Since no conforming application can tell the difference, this is not a bug, 
but rather a false positive in your leak-checker.  All memory is automatically 
freed on process exit, and all file descriptors are closed. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=47599 

From: David Schultz <dschultz@uclink.Berkeley.EDU>
To: Sean Farley <sean-freebsd@farley.org>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/47599: Memory leak on stdout
Date: Tue, 28 Jan 2003 17:39:41 -0800

 Thus spake Sean Farley <sean-freebsd@farley.org>:
 > On Tue, 28 Jan 2003, David Schultz wrote:
 > 
 > > Thus spake Sean C. Farley <sean-freebsd@farley.org>:
 > > > 	When testing an application for memory leaks, I noticed one that
 > > > 	I could not get rid of.  I happened to be allocated from
 > > > 	/usr/src/lib/libc/stdio/makebuf.c on line 72, but only when
 > > > 	printf() (or really any function) used stdout.  Adding an
 > > > 	fclose(stdout) to the end of my application fixed the memory
 > > > 	leak.
 > > >
 > > > 	I realize this is not much of a leak, but I thought it would be
 > > > 	nice to have it either documented or fixed before others run
 > > > 	into this confusing leak.
 > >
 > > I don't think it's a bug that libc lazily allocates memory for the
 > > three standard file descriptors.  I think you should consider this a
 > > false positive from dmalloc.
 > 
 > Do you mean lazily deallocates memory?  I think the allocation is
 > perfectly fine.  I was just wondering if there is a point at which libc
 > was supposed to free the memory before exit.  A hook similar to
 > atexit()?
 
 No, it lazily allocates a buffer for each output stream the first
 time that stream is used.  It frees the buffer when the file is
 closed, which is usually never, in the case of the standard three
 file descriptors.
 
 In a practical sense, freeing that memory is pointless extra work
 because you need it until the program terminates anyway.  If you
 just want to appease dmalloc, you could probably hack something
 up, but it would be harder than you think.  You can't just special
 case the standard file descriptors and give them static buffers,
 because then setbuf(3) would cause a *real* memory leak.  Adding
 an atexit hook might work, but you have a chicken-and-egg problem.
 Your hook to free up to three measely 1K buffers would have to be
 last, because other atexit routines would expect stdio to work.
 But dmalloc uses an atexit hook to look for memory leaks, so you'd
 have to run your atexit handler before dmalloc's.  But dmalloc
 uses stdio...
>Unformatted:
