File is not open
| Vulnerability potential | Low |
| DDoS potential | Low |
It is possible that the file is not open
Impact
A file operation (fread, fwrite, fprintf, fseek, fclose) is performed on
a handle that may not be open. The usual cause is using the result of fopen
without checking it: when the open fails — missing file, wrong permissions, out of
descriptors — fopen returns NULL, and the subsequent call dereferences that
null FILE*, crashing the process. With raw descriptors the analogue is using an
fd of -1 returned by a failed open, which makes every later read/write
fail with EBADF.
Either way the program proceeds on the false assumption that I/O succeeded:
expected data is never read or written, and in the null-FILE* case the program
terminates abruptly at the first use.
Vulnerability potential
The exposure is limited.
- Denial of service. Passing a
NULLFILE*tostdiodereferences it and crashes the process. If an attacker can force the open to fail (deleting the file, exhausting descriptors, or pointing the path at something they control), they can turn that into a reliable crash. - Silent data loss / wrong control flow. Ignoring the failed-open state means “successful” writes that never land, or reads that leave a buffer uninitialized; downstream logic then acts on stale or garbage data, which can mildly weaken security decisions.
There is no memory corruption beyond the null dereference, so both ratings are
Low.
Technical details
fopen / FILE*
fopen returns NULL on failure and sets errno. The FILE* is opaque; passing
NULL to any stdio function is undefined behaviour and in practice
dereferences a null pointer inside libc, faulting immediately.
POSIX descriptors
open returns -1 on failure. Unlike a null FILE*, calling read/write on
-1 does not crash — it returns -1 with errno == EBADF. Code that ignores
those return values then loses the data silently, which is harder to notice than a
crash.
Partially constructed state
The handle can also be “not open” because the open path was skipped by an earlier
return/break, or because a struct holding the handle was zero-initialized and
never populated. The analyzer flags I/O on any path where the handle’s open state
is not established.
Catching the issue
Always check the open result
Test fopen against NULL and open against -1 immediately, report errno
(strerror/perror), and do not proceed to I/O on failure. This single check
prevents the entire defect.
Sanitizers and runtime
A null FILE* dereference is caught by a normal crash and by AddressSanitizer.
UBSan flags the null pointer use. Checking ferror/return values after I/O
surfaces the descriptor-based variant.
Static analysis
Cppcheck, clang-tidy and the analyzer emitting this diagnostic perform null/value
tracking from fopen/open to the first use and report any I/O on a
possibly-unopened handle. Annotate APIs with nullability attributes to strengthen
this.
How to reproduce
Run this so the open fails (the path is not writable). fopen returns NULL and
the unchecked fputs dereferences it, crashing the program.
#include <stdio.h>
int main(void)
{
/* Opening a file in a non-existent directory fails and returns NULL. */
FILE *f = fopen("/no/such/dir/out.txt", "w");
/* No check: f may be NULL, and fputs then dereferences a null FILE*. */
fputs("data\n", f);
fclose(f);
return 0;
}