Section The C Standard, 7.1921.5.3 of C99 , paragraph 7 [ISO/IEC 9899:2011], places the following restrictions on update streams: [ISO/IEC 9899:1999]
When a file is opened with update mode both . . ., both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the
fflush
function or to a file positioning function (fseek
,fsetpos
, orrewind
), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file. Opening (or creating) a text file with update mode may instead open (or create) a binary stream in some implementations.
...
The following scenarios can result in undefined behavior (see undefined behavior 151):
- Receiving input from a stream directly following an output to that stream without an intervening call to
fflush()
,fseek()
,fsetpos()
, orrewind()
...
- if the file is not at end-of-file
- Outputting to a stream after receiving input from
...
- that stream without a call to
fseek()
,fsetpos()
, orrewind()
if the file is not at end-of-file
...
Consequently, a call to fseek()
, fflush()
, or fsetpos()
is necessary between input and output to the same stream
...
. See FIO07-CPP. Prefer fseek() to rewind() for more information on why fseek()
is preferred over rewind()
.
Noncompliant Code Example
...
This noncompliant code example appends data to a file and then reads from the same file.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> enum { BUFFERSIZE = 32 }; extern void initialize_data(char *data, size_t size); void func(const char *file_name) { char data[BUFFERSIZE]; char append_data[BUFFERSIZE]; char *file_name; FILE *file; /* Initialize file_name */ file = fopen(file_name, "a+"); if (file == NULL) { /* Handle error */ } /* initialize _data(append_data, */BUFFERSIZE); if (fwrite(append_data, BUFFERSIZE1, 1BUFFERSIZE, file) != BUFFERSIZE) { /* Handle error */ } if (fread(data, BUFFERSIZE1, 1BUFFERSIZE, file) !=< 0BUFFERSIZE) { /* Handle there not being data */ } if (fclose(file); ) == EOF) { /* Handle error */ } } |
Because there is no intervening flush or positioning call between the calls However, because the stream is not flushed in between the call to fread()
and fwrite()
, the behavior is undefined.
Compliant Solution
...
In this compliant solution, fseek()
is called in between the output and input, eliminating the undefined behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> enum { BUFFERSIZE = 32 }; extern void initialize_data(char *data, size_t size); void func(const char *file_name) { char data[BUFFERSIZE]; char append_data[BUFFERSIZE]; char *file_name; FILE *file; /* initialize file_name */ file = fopen(file_name, "a+"); if (file == NULL) { /* Handle error */ } /* Initialize initialize_data(append_data, */ BUFFERSIZE); if (fwrite(append_data, BUFFERSIZE, 1, file) != BUFFERSIZE) { /* Handle error */ } if (fseek(file, 0L, SEEK_SET) != 0) { /* Handle error */ } if (fread(data, BUFFERSIZE, 1, file) != 0) { /* Handle there not being data */ } if (fclose(file); == EOF) { /* Handle error */ } } |
Noncompliant Code Example (iofstream
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
{
char data[BUFFERSIZE];
char append_data[BUFFERSIZE];
char *file_name;
* Initialize file_name and append_data */
fstream file( file_name, fstream::in | fstream::out | fstream::app);
file << append_data << ends;
file >> data;
// ...
} /* File gets closed here */
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
{
char data[BUFFERSIZE];
char append_data[BUFFERSIZE];
char *file_name;
* Initialize file_name and append_data */
fstream file( file_name, fstream::in | fstream::out | fstream::app);
file << append_data << ends;
file.seekg(0, ios::beg);
file >> data;
// ...
} /* File gets closed here */
|
...
Alternately inputting and outputting from a stream without an intervening flush or positioning call results in is undefined behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO39-CPP | low Low | likely Likely | medium Medium | P6 | L2 |
Automated Detection
Tool |
---|
...
Version | Checker | Description | |
---|---|---|---|
Can detect simple violations of this rule | |||
5. |
...
0 | Can detect |
...
violations of this rule |
...
with CERT C Rule Pack | |||||||||
| 84 D | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
...
Related Guidelines
...
...
ISO/IEC TS 17961:2013 | Interleaving stream inputs and outputs without a flush or positioning call [ioileave] |
Bibliography
...
2011] |
...
7. |
...
21.5.3, "The fopen |
...
Function" |
...