The standard C library includes a number of functions for handling I/O streams. These functions put certain constraints on the values of their
parameters. The constraints include the following:
- The value for the
FILE*-typed parameter may not be NULL
- The third argument of
fseek must be either of SEEK_SET, SEEK_END, or SEEK_CUR
Failing to pass correctly constrained parameters renders them invalid and will result in undefined behavior.
#include <stdio.h>
size_t get_file_size() {
FILE *f = fopen("example_file.txt", "r");
// `f` may be NULL if `fopen` fails.
fseek(f, 0L, SEEK_END); // Leads to undefined behavior, if `f` is NULL.
size_t size = ftell(f); // Leads to undefined behavior, if `f` is NULL.
fclose(f);
return size;
}
What is the potential impact?
Using the standard C library’s functions for handling I/O streams with invalid arguments leads to undefined behavior.
When a program comprises undefined behavior, the compiler no longer needs to adhere to the language standard, and the program has no meaning
assigned to it.
Due to the resulting NULL pointer dereferences in the C library functions, the application might just crash, but in the worst case, the application
may appear to execute correctly, while losing data or producing incorrect results.
Besides affecting the application’s availability, NULL pointer dereferences may lead to code execution, in rare circumstances. If NULL is
equivalent to the 0x0 memory address that can be accessed by privileged code, writing and reading memory is possible, which compromises the integrity
and confidentiality of the application.