By John Lakos
In our component-based development methodology, each developer is responsible for ensuring that the software he or she creates is easy to understand and use, and not especially easy to misuse. One common form of misuse is to invoke a library function or method under circumstances where not all of its preconditions are satisfied, leading to undefined behavior. Contracts having undefined behavior are not necessarily undesirable, and (for many engineering reasons) are often optimal. Most would agree that a well-implemented library should do something other than silently continue when a pre-condition violation is detected, although these same folks might not agree on what specific action should be taken. Unfortunately, validating preconditions implies writing additional code that will execute at runtime. More code runs slower, and some would fairly argue that they should not be forced to pay for redundant runtime checks in the library software they use. Whether and to what extent library functions should validate their preconditions, and what should happen if a precondition violation is detected are questions that are best answered on an application by application basis - i.e., by the owner of main. "Defensive Programming Done Right" makes it all possible.
In this talk, we begin by reviewing the basic concepts of Design-By-Contract (DbC), and what we mean by the term "Defensive Programming" (DP). We then explore our overall approach to institutionalizing defensive programming in robust reusable library software such that each application can conveniently specify both the runtime budget (e.g., none, some, lots) for defensive checking, and also the specific action to be taken (e.g., abort, throw, spin) should a precondition violation occur. Along the way, we touch on how modern compilers and linkers work, binary compatibility, and the consequences of possibly violating the one-definition rule in mixed-mode builds. We conclude the talk by describing and then demonstrating our "negative testing" strategy (and supporting test apparatus) for readily verifying, in our component-level test drivers, that our defensive checks detect and report out-of-contract client use as intended. Actual source for the supporting utility components will be presented throughout the talk and made available afterwards.