0% found this document useful (0 votes)
25 views

Power of Ten

Adhering to a set of 10 verifiable coding rules can make analysis of critical software more reliable. The rules restrict control flow constructs, require loops to have fixed bounds, ban dynamic memory allocation, use assertions for checking, and minimize data scope. While strict, following a small set of rules precisely can enable formal analysis tools to verify properties of safety-critical code.

Uploaded by

bytesombrio
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views

Power of Ten

Adhering to a set of 10 verifiable coding rules can make analysis of critical software more reliable. The rules restrict control flow constructs, require loops to have fixed bounds, ban dynamic memory allocation, use assertions for checking, and minimize data scope. While strict, following a small set of rules precisely can enable formal analysis tools to verify properties of safety-critical code.

Uploaded by

bytesombrio
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 3

SOFTWARE TECHNOLOGIES

To put an upper bound on the num-

The Power of 10: ber of rules, I will argue that restrict-


ing the set to no more than 10 rules
will provide an effective guideline.

Rules for Although such a small set of rules can-


not be all-encompassing, following it
can achieve measurable effects on soft-
ware reliability and verifiability.

Developing Safety- To support strong checking, the


rules I will propose are somewhat
strict—some might even say dracon-

Critical Code ian. The tradeoff, though, should be


clear. When it really counts, especially
in the development of safety-critical
code, working within stricter limits can
Gerard J. Holzmann be worth the extra effort. In return, it
NASA/JPL Laboratory for Reliable Software should be possible to demonstrate
more convincingly that critical soft-
ware will work as intended.

SAFETY-CRITICAL
Adhering to a set of 10 verifiable CODING RULES
coding rules can make the analysis The choice of language for safety-
critical code is in itself a key consider-
of critical software components ation. At many organizations, JPL
more reliable. included, developers write most code
in C. With its long history, there is
extensive tool support for this lan-
guage, including strong source code
analyzers, logic model extractors, met-

M
ost serious software Not surprisingly, the existing cod- rics tools, debuggers, test-support
development projects use ing guidelines tend to have little effect tools, and a choice of mature, stable
coding guidelines. These on what developers actually do when compilers. For this reason, C is also
guidelines are meant to they write code. The most dooming the target of the majority of existing
define the ground rules aspect of many of the guidelines is that coding guidelines. For fairly pragmatic
for the software to be written: how it they rarely allow for comprehensive reasons, then, the following 10 rules
should be structured and which lan- tool-based compliance checks. Tool- primarily target C and attempt to opti-
guage features should and should not based checks are important because mize the ability to more thoroughly
be used. Curiously, there is little con- manually reviewing the hundreds of check the reliability of critical appli-
sensus on what a good coding stan- thousands of lines of code that are cations written in C.
dard is. written for larger applications is often These rules might prove to be ben-
Among the many coding guidelines infeasible. eficial, especially if the small number
that have been written, there are Existing coding guidelines therefore means that developers will actually
remarkably few patterns to discern, offer limited benefit, even for critical adhere to them.
except that each new document tends applications. A verifiable set of well-
to be longer than the one before it. The chosen coding rules could, however, Rule 1: Restrict all code to very simple
result is that most existing guidelines assist in analyzing critical software control flow constructs—do not use
contain well over 100 rules, sometimes components for properties that go goto statements, setjmp or longjmp con-
with questionable justification. Some well beyond compliance with the set structs, or direct or indirect recursion.
rules, especially those that try to stip- of rules itself. To be effective, though, Rationale: Simpler control flow trans-
ulate the use of white space in pro- the set of rules must be small, and it lates into stronger capabilities for
grams, may have been introduced by must be clear enough that users can analysis and often results in improved
personal preference; others are meant easily understand and remember it. In code clarity. Banishing recursion is per-
to prevent very specific and unlikely addition, the rules must be specific haps the biggest surprise here.
types of errors from earlier coding enough that users can check them Avoiding recursion results in having an
efforts within the same organization. thoroughly and mechanically. acyclic function call graph, which code

June 2006 93
SOFTWARE TECHNOLOGIES

analyzers can exploit to prove limits these problems and make it easier to cepting defects increase significantly
on stack use and boundedness of exe- verify memory use. with increasing assertion density. Using
cutions. Note that this rule does not Note that the only way to dynami- assertions is often recommended as
require that all functions have a single cally claim memory in the absence of part of a strong defensive coding strat-
point of return, although this often memory allocation from the heap is to egy. Developers can use assertions to
also simplifies control flow. In some use stack memory. In the absence of verify pre- and postconditions of func-
cases, though, an early error return is recursion, an upper bound on the use tions, parameter values, return values
the simpler solution. of stack memory can be derived stati- of functions, and loop invariants.
cally, thus making it possible to prove Because the proposed assertions are
Rule 2: Give all loops a fixed upper that an application will always live side-effect free, they can be selectively
bound. It must be trivially possible for within its resource bounds. disabled after testing in performance-
a checking tool to prove statically that critical code.
the loop cannot exceed a preset upper
bound on the number of iterations. If a Following a small set Rule 6: Declare all data objects at the
tool cannot prove the loop bound sta- smallest possible level of scope.
tically, the rule is considered violated.
of rules can achieve Rationale: This rule supports a basic
Rationale: The absence of recursion measurable effects principle of data hiding. Clearly, if an
and the presence of loop bounds pre- on software reliability object is not in scope, other modules
vents runaway code. This rule does cannot reference or corrupt its value.
not, of course, apply to iterations that
and verifiability. Similarly, if a tester must diagnose an
are meant to be nonterminating—for object’s erroneous value, the fewer the
example, in a process scheduler. In number of statements where the value
those special cases, the reverse rule is Rule 4: No function should be longer could have been assigned, the easier it
applied: It should be possible for a than what can be printed on a single is to diagnose the problem. The rule
checking tool to prove statically that sheet of paper in a standard format also discourages the reuse of variables
the iteration cannot terminate. with one line per statement and one for multiple, incompatible purposes,
One way to comply with this rule is line per declaration. Typically, this which can complicate fault diagnosis.
to add an explicit upper bound to all means no more than about 60 lines of
loops that have a variable number of code per function. Rule 7: Each calling function must
iterations—for example, code that tra- Rationale: Each function should be a check the return value of nonvoid
verses a linked list. When the loop logical unit in the code that is under- functions, and each called function
exceeds the upper bound, it must trig- standable and verifiable as a unit. It is must check the validity of all parame-
ger an assertion failure, and the func- much harder to understand a logical ters provided by the caller.
tion containing the failing iteration unit that spans multiple pages. Rationale: This is possibly the most
should return an error. Excessively long functions are often a frequently violated rule, and therefore
sign of poorly structured code. it is somewhat more suspect for inclu-
Rule 3: Do not use dynamic memory sion as a general rule. In its strictest
allocation after initialization. Rule 5: The code’s assertion density form, this rule means that even the
Rationale: This rule appears in most should average to minimally two asser- return value of printf statements and
coding guidelines for safety-critical tions per function. Assertions must be file close statements must be checked.
software. The reason is simple: used to check for anomalous condi- Yet, if the response to an error would
Memory allocators, such as malloc, tions that should never happen in real- be no different than the response to
and garbage collectors often have life executions. Assertions must be success, there is little point in explic-
unpredictable behavior that can sig- side-effect free and should be defined itly checking a return value. This is
nificantly impact performance. as Boolean tests. When an assertion often the case with calls to printf and
A notable class of coding errors also fails, an explicit recovery action must close. In cases like these, explicitly
stems from the mishandling of mem- be taken such as returning an error casting the function return value to
ory allocation and free routines: for- condition to the caller of the function (void) can be acceptable, thereby indi-
getting to free memory or continuing that executes the failing assertion. Any cating that the programmer explicitly
to use memory after it was freed, assertion for which a static checking and not accidentally decided to ignore
attempting to allocate more memory tool can prove that it can never fail or a return value.
than physically available, overstep- never hold violates this rule. In more dubious cases, a comment
ping boundaries on allocated memory, Rationale: Statistics for industrial cod- should be offered to explain why a
and so on. Forcing all applications to ing efforts indicate that unit tests often return value can be considered irrele-
live within a fixed, preallocated area find at least one defect per 10 to 100 vant. In most cases, though, a func-
of memory can eliminate many of lines of written code. The odds of inter- tion’s return value should not be

94 Computer
ignored, especially if the function tification for doing so because they can to the allocation and freeing of mem-
should propagate an error return seriously restrict the types of auto- ory, the use of stray pointers, etc. The
value up the function call chain. mated checks that code checkers can next few rules are fairly broadly
Rule 8: The use of the preprocessor perform. For example, if function accepted as standards for good cod-
must be limited to the inclusion of pointers are used, it can become ing style. Other rules secure some of
header files and simple macro defini- impossible for a tool to prove the the benefits of stronger coding styles
tions. Token pasting, variable argument absence of recursion, requiring alter- that have been advanced for safety-
lists (ellipses), and recursive macro calls nate guarantees to make up for this critical systems such as the “design by
are not allowed. All macros must loss in checking power. contract” discipline.
expand into complete syntactic units.
The use of conditional compilation Rule 10: All code must be compiled,

D
directives must be kept to a minimum. from the first day of development, evelopers are currently using this
Rationale: The C preprocessor is a with all compiler warnings enabled at rule set experimentally at JPL to
powerful obfuscation tool that can the most pedantic setting available. All write mission-critical software,
destroy code clarity and befuddle code must compile without warnings. with encouraging results. After over-
many text-based checkers. The effect All code must also be checked daily coming a healthy initial reluctance to
of constructs in unrestricted pre- with at least one, but preferably more live within such strict confines, devel-
processor code can be extremely hard than one, strong static source code opers often find that compliance with
to decipher, even with a formal lan- analyzer and should pass all analyses the rules does tend to benefit code
guage definition. In a new implemen- with zero warnings. safety. The rules lessen the burden on
tation of the C preprocessor, Rationale: There are several extremely developers and testers to use other
developers often must resort to using effective static source code analyzers means to establish key properties of
earlier implementations to interpret on the market today, and quite a few code such as termination or bounded-
complex defining language in the C freeware tools as well. There simply is ness and safe use of memory and stack.
standard. The rationale for the caution no excuse for any software develop- If these rules seem draconian at first,
against conditional compilation is ment effort not to use this readily bear in mind that they are meant to
equally important. With just 10 con- available technology. It should be con- make it possible to check safety-criti-
ditional compilation directives, there sidered routine practice, even for non- cal code where human lives can very
could be up to 210 possible versions of critical code development. literally depend on its correctness. The
the code, each of which would have to The rule of zero warnings applies rules are like the seat belts in a car:
be tested—causing a huge increase in even when the compiler or the static Initially, using them is perhaps a little
the required test effort. The use of con- analyzer gives an erroneous warning: uncomfortable, but after a while it
ditional compilation cannot always be If the compiler or analyzer gets con- becomes second nature, and not using
avoided, but even in large software fused, the code causing the confusion them is unimaginable. ■
development efforts there is rarely jus- should be rewritten. Many developers
tification for more than one or two have been caught in the assumption The research described in this paper
such directives, beyond the standard that a warning was surely invalid, only was carried out at the Jet Propulsion
boilerplate that avoids multiple inclu- to realize much later that the message Laboratory, California Institute of
sions of the same header file. A tool- was in fact valid for less obvious rea- Technology, under a contract with the
based checker should flag each use and sons. Static analyzers have somewhat National Aeronautics and Space
each use should be justified in the code. of a bad reputation due to early ver- Administration.
sions that produced mostly invalid
Rule 9: The use of pointers must be messages, but this is no longer the case. Gerard J. Holzmann is a Principal Com-
restricted. Specifically, no more than The best static analyzers today are fast, puter Scientist at NASA’s Jet Propulsion
one level of dereferencing should be and they produce accurate messages. Laboratories, where he leads the Labo-
used. Pointer dereference operations Their use should not be negotiable on ratory for Reliable Software. Contact
may not be hidden in macro defini- any serious software project. him at [email protected].
tions or inside typedef declarations.
Function pointers are not permitted. FOLLOWING THE RULES
Rationale: Pointers are easily misused, The first few rules from this set
Editor: Michael G. Hinchey, NASA Soft-
even by experienced programmers. guarantee the creation of a clear and
ware Engineering Laboratory at NASA
They can make it hard to follow or transparent control flow structure that
Goddard Space Flight Center and Loyola
analyze the flow of data in a program, is easier to build, test, and analyze.
College in Maryland;
especially by tool-based analyzers. The absence of dynamic memory allo-
[email protected]
Similarly, function pointers should be cation, stipulated by the third rule,
used only if there is a very strong jus- eliminates a class of problems related

June 2006 95

You might also like