“An ounce of prevention is worth a pound of cure.”
— Benjamin Franklin
When you ask folks who sell static analysis tools why you should buy their expensive products, they all will tell you “to find bugs, of course!”. Very likely, they will show you a diagram that displays the exponential cost growth of fixing a bug, depending on the stage where it is detected. Also very likely, they will brag that — compared to PC-lint — they have a very low “false positive” rate.
Fair enough, but the story doesn’t end here. Take this code, for instance:
1 2 3 |
#include <iostream> |
1 2 3 |
#define ADD(x, y) x + y |
1 2 3 4 5 6 7 8 9 10 |
class Base { public: Base(int i) : _i(i) { ... } int add(int a, int b) { return ADD(a, b); } ~Base() { ... } private: int _i; }; |
1 2 3 4 5 |
class Derived : public Base { void increment() { ... } }; |
The code, as it stands, is 100% error-free. Yet, PC-lint will not like it for several good reasons. For instance:
- There are no virtual functions in Base, so what’s the point deriving from it? Was it an oversight?
- There is no default constructor, and hence you cannot put objects of type Base in standard library containers
- The Base constructor is not explicit, so plain integers might get silently converted into Base objects
- The add method could be declared const; adding const-correctness later is usually difficult
- The ADD macro is not parenthesized and neither are its parameters; this gives rise to all sorts of operator precedence problems
- Base’s destructor is not virtual, which means that the behavior is undefined when somebody deletes Derived objects through a pointer to Base
- The iostream header file is not used and hence not needed; removing the #include statement improves clarity and compilation times
So there are no bugs. But are these issues flagged by PC-lint really false positives?
Too me, the reported warnings are a sign of the poor quality of this code; this code is full of latent bugs, just waiting to become alive in the future or in somebody else’s hands. Shady code like this increases technical debt, makes maintenance harder, riskier, and more expensive.
I want such issues reported and resolved before I check in my code, actually, before I even execute it. Right after a successful compile I pay attention to PC-lint’s feedback and resolve real bugs, latent bugs and any bad coding practices. I don’t want to get a ticket three weeks later from a software QA guy, after I’m done with debugging and when the mental distance has become large. So large that it would take a lot of effort to recall what I was thinking at the time of writing. I want quick and easy desktop checking such that my bad code is never seen by anyone but me.
Finding bugs and code smells at the earliest possible time and thus keeping maintenance cost lost; not just focusing on finding bugs, but preventing bugs — today and tomorrow — in the first place. That’s the true value of PC-lint.