|For novel ideas about building embedded systems (both hardware and firmware), join the 27,000+ engineers who subscribe to The Embedded Muse, a free biweekly newsletter. The Muse has no hype, no vendor PR. It takes just a few seconds (just enter your email, which is shared with absolutely no one) to subscribe.|
By Jack Ganssle
The MISRA Standard
English is a complex and wonderfully expressive language, full of oddball peculiarities, homonyms, and perverse punctuations. Anyone who reads USENET, email, or even (alas) billboards, sees how few Americans know the difference between their, there and they're. Than and then get confused almost as often as affect and effect. And is it its or is it it's?
Lynne Truss humorously pointed out that a Panda "eats shoots & leaves." Add a comma, the tiniest of all typographical constructs, after "eats" and the phrase now expresses an entirely different idea.
Suggestion: Subscribe to my free newsletter which often talks about standards, MISRA, and tools to automate compliance.
The word "display," so often used in programs as part of a function name, can be the noun indicating the display hardware, or the verb "to show." Which is it? Better think it through when incorporating it as port of a function or variable name.
Do you lie down or lay down? What does "lay" mean, anyway? Just the verb form has 52 different definitions in The American Heritage Dictionary of the English Language. As a noun it can be a ballad; as an adjective it denotes a secular person.
Then there's "lie" which means reclining, being mendacious, the hiding place of an animal, and more. Sometimes the context makes the meaning clear, which creates this epistemological puzzle that words themselves carry only a fraction of one's intent. Since a sentence may have many words whose meaning recursively depends on context it's a wonder we manage to communicate at all.
C, too, is a wonderfully expressive language, one whose grammar lets us construct torturous though perfectly-legal constructions. ****************i=0; is semantically and linguistically correct, yet solving Poincare's Conjecture might be a shade easier than following that chain of indirection. Just a few deft lines of nested ifs can yield a veritable explosion of possible permutations that the compiler accepts with the wisdom of Buddha. But humans and lesser gods cannot decipher all of the inscrutable possibilities.
The International Obfuscated C Code Contest (www.ioccc.org) runs a competition to, ah, "honor" incomprehensible yet working C programs. One winner in 2004 supplied the code in Figure 1, which (somehow) graphs polynomials.
Figure 1: Your worst nightmare: maintaining this. Reprinted with permission of the IOCCC.
Any computer language that lets us construct such convoluted and unmaintainable bits of agony must be eliminated or tamed. C isn't going away, so it's up to us to use it in a grownup fashion that eases debug, test and maintenance.
Post-processing tools like Lint help find bugs, but they don't insure we're building clean code that people can understand. Complexity analyzers do flag modules that look difficult, but, again, only work on code we've already written. I ran the program in Figure 1 through a complexity analyzer and the tool sputtered out some warnings and then crashed.
Program proactively. Write code that's inherently good even before it's compiled or processed by some tool. That's the point of a software standard; it defines what sort of operations and constructs are allowed before you press the editor's "save" button. The C language is an entire universe of possibilities whose vastness the standard narrows to safer, more comprehensible, subset.
Enter MISRA, the Motor Industry Software Reliability Association. This consortium of automotive and related companies was formed to find better ways to build firmware for cars. For the vendors are terrified of software. Though it adds tremendous value to their products, the cost of defects is staggeringly high. One little bug can initiate a crippling recall. My wonderful hybrid Prius whose average 52 MPG results from very smart firmware was recalled last year due to a software problem. (Yes, the 52 is real, averaged over 162k miles, though unlike most of us my wife and I don't drive as if all the demons of hell are in hot pursuit). The last version appeared in 2004, but a few weeks ago MISRA 2012 hit the street. Among other improvements it now handles C99 (as well as C90).
MISRA 2012 is huge, at 236 pages about double the size of the previous standard. A few more rules were added, and the wording of many of the others changed. MISRA 2012 has better explanations of the rationale behind each rule.
Now there are rules as well as directives. The latter are guidelines which may require access to other resources to prove compliance. An example is Directive 3.1: "All code shall be traceable to documented requirements." Rules can be tested just by examining the code.
The CERT standard took a strong stand against code that can have unwanted side-effects (like careless use of the increment and decrement operators). MISRA 2004 had some rules about these issues, but the new version is much more explicit.
But some of the rules and directives leave me scratching my head. Directive 4.1 says "Run-time failures shall be minimized." What does that mean? How can one measure it? What does "minimize" mean, quantitatively? This rule almost leaves one thinking that it's an advisory against the use of C, which places the burden of taking care of runtime problems entirely in the programmer's lap. The guidelines suggest adding code to deal with problems and using static analyzers, both great ideas. But I can't see how one can claim conformance with the Directive without making some sort of formal argument rather like a safety case. And that's quite an expensive proposition.
5.2.1 goes further, and says, among other things, that developers have to demonstrate that run-time errors have been avoided. "Run-time error" is not defined, though examples (like arithmetic overflow) are given. Is code that doesn't implement a requirement properly a run-time error? Absent a proof-checking language like SPARK this seems more a wish than a command.
5.5 is probably wise but will be problematic for non-greenfield projects that require adherence to MISRA. To claim compliance one must assure, among other things, that all of the C code in the project meets MISRA 2012. Using Linux? Forget putting a MISRA badge on the project. Is there legacy code (and most projects use lots)? Well, I'd advise using MISRA for the new code, but you won't get compliance points.
I'm a strong advocate of MISRA. No one (well, with the possible exception of those who crafted the standard) likes all of the rules, but most of them make a lot of sense. MISRA is one way to get a firmware standard in place fast, one that has plenty of street cred. If you don't have regulatory compliance issues, overcome objections to the few rules you don't like by subsetting it.
Happily a lot of automatic compliance checkers exist. Somelet you pick and chose which rules to check.
There's more info here: http://misra.org.uk/. For a lousy 15 quid all of us can get all the benefits with none of the work. Talk about a no-brainer!