
The C standard makes no guarantees as to when output to stdout
(standard output) or stderr
(standard error) is actually flushed. On many platforms, output to stdout
is buffered unless stdout
outputs to a terminal, and stderr
output is typically not buffered. However, programs are free to modify the buffering rules for either stdout
or stderr
. Programs are also free to explicitly close stdout
or stderr
; if they do not do so, these streams will be closed upon program termination.
Closing any output stream requires flushing any data that has not yet been written to the stream. The flushing operation (manually handled by the fflush()
function) can fail for several reasons. The output stream may be directed to a file in a filesystem with no remaining free space, or to a network socket that fails. Checking for the success of a fflush()
operation is mandatory for a secure program, and hence checking the result of a fclose()
operation is also required.
Consequently, any program that sends data to stdout
or stderr
must take care to flush the data before it terminates. Failing to flush the data (with a call to fflush()
or fclose()
), may cause the data to fail to be written and become lost.
Noncompliant Code Example
This noncompliant code example sends some data to standard output. If standard output is directed to a file and an error occurs while flushing the data (after program termination), then the output may be lost.
#include <stdio.h> int main(void) { printf("Hello, world!\n"); return 0; }
Compliant Solution
This compliant solution explicitly closes stdout
, and handles any errors that arise.
#include <stdio.h> int main(void) { printf("Hello, world!\n"); if (fclose(stdout) == EOF) { /* Handle error */ } return 0; }
Noncompliant Code Example (atexit()
)
This noncompliant code example closes standard output before exiting main()
, but then tries to print to standard output in an exit handler.
#include <stdio.h> void cleanup(void) { /* Do cleanup */ printf("All cleaned up!\n"); } int main(void) { atexit(cleanup); printf("Doing important stuff\n"); /* Do important stuff */ if (fclose(stdout) == EOF) { /* Handle error */ } return 0; }
Compliant Solution (atexit()
)
This compliant solution uses fflush()
instead of fclose()
, and the exit handler also uses fflush()
to flush its output:
#include <stdio.h> void cleanup(void) { /* Do cleanup */ printf("All cleaned up!\n"); if (fflush(stdout) == EOF) { /* Handle error */ } } int main(void) { atexit(cleanup); printf("Doing important stuff\n"); /* Do important stuff */ if (fflush(stdout) == EOF) { /* Handle error */ } return 0; }
Exceptions
FIO23-C-EX1: Programs that do not send data to either output stream need not close them.
FIO23-C-EX2: Programs that never run with buffered output streams need not close them.
Risk Assessment
Failing to flush data buffered for standard output or standard error may result in lost data.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO23-C | Medium | Unlikely | Medium | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.