...
Note that std::basic_ifstream<T>
, std::basic_ofstream<T>
, and std::basic_fstream<T>
all maintain an internal reference to a std::basic_filebuf<T>
object on which open()
and close()
are called as - needed. Properly managing an object of one of these types (by not leaking the object) is sufficient to ensure compliance with this rule. OftentimesOften, the best solution is to use the stream object by value semantics instead of via dynamic memory allocation, ensuring compliance with MEM31MEM51-CPP. Properly deallocate dynamically allocated resources. However, that is still insufficient for situations where in which destructors are not automatically called.
Page properties | ||
---|---|---|
| ||
We may want an overarching rule that covers any situation where destructors are not automatically called, since there can be all sorts of nasty things that happen in those situations. |
Noncompliant Code Example
In this noncompliant code example, a std::fstream
object f
file
is constructed. The constructor for std::fstream
calls std::basic_filebuf<T>::open()
, and the default std::terminate_handler
called by std::terminate()
is std::abort()
, which does not call destructors. ThusConsequently, the underlying std::basic_filebuf<T>
object maintained by the object is not properly closed, and the program has no way of determining if an error occurs while flushing or closing the file.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <exception> #include <fstream> #include <string> void f(const std::string &NfileName) { std::fstream ffile(NfileName); if (!ffile.is_open()) { // Handle error return; } // ... std::terminate(); } |
This noncompliant code example and the subsequent compliant solutions are assumed to eventually call std::terminate()
in accordance with the ERR50-CPP-EX1 exception described in ERR50-CPP. Do not abruptly terminate the program. Indicating the nature of the problem to the operator is elided for brevity.
Compliant Solution
In this compliant solution, std::fstream::close()
is called prior to calling before std::terminate()
is called, ensuring that the file resources are properly closed.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <exception> #include <fstream> #include <string> void f(const std::string &NfileName) { std::fstream ffile(NfileName); if (!ffile.is_open()) { // Handle error return; } // ... ffile.close(); if (ffile.fail()) { // Handle error } std::terminate(); } |
Compliant Solution
In this compliant solution, the stream is implicitly closed through RAII before std::terminate()
is called, ensuring that the file resources are properly closed.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <exception>
#include <fstream>
#include <string>
void f(const std::string &fileName) {
{
std::fstream file(fileName);
if (!file.is_open()) {
// Handle error
return;
}
} // file is closed properly here when it is destroyed
std::terminate();
} |
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 |
---|
FIO51-CPP | Medium | Unlikely | Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|
CodeSonar |
| ALLOC.LEAK | Leak | ||||||
Helix QAC |
| DF4786, DF4787, DF4788 | |||||||
Klocwork |
| RH.LEAK | |||||||
Parasoft C/C++test |
| CERT_CPP-FIO51-a | Ensure resources are freed | ||||||
Parasoft Insure++ | Runtime detection | ||||||||
Polyspace Bug Finder |
| CERT C++: FIO51-CPP | Checks for resource leak (rule partially covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
...
This rule supplements FIO42-C. Close files when they are no longer needed.
Bibliography
[ISO/IEC 14882-2014] | Subclause 27.9.1, "File Streams" |
...