MISRA C:2012 Rule 1.3 and the Dark Underbelly of C and C++April 9, 2020 Tweet
MISRA C is a set of guidelines for the safe use of the C programming language mainly targeted for its use in safety-critical embedded systems. Many of its rules and directives are meant to help software developers write code that is easier to understand and maintain. Software development is teamwork so these coding style rules are important to help make the source code easy to understand. Other rules disallow risky constructs or known poor programming practices.
A great example of a coding style rule is rule 5.3 “An identifier declared in an inner scope shall not hide an identifier declared in an outer scope”. This is clearly a coding style warning. A violation of this rule will not by itself cause the program to crash. However, such declarations can make the code more difficult to understand because the inner identifier may be confused with the outer one.
Violations of these types of coding style guidelines are generally easily found by a static analysis tool. For rule 5.3, a tool can precisely find where an inner declaration hides an outer declaration. MISRA lists this rule as ‘decidable,' meaning that it is possible for a static analysis tool to find violations with few or no false positives.
Rule 1.3 and Undefined Behavior
MISRA-C:2012 rule 1.3 is a completely different category; it states ‘There shall be no occurrence of undefined or critically unspecified behavior’. Often people don’t fully appreciate the significance of this rule and the complexity behind checking for violations of it. Undefined behavior is the Achilles’ Heel of the C programming language; it is easy to make mistakes that cause undefined behavior and the consequences can be disastrous. If you’re lucky the program will crash right away, in which case the cause is likely to be obvious; if you’re unlucky, the undefined behavior will silently corrupt the program state and the program will do the wrong thing or fail outright later with mysterious symptoms. Undefined behavior is caused by bugs such as buffer overruns, reading uninitialized memory, dereferencing invalid addresses, and even concurrency problems such as data races. Many of the most serious security vulnerabilities have their root cause in undefined behavior.
The standard for C90/C99 lists 230 instances of undefined behavior, and although some of these are explicitly disallowed by MISRA C 2012, about a quarter are not covered by any rule other than Rule 1.3. Consequently that one rule covers a lot of ground.
I consider Rule 1.3 the single most important rule in the MISRA rulebook because eliminating undefined behavior directly addresses functional safety.
Finding undefined behavior requires static analysis tools to reason about the deep semantics of a program. Lightweight tools might be able to find some instances, but it requires very sophisticated machinery to the really serious defects; those that involve complicated control and data flow across components implemented in different source files. Static analysis tools that can accomplish this do so using techniques that involve whole-program data and control-flow analysis, typically using a form of abstract interpretation.
Detecting and resolving as many of these problems as possible in your development cycle is crucially important. I recently spoke with a customer that lost 4 weeks of engineering time trying to locate an uninitialized variable problem. Our static analysis tool, CodeSonar was able to find the problem immediately. This is because CodeSonar was designed to find the most serious software defects and the most hazardous security vulnerabilities.
Real Functional Safety is More Important than Conformance
Some organizations are now requiring that code conform to MISRA C. This is a good thing because many of the MISRA C rules are about making the code easier to understand and maintain, and that is very important. However there is a serious danger in letting conformance be the sole driver of your static-analysis efforts, because focusing too closely on the superficial properties of the code can blind you to the fact that functional safety is what really matters most. A simplistic static analysis tool may report no violations on a program, yet that program may be riddled with serious defects due to undefined behavior. Consequently, static analysis tools that are good at finding violations of Rule 1.3 are more valuable than tools that are designed to find only violations of the more superficial properties.
CodeSonar may find five times as many serious software defects as comparable static analysis tools. Yes, this may mean your team has to triage more static analysis warnings to look at, but doing so is valuable because it means you are catching more bugs earlier when they are easier and cheaper to fix.
Interested in learning more? Read our guide "Accelerating Software Safety with MISRA and Static Analysis"