CertC-FIO42¶
Close files when they are no longer needed
Required inputs: IR, StaticSemanticAnalysis
A call to the
fopen() or
freopen() function must be matched with a call to
fclose() before the lifetime of the last pointer that stores
the return value of the call has ended or before normal program termination,
whichever occurs first.
In general, this rule should also be applied to other functions with open and
close resources, such as the POSIX
open() and
close() functions, or the Microsoft Windows
CreateFile() and
CloseHandle() functions.
Noncompliant Code Example
This code example is noncompliant because the file opened by the call to
fopen() is not closed before function
func() returns:
#include <stdio.h>
int func(const char *filename) {
FILE *f = fopen(filename, "r");
if (NULL == f) {
return -1;
}
/* ... */
return 0;
}
Compliant Solution
In this compliant solution, the file pointed to by
f is closed before returning to the caller:
#include <stdio.h>
int func(const char *filename) {
FILE *f = fopen(filename, "r");
if (NULL == f) {
return -1;
}
/* ... */
if (fclose(f) == EOF) {
return -1;
}
return 0;
}
Noncompliant Code Example (
exit())
This code example is noncompliant because the resource allocated by the call to
fopen() is not closed before the program terminates.
Although
exit() closes the file, the program has no way of determining if
an error occurs while flushing or closing the file.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *f = fopen(filename, "w");
if (NULL == f) {
exit(EXIT_FAILURE);
}
/* ... */
exit(EXIT_SUCCESS);
}
Compliant Solution (
exit())
In this compliant solution, the program closes
f explicitly before calling
exit(), allowing any error that occurs when flushing or closing
the file to be handled appropriately:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *f = fopen(filename, "w");
if (NULL == f) {
/* Handle error */
}
/* ... */
if (fclose(f) == EOF) {
/* Handle error */
}
exit(EXIT_SUCCESS);
}
Noncompliant Code Example (POSIX)
This code example is noncompliant because the resource allocated by the call to
open() is not closed before function
func() returns:
#include <stdio.h>
#include <fcntl.h>
int func(const char *filename) {
int fd = open(filename, O_RDONLY, S_IRUSR);
if (-1 == fd) {
return -1;
}
/* ... */
return 0;
}
Compliant Solution (POSIX)
In this compliant solution,
fd is closed before returning to the caller:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int func(const char *filename) {
int fd = open(filename, O_RDONLY, S_IRUSR);
if (-1 == fd) {
return -1
}
/* ... */
if (-1 == close(fd)) {
return -1;
}
return 0;
}
Noncompliant Code Example (Windows)
In this noncompliant code example, the file opened by the Microsoft
Windows
CreateFile() function is not closed before
func() returns:
#include <Windows.h>
int func(LPCTSTR filename) {
HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return -1;
}
/* ... */
return 0;
}
Compliant Solution (Windows)
In this compliant solution,
hFile is closed by invoking the
CloseHandle() function before returning to the
caller:
#include <Windows.h>
int func(LPCTSTR filename) {
HANDLE hFile = CreateFile(filename, GENERIC_READ, 0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return -1;
}
/* ... */
if (!CloseHandle(hFile)) {
return -1;
}
return 0;
}
Risk Assessment
Failing to properly close files may allow an attacker to exhaust system resources and can increase the risk that data written into in-memory file buffers will not be flushed in the event of abnormal program termination.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| FIO42-C | Medium | Unlikely | Medium | P4 | L3 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C | FIO51-CPP. Close files when they are no longer needed | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CERT Oracle Secure Coding Standard for Java | FIO04-J. Release resources when they are no longer needed | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TS 17961:2013 | Failing to close files or free dynamic memory when they are no longer needed [fileclose] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CWE 2.11 | CWE-404, Improper Resource Shutdown or Release | 2017-07-06: CERT: Rule subset of CWE |
| CWE 2.11 | CWE-459 | 2017-07-06: CERT: Rule subset of CWE |
| CWE 2.11 | CWE-772 | 2017-07-06: CERT: Rule subset of CWE |
| CWE 2.11 | CWE-773 | 2017-07-06: CERT: Rule subset of CWE |
| CWE 2.11 | CWE-775 | 2017-07-06: CERT: Rule subset of CWE |
| CWE 2.11 | CWE-403 |
2017-10-30:MITRE:Unspecified Relationship 2018-10-18:CERT:Partial overlap |
Bibliography
| [ IEEE Std 1003.1:2013] | XSH, System Interfaces,
open
|
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
memory_leak |
Close files when they are no longer needed. |
None |
False |
possible_memory_leak |
Close files when they are no longer needed. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
resources¶
resources : set[str] = {'FileHandle'}
witness_paths¶
witness_paths : bool = True
witness_should_include_exception_handling¶
witness_should_include_exception_handling : bool = False