Search code examples
cfileio

Writing to a closed file in C


In C, how can I detect that I have written to a closed file?

Here is a trivial example I wrote:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, char** argv) {
    // Check for a filename, which will be used to open an output file.
    if (argc < 2) {
        fprintf(stderr, "Filename expected from command line.\n");
        exit(EXIT_FAILURE);
    }

    FILE* file = fopen(argv[1], "w");
    if (!file) {
        fprintf(stderr, "Error opening file: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    // Here, I purposely close the file and then try to write to it.
    fclose(file);
    int written = fprintf(file, "hello there, friend\n");

    // Now I check a few things to see if the write was successful.
    printf("ferror(file) = %i\n", ferror(file));
    printf("errno        = %i\n", errno);
    printf("written      = %i\n", written);

    return 0;
}

The output from running this program and providing an output file, which I have called output.txt, is this:

ferror(file) = 0
errno        = 0
written      = 20

The cplusplus.com reference page for fprintf says this about its return value:

On success, the total number of characters written is returned.

If a writing error occurs, the error indicator (ferror) is set and a negative number is returned.

I expected a negative number as a return value from fprintf, but instead I got 20; next I expected a non-zero error indicator for the file, but it is 0. This makes it seem as though the string was successfully written to output.txt, but the file is empty.

In a scenario like this, is it possible to detect whether I have tried writing data to a closed file?

Edit:

I am writing this code on a virtual machine running Ubuntu 18.04 and I am using gcc 7.4.0.


Solution

  • errno is not useful in the currently-posted code.

    First, the value of errno is valid only immediately after a call that fails - if the call is documented to set errno. fprintf() is not:

    7.21.6.1 The fprintf function

    Synopsis

    1

          #include <stdio.h>
          int fprintf(FILE * restrict stream,
               const char * restrict format, ...);
    

    ...

    Returns

    14 The fprintf function returns the number of characters transmitted, or a negative value if an output or encoding error occurred.

    There's no mention of errno being set by fprintf(). Per 7.5 Errors , paragraph 3 of the C 11 standard:

    The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

    Since fprintf() is not documented to set errno, it's value is not useful after a call to that function fails.

    Note that this code should indicate an error by returning a negative value, and not 20, as your posted output indicates it's doing:

    // Here, I purposely close the file and then try to write to it.
    fclose(file);
    int written = fprintf(file, "hello there, friend\n");
    

    I am completely unable to duplicate that problem, so this is only a partial answer to address the use of errno.