fclose return value check

From comp.lang.c:

The fclose() call can fail, and should be error-checked just as assiduously as all the other file operations. Sounds pedantic, right? Wrong. In a former life, my company's product managed to destroy a customer's data by omitting a check for failure when closing a file. The sequence went something like (paraphrased):

stream = fopen(tempfile, "w"); 
if (stream == NULL) ... 
    while (more_to_write) 
        if (fwrite(buffer, 1, buflen, stream) != buflen) ... 
fclose (stream); 

/* The new version has been written successfully.  Delete 
 * the old one and rename. 
 */ 
remove (realfile); 
rename (tempfile, realfile); 

Of course, what happened was that fclose() ran out of disk space trying to write the last couple blocks of data, so the `tempfile' was truncated and unusable. And since the fclose() failure wasn't detected, the program went right ahead and destroyed the best extant version of the data in favor of the damaged version. And, as Murphy would have it, the victim in this particular incident was the person in charge of the customer's department, the person with authority to buy more of our product or replace it with a competitor's product -- and, natch, a person who was already unhappy with us for other reasons.

It'd be a stretch to ascribe all of the ensuing misery to this single omission, but it may be worth pointing out that both the customer and my former company have since vanished from the corporate ecology.

CHECK THOSE FAILURE CODES!


When you fwrite to a file, it may not actually write anything, it may stay in a buffer (inside the FILE object). Calling fflush would actually write it to disk. That operation may fail, for example if you just ran out of disk space, or there is some other I/O error.

fclose flushes the buffers implicitly too, so it may fail for the same reasons.


You could (and should) report the error, but in a sense, the stream is still closed:

After the call to fclose(), any use of stream results in undefined behavior.


  1. fclose() will flush any unwritten output (via fflush()) before returning, so the error results from the underlying write() won't be reported at fwrite() or fprintf() time, but when you do the fclose(). As a result, any error that write() or fflush() can generate can be generated by fclose().

  2. fclose() will also call close() which can generate errors on NFS clients, where the changed file isn't actually uploaded to the remote server until close() time. If the NFS server crashed, then the close() will fail, and thus fclose() will fail as well. This might be true of other networked filesystems.

Tags:

C

File Io