safe to fclose stdout to avoid memory leak?

P

Pietro Cerutti

Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
cat test.c
#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
return (0);
}
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test
[snip bla bla]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

Now, if I modify the test program as follows:
cat test.c
#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
fclose(stdout);
return (0);
}

and I recompile it:
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test
==1846== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==1846== malloc/free: in use at exit: 0 bytes in 0 blocks.
==1846== malloc/free: 1 allocs, 1 frees, 4096 bytes allocated.

My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?
- is it safe to fclose stdout before returning to the OS?

Thanks!
 
D

David Resnick

Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
cat test.c

#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
return (0);

}
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test

[snip bla bla]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

Now, if I modify the test program as follows:
cat test.c

#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
fclose(stdout);
return (0);

}

and I recompile it:
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test

==1846== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==1846== malloc/free: in use at exit: 0 bytes in 0 blocks.
==1846== malloc/free: 1 allocs, 1 frees, 4096 bytes allocated.

My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?
- is it safe to fclose stdout before returning to the OS?

Thanks!

It is fine to close stdout. As to the valgrind's complaint, consider
this code.

#include <stdlib.h>
static char *foo;
int main(void)
{
foo=malloc(4);
return 0;
}

The memory returned by malloc and pointed to by foo is still
"reachable". It is not "leaked", there is a good pointer to it. If
you inserted foo=NULL; after the malloc line, then it would be
leaked. Apparently, the library is creating a buffer associated with
stdout when stdout is first used and is keeping a pointer to that
buffer until stdout is explicitly closed. Sounds harmless enough.
Memory that is still "reachable" is not leaked per se, though it can
still be a problem if, for example, you have a data structure like a
hash table growing without bounds...

-David
 
E

Eric Sosman

Pietro Cerutti wrote On 08/20/07 11:35,:
Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).

cat test.c

#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
return (0);
}

gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test

[snip bla bla]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

Now, if I modify the test program as follows:

cat test.c

#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
fclose(stdout);
return (0);
}

and I recompile it:

gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test

==1846== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==1846== malloc/free: in use at exit: 0 bytes in 0 blocks.
==1846== malloc/free: 1 allocs, 1 frees, 4096 bytes allocated.

My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?

It is unlikely to be a bug.
- is it safe to fclose stdout before returning to the OS?

It is safe, but note that the program might not end
when main() returns or when exit() is called. If any
functions have been registered with atexit(), they will
run after this point -- and if they try to use stdout ...
 
P

Pietro Cerutti

Pietro said:
Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
cat test.c
#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
return (0);
}
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test
[snip bla bla]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

Now, if I modify the test program as follows:
cat test.c
#include <stdio.h>
int main(void) {
printf("%s\n", "Hello");
fclose(stdout);
return (0);
}

and I recompile it:
gcc -o test test.c
valgrind --leak-check=yes --show-reachable=yes -v ./test
==1846== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==1846== malloc/free: in use at exit: 0 bytes in 0 blocks.
==1846== malloc/free: 1 allocs, 1 frees, 4096 bytes allocated.

My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?
- is it safe to fclose stdout before returning to the OS?

Thanks!

Thank you David and Eric for your points!
 
C

Chris Torek

Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
[snippage, some output from valgrind remaining:]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

These function names suggest that your libc uses the stdio code I
wrote for 4.xBSD (or something closely related / descended; I think
my printf engine was originally named __svfprintf, for instance).

Originally, I had -- or was going to have -- the code called at
program exit iterate over all the open FILE data structures and
"fclose" them. This would release the memory allocated by
__smakebuf(), and also use the system's "close file" call on the
associated file descriptor (normally fd 1). Someone pointed out,
though, that it is "more efficient" on the BSD systems to just
fflush() these files, to force pending output to appear, and then
use the system's "exit" call to release all memory (including
malloc()ed memory, without going through free() at all) and close
all files (without using the system's "close file" call).

If you or I were writing Standard C, this is not such a great idea.
But I was not writing Standard C; I was implementing the C library
in a system-specific manner. Because I was writing system-specific
code, I could depend on behavior not prescribed by the C Standard,
such as "memory gets freed automatically when the program terminates"
and "files get closed automatically when the program terminates".
In other words, as the implementor, I am *allowed* to cheat. :)

(Note also that the function names I used are all in the implementor's
namespace. I used names beginning with double underscores, which
you -- as a "user" programmer -- must avoid. I, as an "implementor"
programmer, must avoid any names that you can use. The double
underscore prefix safely hides me from you, and you from me, except
at the interfaces required by Standard C: fopen, fclose, and so
on, in this case.)
My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?

It is not really "normal" but it is not a "bug" either. Instead,
it is a deliberate violation done in the name of efficiency,
"knowing" various things (which I hope are still true today :) )
about the system. (Anyone modifying the underlying system in a
way that breaks these assumptions must also modify the C implementation.)
- is it safe to fclose stdout before returning to the OS?

It should be safe, but unnecessary.
 
R

Richard Tobin

Chris Torek said:
But I was not writing Standard C; I was implementing the C library
in a system-specific manner. Because I was writing system-specific
code, I could depend on behavior not prescribed by the C Standard,
such as "memory gets freed automatically when the program terminates"
and "files get closed automatically when the program terminates".
In other words, as the implementor, I am *allowed* to cheat. :)

If one were writing the code today (rather than in the 1980s) I think
the advantage of having memory checkers show no leaks at exit would
outweigh the (now insignificant) efficiency gain.

-- Richard
 
P

Pietro Cerutti

Chris said:
Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
[snippage, some output from valgrind remaining:]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

These function names suggest that your libc uses the stdio code I
wrote for 4.xBSD (or something closely related / descended; I think
my printf engine was originally named __svfprintf, for instance).

Originally, I had -- or was going to have -- the code called at
program exit iterate over all the open FILE data structures and
"fclose" them. This would release the memory allocated by
__smakebuf(), and also use the system's "close file" call on the
associated file descriptor (normally fd 1). Someone pointed out,
though, that it is "more efficient" on the BSD systems to just
fflush() these files, to force pending output to appear, and then
use the system's "exit" call to release all memory (including
malloc()ed memory, without going through free() at all) and close
all files (without using the system's "close file" call).

If you or I were writing Standard C, this is not such a great idea.
But I was not writing Standard C; I was implementing the C library
in a system-specific manner. Because I was writing system-specific
code, I could depend on behavior not prescribed by the C Standard,
such as "memory gets freed automatically when the program terminates"
and "files get closed automatically when the program terminates".
In other words, as the implementor, I am *allowed* to cheat. :)

(Note also that the function names I used are all in the implementor's
namespace. I used names beginning with double underscores, which
you -- as a "user" programmer -- must avoid. I, as an "implementor"
programmer, must avoid any names that you can use. The double
underscore prefix safely hides me from you, and you from me, except
at the interfaces required by Standard C: fopen, fclose, and so
on, in this case.)
My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?

It is not really "normal" but it is not a "bug" either. Instead,
it is a deliberate violation done in the name of efficiency,
"knowing" various things (which I hope are still true today :) )
about the system. (Anyone modifying the underlying system in a
way that breaks these assumptions must also modify the C implementation.)
- is it safe to fclose stdout before returning to the OS?

It should be safe, but unnecessary.

Hi Christ,
thank you very much for your exhaustive explanation.
So, in short terms, what you're saying is that valgrind notices that
memory isn't deallocated at program exit (which is true) because it gets
eventually free'd by the OS, so I don't have to worry about memory
leaks, right?

Regards,
 
A

Antoninus Twink

Chris said:
Hi group,
I just noticed that a malloc w/out relative free occurs in the standard
C library (or at least, on my implementation of it).
[snippage, some output from valgrind remaining:]
4096 bytes in 1 blocks are still reachable in loss record 1 of 1
at 0x3C03B18F: malloc (in /usr/local/lib/valgrind/vgpreload_memcheck.so)
by 0x3C116FD2: __smakebuf (in /lib/libc.so.6)
by 0x3C116E77: __swsetup (in /lib/libc.so.6)
by 0x3C10BF7F: __vfprintf (in /lib/libc.so.6)

These function names suggest that your libc uses the stdio code I
wrote for 4.xBSD (or something closely related / descended; I think
my printf engine was originally named __svfprintf, for instance).

Originally, I had -- or was going to have -- the code called at
program exit iterate over all the open FILE data structures and
"fclose" them. This would release the memory allocated by
__smakebuf(), and also use the system's "close file" call on the
associated file descriptor (normally fd 1). Someone pointed out,
though, that it is "more efficient" on the BSD systems to just
fflush() these files, to force pending output to appear, and then
use the system's "exit" call to release all memory (including
malloc()ed memory, without going through free() at all) and close
all files (without using the system's "close file" call).

If you or I were writing Standard C, this is not such a great idea.
But I was not writing Standard C; I was implementing the C library
in a system-specific manner. Because I was writing system-specific
code, I could depend on behavior not prescribed by the C Standard,
such as "memory gets freed automatically when the program terminates"
and "files get closed automatically when the program terminates".
In other words, as the implementor, I am *allowed* to cheat. :)

(Note also that the function names I used are all in the implementor's
namespace. I used names beginning with double underscores, which
you -- as a "user" programmer -- must avoid. I, as an "implementor"
programmer, must avoid any names that you can use. The double
underscore prefix safely hides me from you, and you from me, except
at the interfaces required by Standard C: fopen, fclose, and so
on, in this case.)
My question are the following:
- is it normal or is it likely to be a bug in my implementation of the C
library?

It is not really "normal" but it is not a "bug" either. Instead,
it is a deliberate violation done in the name of efficiency,
"knowing" various things (which I hope are still true today :) )
about the system. (Anyone modifying the underlying system in a
way that breaks these assumptions must also modify the C implementation.)
- is it safe to fclose stdout before returning to the OS?

It should be safe, but unnecessary.

Hi Christ,
thank you very much for your exhaustive explanation.
So, in short terms, what you're saying is that valgrind notices that
memory isn't deallocated at program exit (which is true) because it gets
eventually free'd by the OS, so I don't have to worry about memory
leaks, right?

I believe that is false on some versions of MS-DOS.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top