A function call to ``++fopen++`` or ``++open++`` must be matched with a call to ``++fclose++`` or ``++close++``, respectively.

== Why is this an issue?

The standard C library provides ``++fopen++`` and the system call ``++open++`` to open and possibly create files.
Each call to one of these functions must be matched with a respective call to ``++fclose++`` or ``++close++``.

Failing to close files that have been opened may lead to using up all of the OS's file handles.


== What is the potential impact?

If a program does not properly close or release file handles after using them, it will leak resources.
In that case, the program will continue to hold onto file handles even when they are no longer needed, eventually exhausting the available file handles.

If a program has run out of file handles and tries to open yet another file, the file opening operation will fail.
This can result in errors or unexpected behavior in the program.

The program may not be able to read or write to files anymore, which can cause data loss, corruption, or incomplete operations.
In some cases, when a program runs out of file handles, it may crash or hang indefinitely.
This can happen if the program does not handle the error condition properly or if it enters an infinite loop trying to open files, for instance.
In the worst case, a resource leak can lock up everything that runs on the machine.


== How to fix it

Make sure that each call to ``++fopen++`` and ``++open++`` has a matching call to ``++fclose++`` and ``++close++``, respectively.

=== Code examples

==== Noncompliant code example

[source,cpp,diff-id=1,diff-type=noncompliant]
----
#include <stdio.h>
#include <stdlib.h>

int process_file(int print) {
  FILE *f = fopen("example.txt", "r");
  if (!f) {
    perror("fopen() failed");
    return 1;
  }

  if (print) {
    char buffer[256];
    while (fgets(buffer, 256, f)) {
      printf("%s", buffer);
    }
  }

  return 0; // Noncompliant: file `f` has not been closed
}
----

==== Compliant solution

[source,cpp,diff-id=1,diff-type=compliant]
----
#include <stdio.h>
#include <stdlib.h>

int process_file(int print) {
  FILE *f = fopen("example.txt", "r");
  if (!f) {
    perror("fopen() failed");
    return 1;
  }

  if (print) {
    char buffer[256];
    while (fgets(buffer, 256, f)) {
      printf("%s", buffer);
    }
  }

  fclose(f);
  return 0; // Compliant: file `f` has been closed
}
----

=== Going the extra mile

Using {cpp}'s _RAII_ idiom can mitigate unmatched calls to ``++fopen++`` and ``++open++``.

include::../../../shared_content/cfamily/c_file_io_raii_extra_mile.adoc[]

With the design shown above, calls to ``++fopen++`` will be automatically matched with a corresponding call to ``++fclose++`` by default.
The associated file will be automatically closed when the ``++File++`` typed file handle object goes out of scope and its destructor is called.
However, it is still possible to leak a resource, if ``++File++``'s function member ``++File::release++`` is used inappropriately.
If this is a concern, this function member should be removed.

If falling back to low-level file operations is not necessary, one should prefer ``++std::fstream++``.


== Resources

=== Standards

* CERT - https://wiki.sei.cmu.edu/confluence/x/QtUxBQ[FIO42-C. Close files when they are no longer needed]
* CWE - https://cwe.mitre.org/data/definitions/459[CWE-459 Incomplete Cleanup]
* CWE - https://cwe.mitre.org/data/definitions/772[CWE-772 Missing Release of Resource after Effective Lifetime]

=== Related rules

* S3588 ensures that ``++FILE*++`` typed variables are not accessed after the associated file has been closed



ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

=== Message

Review the data-flow; this file might not have been closed when reaching exit point at line ``++line++``.


=== Highlighting

* Primary: the open call, ex: fopen
* Additional: statement exiting the function
** Message: Exit point


'''
== Comments And Links
(visible only on this page)

=== on 30 Mar 2016, 16:46:31 Ann Campbell wrote:
\[~massimo.paladin] I've expanded the description slightly with a 'why'.


Speaking of which, why downgrade this from Blocker to Critical?

=== on 31 Mar 2016, 13:11:53 Ann Campbell wrote:
\[~massimo.paladin] I've moved the Cert C reference back to the main task. All references go on every language-variation of a rule.

=== on 31 Mar 2016, 13:15:08 Massimo PALADIN wrote:
\[~ann.campbell.2] what about ``++Exceptions++`` section which is present on the main task but is not applicable to the language variation?

=== on 31 Mar 2016, 13:29:56 Ann Campbell wrote:
\[~massimo.paladin] I've moved that into a language-specific subtask

include::../comments-and-links.adoc[]

endif::env-github,rspecator-view[]
