“It Can’t Be a Bug, My Makefile Depends on It!” 191
features would amount to nothing more than wasted silicon since the
majority of programs, written in C, wouldn’t use them.
Recall that C has no way to handle integer overflow. The solution when
using C is simply to use integers that are larger than the problem you have
to deal with—and hope that the problem doesn’t get larger during the life-
time of your program.
C doesn’t really have arrays either. It has something that looks like an array
but is really a pointer to a memory location. There is an array indexing
expression, array[index], that is merely shorthand for the expression
((array + index)). Therefore it’s equally valid to write index[array], which
is also shorthand for ((array+index)). Clever, huh? This duality can be
commonly seen in the way C programs handle character arrays. Array vari-
ables are used interchangeably as pointers and as arrays.
To belabor the point, if you have:
char *str = "bugy”;
...then the following equivalencies are also true:
0[str] == 'b'
*(str+1) == 'u'
*(2+str) == 'g'
str[3] == 'y'
Isn’t C grand?
The problem with this approach is that C doesn’t do any automatic bounds
checking on the array references. Why should it? The arrays are really just
pointers, and you can have pointers to anywhere in memory, right? Well,
you might want to ensure that a piece of code doesn’t scribble all over arbi-
trary pieces of memory, especially if the piece of memory in question is
important, like the program’s stack.
This brings us to the first source of bugs mentioned in the Miller paper.
Many of the programs that crashed did so while reading input into a char-
acter buffer that was allocated on the call stack. Many C programs do this;
the following C function reads a line of input into a stack-allocated array
and then calls do_it on the line of input.