For C programmers working on safety-critical applications, restrictions and guidelines to ensure safe coding practices can be painful. Features of the language that are designed to make your work easier or more efficient, or that provide work-arounds for obstacles, are often just the features that the guidelines disallow. But if you are developing applications for automotive, medical, mil/aero or other life-critical applications, you cannot afford to take chances. In some cases, such as avionics, compliance to accepted coding best practices can be part of the requirements traceability for rigorous assurance such as DO-178B/C. Even if your application does not require certification, you may still need to prove that your code was developed to the most stringent quality standards to mitigate liability and risk. For those types of applications, the newest version of MISRA C offers new hope for programmers.
Spend More Time Coding, And Less Time On Compliance Efforts
MISRA C is a software development language subset that was originally created to promote the use of the C programming language in safety-critical embedded applications within the motor industry. The original version was released in 1998 (MISRA C:1998) to target C90, and the 2004 version (MISRA-C:2004) included a host of extensions and improvements to the original.
While MISRA C is actually a language subset, not a coding standard, it provides a sound basis for coding best practises. Over the years, MISRA C has gained widespread acceptance as a de facto standard for safety-, life-, and mission-critical applications in aerospace, telecom, medical, defense, railway, and other industries, and is widely referred to as the MISRA standard.
The intention for the new MISRA version is to make development as predictable as possible, across projects or pieces of code, without errors of interpretation. Repeatability and predictability are key drivers. Even a dispersed development team—such as a prime contractor with many subcontractors—that follows the MISRA rules can be confident that all of the code will be consistent across the project. Following the new rules will help programmers mitigate software-related risks for safety-critical applications, while allowing them to spend more time coding and less time on compliance efforts.
Reasons For A New MISRA Version
Any updated coding practices or standards require developers to learn new rules and update their tools and programming methodologies. But this short-term inconvenience is outweighed by the advantages of updates that improve existing rules, extend support to the latest version of the language, and reduce development efforts overall. MISRA C:2012 was designed to:
- Add support for C99 while retaining support for C90
- Correct issues found in the 2004 version
- Provide backwards compatibility as much as possible to make it unnecessary to modify code when moving from MISRA C:2004 to MISRA C:2012
- Ensure all rules include a detailed rationale and remove rules without strong rationale
- Increase the number of decidable rules to allow better tool enforcement and reduce the amount of manual checking, saving time and money
- Include guidance on the applicability of rules to automatically generated code
What Has MISRA Done For You Lately?
In MISRA C:2012, rules have been made more precise so that the standard will not prevent reasonable uses orbehaviours that have no undesirable consequences. This will be good news for developers who may have been frustrated in the past by rules that were more restrictive than necessary, or that were too general. For instance, many developers hated the old rule about macros. It is possible to get into all sorts of difficulty using macros, so the simple approach was to say do not use them. Unfortunately, that prevents them from being used in circumstances where they provide a neat, convenient and technically sound solution. The new MISRA rules limit the use of macros to make sure they are only used properly.
In addition, developers now have better guidance on rules enforcement, such as whether a rule defines a general behavior across the project, or only specific cases. And all rules now include detailed rationale, which should help developers understand the need for the rule, rather than lead them to try to second-guess its intent.
The updated version also tells developers if a rule is “decidable”—those against which an analysis tool can always determine compliance or non-compliance— versus undecidable, in which this is not the case generally due to pointer or data values affecting control flow (Fig. 1). Undecidable rules can result in false-positive or false-negative test results simply because the tool has inadequate information available to it during analysis. This improvement in rules definition can significantly help reduce manual code-review requirements, and lets developers know ahead of time if another method of testing should be used.
Support For C99
MISRA C:2012 explicitly covers C99 as well as C90, maintaining backwards compatibility and making an effort to establish rules to cover both versions of the language as much as possible (very few rules may only be applicable to one or the other). In previous MISRA versions, some behaviour was implicitly undefined or unspecified in C90. Because developers may not have been aware of the existence or whereabouts of these “holes” in the language, they sometimes found it hard not to fall into them. These have now been explicitly defined in C99 so that developers know what circumstances to avoid.
MISRA C:2012 Offers A Reasoned Approach
Let us look at some specific examples of programming approaches that are now addressed with the more reasoned approach of MISRA C:2012.
Freeing Memory: AKA, Being Too Clever For Your Own Good
In some instances, developers have freed memory that is automatically allocated to variables for use elsewhere. This is legitimate C syntax, but is dangerous and unnecessary. The new MISRA rule is designed to prevent developers from being too clever for their own good. In this case, the rule states that a block of memory shall only be freed if it was allocated by means of a standard library function.
void fn ( void ) { int32_t a; free ( &a ); /* Non-compliant - a does not point to allocated storage */ }
MISRA C:2012 defines rules as “Required,” “Advisory” or as a new “Mandatory” category, which includes rules such as the above that must never be broken (Fig. 2). The first two categories can be broken with varying degrees of justification required, so that an “Advisory” rule might be at a programmer’s discretion, while “Required” might require the approval of a manager.
The Rationale Behind The Rules
The previous versions of MISRA may have seemed dictatorial in approach due to a lack of complete rationale. The new version enhances the concept of “rationale”—descriptions that explain why each rule is a good idea.
For instance, it is now a requirement that typedefs that indicate size and signedness should be used in place of the basic numerical types. For example, on a 32-bit C90 implementation the following definitions might be suitable:
typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef signed long int64_t;
From the perspective of portability, the rationale debunks the possible false perception that adherence to this guideline guarantees portability because the size of the int type may determine whether or not an expression is subject to integral promotion. For example, an expression with type int16_t will not be promoted if int is implemented using 16 bits but will be promoted if int is implemented using 32 bits. In other words, the rationale helps guide the developer around a common pitfall.
Not All Goto Statements Patch Up Wooly Thinking!
All too often, goto statements are used to patch up wooly thinking or an ill-defined algorithm. However, there are situations where the use of the goto statement is justified. For example, if there is an emergency situation in a process-control application, is it really better to set a flag and check it later in the algorithm than to take a direct route via a goto? The “goto statement should not be used” rule is now advisory rather than required, and an additional two rules narrow down the circumstances under which it is acceptable:
- The goto statement shall jump to a label declared later in the same function.
- Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement.
System-wide Analysis Sees The Big Picture
The new MISRA standard defines rules as applying to a “system-wide” or “single translation unit” analysis. A good example is the rule which prevents the same file from being open for read and write access at the same time on different streams. It is unlikely that anyone would do this deliberately, but a raised violation will help prevent mistakes. A tool may help confirm or deny a violation if it can reference all source code in that system through system-wide analysis.
MISRA Helps Meet Coding Best Practices
MISRA, in all its flavors, was developed to help software development teams create software applications of the highest quality, meaning code that has fewer defects and that is more maintainable, readable, consistent and verifiable. Essentially, MISRA is about applying best practices in coding. Understanding and meeting the requirements of MISRA C:2012 can help you meet high software-quality assurance requirements while allowing you to make better decisions about features of the programming language, optimize compiler use and make better use of hardware. Test tools that support MISRA compliance should allow you to easily choose between versions of the standard and appropriate subset (for both legacy and new projects), and should allow you to choose full compliance or a user-defined subset of rules that meet in-house templates or requirements.