Defensive or Assertive?

        Submitter: Oleg Goldshmidt

        Language: C++

        Date:        2003/07/16

Here is a piece of code I just saw (as always, drastically simplified):

#include <assert.h>

void unwind(Stack *stack, const unsigned int numframes)
assert(numframes > 0 && stack->depth() >= numframes);
long val;
for (unsigned int i = 0; i < numframes; i++)
val = stack->pop();

The author apparently thought he (or maybe she?) was defensive enough because the assertion verifies the input. However, this relies on every code path leading to the function to be thoroughly tested in the debugging mode, and this does not happen always. Or often. 

The result is that there may be cases where val will contain garbage, and what do_something_with(val) will actually do with the garbage is anyone's guess. For all I know, for some values of val it may launch ICBMs.

Assertions should be reserved to checking for conditions that should never ever happen. Input validation is not one of such conditions, and it should be done properly independently of the compilation flags. The code above will not do any input validation in production.

Incidentally, if you only compile with debugging flags during development, the compiler may never tell you there is something wrong here. Only when you disable debugging you will get a warning that val may be used uninitialized. Do try different flags, and in particular those that will be used in production, during development.

And finally, do take care of initializations everywhere. It's not all that difficult. Especially since the compiler will warn you if there is a problem.

Be defensive, not necessarily assertive.