Why leaking file descriptors is a problem
Whenever you open a file with fopen
, you get a FILE *
which is your handle
to the file you just opened. Some people tell you to always run fclose
on the
file handle such that the file is closed.
Leaving the file unclosed will not cause problems in most cases. I guess most
people have forgot the fclose
or did not bother to write it at some point.
Their programs did not crash. To test when they crash, I wrote this little
testing program. All it does it to open a lot of files in a loop and not close
them.
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { char filename[100]; for (size_t i = 0; i < 1500; ++i) { sprintf(filename, "/tmp/%010ld.txt", i); FILE *fp = fopen(filename, "w"); if (fp == NULL) { printf("i = %6ld: failed!\n", i); return 1; } if (i % 100 == 0) { printf("i = %6ld: ok.\n", i); } } return 0; }
You can download this file: leak.c
Then compile it. You could also have used gcc
if you like, this is ISO
standard C. When I run it, I get the following output:
$ clang --std=c11 leak.c -o leak $ ./leak i = 0: ok. i = 100: ok. i = 200: ok. i = 300: ok. i = 400: ok. i = 500: ok. i = 600: ok. i = 700: ok. i = 800: ok. i = 900: ok. i = 1000: ok. i = 1021: failed!
Ouch! The last file created in the directory is 0000001020.txt
. It seems this
program can only open 1020 files at the same time. This is enough if you just
process a couple files. When you open files in a loop, it will break.
On my machine, ulimit -n
tells me that there are 1024 file descriptors for
each program. I assume that the program itself will need one descriptor for its
machine code, and perhaps there are three other ones used for shared libraries.
So please use fclose
to close your files in your programs. If you do not do
that and somebody works with a lot of files, it will either crash (when you
have checked fp == NULL
) or it will just not create a file! Alternatively,
you can use C++ where the std::ofstream
class has a destructor that will
automatically close the file at the end of the loop.