...
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. Consequently, the underlying std::basic_filebuf<T> object maintained by the object is not properly closed, and the program has no way of determining whether 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 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 | Detectable |
|---|
Repairable | Priority | Level | |
|---|---|---|---|
FIO51-CPP | Medium | Unlikely | No |
No |
P2 | 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) | ||||||
| Security Reviewer - Static Reviewer | 6.02 | C80 | Fully implemented |
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.
| SEI CERT C++ Coding Standard | MEM51-CPP. Properly deallocate dynamically allocated resources |
Bibliography
| [ISO/IEC 14882-2014] | Subclause 27.9.1, "File Streams" |
...
...