tags:

views:

207

answers:

5

I ran across the following code in one of our in-house dlls and I am trying to understand the behavior it was showing:

long GetFD(long* fd, const char* fileName, const char* mode)
{
    string fileMode;

    if (strlen(mode) == 0 || tolower(mode[0]) == 'w' || tolower(mode[0]) == 'o')
        fileMode = string("w");
    else if (tolower(mode[0]) == 'a')
        fileMode = string("a");
    else if (tolower(mode[0]) == 'r')
        fileMode = string("r");
    else
        return -1;

    FILE* ofp;
    ofp = fopen(fileName, fileMode.c_str());
    if (! ofp)
        return -1;

    *fd = (long)_fileno(ofp);
    if (*fd < 0)
        return -1;

    return 0;
}

long CloseFD(long fd)
{
    close((int)fd);
    return 0;
}

After repeated calling of GetFD with the appropriate CloseFD, the whole dll would no longer be able to do any file IO. I wrote a tester program and found that I could GetFD 509 times, but the 510th time would error.

Using Process Explorer, the number of Handles did not increase.

So it seems that the dll is reaching the limit for the number of open files; setting _setmaxstdio(2048) does increase the amount of times we can call GetFD. Obviously, the close() is working quite right.

After a bit of searching, I replaced the fopen() call with:

long GetFD(long* fd, const char* fileName, const char* mode)
{
    *fd = (long)open(fileName, 2);
    if (*fd < 0)
      return -1; 

    return 0;
}

Now, repeatedly calling GetFD/CloseFD works.

What is going on here?

+17  A: 

If you open a file with fopen, you have to close it with fclose, symmetrically.

The C++ runtime must be given a chance to clean up/deallocate its inner file-related structures.

Vlad
Specifically, you're leaving a bunch of FILE* structures hanging around, and some OSes have a fixed size table for that, usually 512, which includes the stdin, stdout and stderr FILE*s.
Paul Tomblin
... and this explains the limit of 509: it's just 512 - stdin - stdout - stderr.
Vlad
`stdio` runtime, not just C++ (that is, common to both C and C++).
mpez0
+8  A: 

You need to use fclose with files opened via fopen, or close with files opened via open.

Paul R
+5  A: 

The standard library you are using has a static array of FILE structures. Because you are not calling fclose(), the standard library doesn't know that the underlying files have been closed, so it doesn't know it can reuse the corresponding FILE structures. You get an error after it has run out of entries in the FILE array.

Dave Hinton
+3  A: 

fopen opens it's own file descriptor, so you'd need to do an fclose(ofp) in your original function to prevent running out of file descriptors. Usually, one either uses the lower level file descriptor functions open, close OR the buffered fopen, fclose functions.

jeff7
+1  A: 

you are open the file fopen() function so u have to close the file useing fclose(), if you are using open() function and try to call fclose() function it will not work

sam