Opening a file that is already open has implementation-defined behavior, according to the C Standard, subclause 7.21.3, paragraph 8 [ISO/IEC 9899:2011]:
Functions that open additional (nontemporary) files require a file name, which is a string. The rules for composing valid file names are implementation-defined. Whether the same file can be simultaneously open multiple times is also implementation-defined.
Some platforms may forbid a file simultaneously being opened multiple times, but other platforms may allow it. Therefore, portable code cannot depend on what will happen if this rule is violated.
Opening an already-opened file twice may in fact open a different file. For more information, see FIO45-C. Do not perform multiple file operations on the same filename.
Noncompliant Code Example
This noncompliant code example logs the program's state at runtime:
#include <stdio.h> void do_stuff(void) { FILE *logfile = fopen("log", "a"); if (logfile == NULL) { /* Handle error */ } /* Write logs pertaining to do_stuff() */ fprintf(logfile, "do_stuff\n"); } int main(void) { FILE *logfile = fopen("log", "a"); if (logfile == NULL) { /* Handle error */ } /* Write logs pertaining to main() */ fprintf(logfile, "main\n"); do_stuff(); if (fclose(logfile) == EOF) { /* Handle error */ } return 0; }
Because the file log
is opened twice simultaneously this program has implementation-defined behavior. On a Linux machine running GCC 4.3.2, for example, this program produces
do_stuff main
which does not indicate the order in which data was logged.
Compliant Solution
In this compliant solution, a reference to the file pointer is passed as an argument to functions that need to perform operations on that file. This reference eliminates the need to open the same file multiple times.
#include <stdio.h> void do_stuff(FILE *logfile) { /* Write logs pertaining to do_stuff() */ fprintf(logfile, "do_stuff\n"); } int main(void) { FILE *logfile = fopen("log", "a"); if (logfile == NULL) { /* Handle error */ } /* Write logs pertaining to main() */ fprintf(logfile, "main\n"); do_stuff(logfile); if (fclose(logfile) == EOF) { /* Handle error */ } return 0; }
This program portably produces the following output:
main do_stuff
which matches the order in which logging occurred. This output assumes that the log file was not moved or deleted between the two calls to fopen()
.
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
9.7.1 | 75 D | Fully implemented |
Risk Assessment
Simultaneously opening a file multiple times can result in unexpected errors and nonportable behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO31-C | Medium | Probable | High | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | FIO31-CPP. Do not simultaneously open the same file multiple times |
MITRE CWE | CWE-362, Race conditions CWE-675, Duplicate operations on resource |
Bibliography
[ISO/IEC 9899:2011] | Subclause 7.21.3, "Files" |