...
This non-compliant code example copies a file. It allocates a buffer of user-defined size on the stack to temporarily store data read from the source file. If the size of the buffer is not constrained, a malicious user could specify a buffer of several gigabytes and cause a crash. A more malicious user could specify a buffer long enough to place the stack pointer into the heap and overwrite memory there with what fputs()
and fgets()
store on the stack.
Code Block | ||
---|---|---|
| ||
int copy_file(FILE *src, FILE *dst, size_t bufsize) { char buf[bufsize]; while (fgets(buf, bufsize, src)) fputs(buf, dst); return 0; } |
...
This solution replaces the dynamic array with a call to malloc()
, and performs appropriate error checking on the malloc()
return value.
Code Block | ||
---|---|---|
| ||
int copy_file(FILE *src, FILE *dst, size_t bufsize) { char *buf = malloc(bufsize); if (!buf) { return -1; } while (fgets(buf, bufsize, src)) { fputs(buf, dst); } return 0; } |
...
Non-Compliant Code Example
Excessive recursion also requires the operating system to grow the stack, and can thus consequently lead to the process being killed due to lack of memory. Depending on the algorithm, this can be much more difficult to fix than the use of dynamic arrays. However, the use of recursion in most C programs is limited in part because non-recursive solutions are often faster.
...
This is a naive implementation of the Fibonacci function using exponential recursion (as well as exponential time). When tested on a Linux system, fib1(100)
crashes with a segmentation fault.
Code Block | ||
---|---|---|
| ||
unsigned long fib1(unsigned int n) { if (n == 0) { return 0; } else if (n == 1 || n == 2) { return 1; } else { return fib1(n-1) + fib1(n-2); } } |
Compliant Solution
This is a much more efficient solution, using constant space and linear time. Tested on a Linux system, fib2(100)
is calculated almost instantly and with almost no chance of crashing due to a failed stack allocation.
Code Block | ||
---|---|---|
| ||
unsigned long fib2(unsigned int n) { if (n == 0) { return 0; } else if (n == 1 || n == 2) { return 1; } unsigned long prev = 1; unsigned long cur = 1; unsigned int i; for (i = 3; i <= n; i++) { unsigned long tmp = cur; cur = cur + prev; prev = tmp; } return cur; } |
...