NASA’s ten coding commandments
NASA has produced its own set of coding standards to ensure code quality and safety among all NASA applications. These standards have evolved from their own guidelines and are set to be applicable to the greater software development industry.
The National Aeronautics and Space Administration, a.k.a. NASA, has been busy looking after the civilian space program as well as continued aeronautics and aerospace research. So it comes as no surprise that their own experience in software development has led them to publish a set of coding guidelines. The research was carried out by the Jet Propulsion Laboratory’s (JPL) Laboratory for Reliable Software.
Rules for code safety
A huge amount of arbitrary rules and inconsistent guidelines causes code quality of even the most critical applications to suffer, according JPL lead scientist Gerard J. Holzmann. That’s why the lab has released ten coding commandments to govern all NASA software: “The Power of Ten — Rules for Developing Safety Critical Code”.
Holzmann and the team penned the rules for developing software with code safety in mind. The rules were specifically written with regards to C, as NASA backs the language for safety-critical code with its long history and extensive tool support. However, the rules can be applied to coding in most other programming languages:
- Restrict all code to very simple control flow constructs — do not use goto statements, setjmp or longjmpconstructs, and direct or indirect recursion.
- All loops must have a fixed upper-bound. It must be trivially possible for a checking tool to prove statically that a preset upper-bound on the number of iterations of a loop cannot be exceeded. If the loop-bound cannot be proven statically, the rule is considered violated.
- Do not use dynamic memory allocation after initialization.
- No function should be longer than what can be printed on a single sheet of paper in a standard reference format with one line per statement and one line per declaration. Typically, this means no more than about 60 lines of code per function.
- The assertion density of the code should average to a minimum of two assertions per function. Assertions are used to check for anomalous conditions that should never happen in real-life executions. Assertions must always be side-effect free and should be defined as Boolean tests. When an assertion fails, an explicit recovery action must be taken, e.g., by returning an error condition to the caller of the function that executes the failing assertion. Any assertion for which a static checking tool can prove that it can never fail or never hold violates this rule (I.e., it is not possible to satisfy the rule by adding unhelpful “assert(true)” statements).
- Data objects must be declared at the smallest possible level of scope.
- The return value of non-void functions must be checked by each calling function, and the validity of parameters must be checked inside each function.
- The use of the preprocessor must be limited to the inclusion of header files and simple macro definitions. Token pasting, variable argument lists (ellipses), and recursive macro calls are not allowed. All macros must expand into complete syntactic units. The use of conditional compilation directives is often also dubious, but cannot always be avoided. This means that there should rarely be justification for more than one or two conditional compilation directives even in large software development efforts, beyond the standard boilerplate that avoids multiple inclusion of the same header file. Each such use should be flagged by a tool-based checker and justified in the code.
- The use of pointers should be restricted. Specifically, no more than one level of dereferencing is allowed. Pointer dereference operations may not be hidden in macro definitions or inside typedef declarations. Function pointers are not permitted.
- All code must be compiled, from the first day of development, with all compiler warnings enabled at the compiler’s most pedantic setting. All code must compile with these setting without any warnings. All code must be checked daily with at least one, but preferably more than one, state-of-the-art static source code analyzer and should pass the analyses with zero warnings.
Rationales have been included under each rule in the official paperwork, which as a whole may come across as rather strict on the first read through. However, as Holzmann explains:
If the rules seem Draconian at first, bear in mind that they are meant to make it possible to check code where very literally your life may depend on its correctness: code that is used to control the airplane that you fly on, the nuclear power plant a few miles from where you live, or the spacecraft that carries astronauts into orbit.
These rules may be just the digital seat belt the industry needs — after all, it would be in our best interest to avoid catastrophes such as these…