By: Tom Williams, Editor-in-Chief
C is the most widely used programming language—and can be quite complex. A standard set of rules is available to avoid any inherent ambiguities and to help programmers steer a course to reliable code.
At this point in the embedded industry, the C language has become not only the most widely used programming language, but almost the lingua franca of the whole computer world, embedded and enterprise. You may use other languages, but you’d better jolly well understand C as well. Since its introduction in 1972 by Brian Kernigan and Dennis Richie of AT&T Bell Labs, C has moved to an international standard under the auspices of the International Organization for Standardization (ISO), which has released several standard specifications over the years, the first being C90, released in 1990 followed by C99 in 1999—a version that offers a number of extended features. The latest version is now C11. However, C99 is of most immediate interest to the embedded community, which will delay a move to C11 until it has been proven over time, a process that could take from five to six years. The overriding reason for this delay is concern for reliability and safety.
The concept of reliability is fairly straightforward—can I count on this thing to do what it is supposed to do every time and for the long term? The concept of safety is a bit broader. It includes the idea of preventing unpredictable behavior, but it also includes ideas of preventing harm to equipment and human life. Some amount of safety can be guaranteed by reliability. Other aspects require thought to the overall design of a system such as not having a robot arm swing into areas that might be occupied by a human head. That requirement, of course, also depends on the ability to reliably expect safe behavior under all circumstances. So when we talk about reliability and safety of a programming language like C, we are generally referring to reliability—that it will perform as expected and reliably execute safely designed system functions.
In order to ensure reliably predictable behavior with C, it is necessary to deal with two factors. One is to help the programmer avoid situations where the programming, while technically predictable, could, as a result of the inappropriate use of certain functions, lead to code that is overly complex and difficult to understand and maintain. This could lead to a misinterpretation of what behavior is to be expected. Another factor is that certain parts of the C language are simply not fully defined. As a result, various compiler manufacturers have gone ahead and built compilers that represent their own interpretation of what these “holes” in the language definition are intended to do.
Now, as long as the programmer stays with the compiler(s) of a single vendor, the behavior of these sections should be consistent. The problem comes when you try to move code that has been developed by one designer, to a different compiler whose designers have made different assumptions about the expected behavior of these portions of the language.
One might be tempted to ask, “Why, then, don’t we go back and via ISO specifically define these portions of the language so that they operate as predictably and reliably as the other parts of C?” Alas, the world is not going to work that way. Consider simply which compiler vendors would be disadvantaged and which helped on the basis of such a decision by the standards body? Whose code would suddenly be in compliance with a worldwide standard and whose would not? There are definite disagreements among compiler manufacturers about the best way to interpret these sections, and they are not at all likely to relent on their opinions. Suffice it to say, that is not going to happen.
Still, we need a way to ensure reliable and safe systems, and the Motor Industry Software Reliability Association (MISRA) of the UK has produced an updated standard set of rules for identifying and working around the aspects of C that are ambiguous and/or dangerous (Figure 1). This latest set of rules, which is based on C99, can be built into a text checking system that will identify when a program has used one of these aspects of C. It will tell the programmer, “Don’t do that,” and will then offer suggestions for how to revise the code so that it is in compliance with what MISRA says you should do.
According to Mark Pitchford, senior field application engineer for LDRA, MISRA has become much better at providing the workaround advice, “with the explanation of what the problem is and what you can do about it.” A MISRA-based code checker is primarily intended for use in the development of new code, which means doing checks regularly during the development process. “If you run code that hasn’t been checked in the course of development, the chances are there will be violations all over the place,” says Pitchford.
The MISRA rules are classed as “required” and “advisory” along with a new class called “mandatory,” or rules that are never to be broken. An example of the latter is:
Rule 22.2 A block of memory shall only be freed if it was allocated by means of a Standard Library function.
There have been instances of developers freeing memory automatically allocated to variables for use elsewhere. This remains possible and is legitimate C syntax, but it is dangerous and unnecessary. It is certainly difficult to track down in case of a problem. The rule is designed to prevent developers from being “too clever for their own good.” While the above rule is classed as “mandatory,” i.e., you can’t use it and be MISRA-compliant, the other two have different levels. “Advisory” means the programmer may use his or her discretion while “required” means the programmer needs a supervisor’s approval to ignore it. These can all be included in the documentation produced by the rule checker.
There are certain cases where the rule that might be applied is itself not an absolute. In this case, the latest set of MISRA rules has made adjustments and provided explanations. One example is the goto statement. Goto is not an ambiguous function; it is a valid statement as far as the definition of the language is concerned. However, according to Pitchford, its overuse or inappropriate use can be an alarm bell, “in some cases that the structure of the code is not quite properly thought out,” or it can be used to patch up wooly thinking. Often, by not relying on the flow of the language, it can lead to code that is hard to follow and maintain. In past versions, MISRA said simply not to use goto.
However, there are instances where goto could be very appropriate such as a process control application where some critical parameter such as a chemical tank or reactor core temperature is going above a safe value. At this point, the code could quickly use goto to trigger a shutdown. Therefore, MISRA has enhanced the concept of “rationale” descriptions of why each rule is a good idea:
Rule 15.1 The goto statement should not be used is now advisory rather than required, and an additional two required rules to narrow down the circumstances under which it is acceptable, vis.
Rule 15.2 The goto statement shall jump to a label declared later in the same function. and
Rule 15.3 Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement.
This both makes the use of goto an advisory rule while at the same time specifying the limited conditions for its use, both of which can be verified by the rule checker.
MISRA rule checkers can be expected from various vendors, which will operate as source analysis tools during code development and possibly also be invoked at compile time. Currently, LDRA offers its version of the rule checker in two forms. One, called LDRArules, incorporates the MISRA rule set with other rule sets. The developer can select one or more sets of rules to verify his or her code (Figure 2). This is primarily for the developer who wants to assure that the code meets safety and reliability requirements, but who does not need to certify compliance to some specification like an FDA or FAA requirement. For those cases, LDRArules is included in the larger LDRA tool suite and is part of the overall static analysis provided by that product.
Nuneaton, Warwickshire, UK.
+44 24 7635 5071.
© 2009 RTC Group, Inc., 905 Calle Amanecer, Suite 250, San Clemente, CA 92673