MISRA C - For Today’s Embedded Software Development

Author : Mark Pitchford, LDRA

01 September 2023

Figure 1: MISRA compliance report example
Figure 1: MISRA compliance report example

The MISRA Working Group recently announced 2 updates of its MISRA guidelines, MISRA C:2012 Amendment 4 (AMD4) and MISRA C:2023.

These mark a critical step in supporting the needs of embedded software developers. Long held as the industry standard for the development of safety/security-critical devices, MISRA C brings code and process guidance to developers to help reduce the risk of unexpected and undefined behaviours in their applications. 

With continued growth in feature-rich and connected devices, manufacturers of safety/security-critical products have turned to more sophisticated techniques to extract further capabilities out of resource-constrained microprocessors, microcontrollers and peripherals. After years of real-world research and development, the MISRA C guideline updates address these modern techniques with guidance relating to multithreading and atomic types in support of the C standards ISO/IEC 9899:2011 and 2018 (known as C11 and C18 respectively).

MISRA C is not a coding style guide, but rather a set of rules and directives for minimising or eliminating language syntax and semantic usage known to be hazardous. As part of a comprehensive software development process, many development teams apply a language style guide in addition to the MISRA C guidelines.

Why C developers need MISRA C guidelines
Embedded developers routinely include software safety, security and reliability requirements in their processes for building systems that range from automotive engine control units through to industrial machines. If such systems behave in an unexpected manner, rather than strictly in ways intended by the developer, then safety issues and security vulnerabilities will likely result.
Yet embedded developers face challenges to ensure this. For starters, the C language allows developers to control application behaviour and memory in ways that could compromise their intended behaviour. In addition, C11 and C18 provide only an incomplete specification of runtime intention, leaving some aspects up to the developer to decide. This leads to non-deterministic components of the C language, giving license to developers in ways that could pose risks to a system under development. These include: 
•Undefined behaviour - where the C standard does not specify a clear requirement. 
•Unspecified behaviour - where the C standard allows for 2 or more possibilities and does not specify clear requirements regarding which is used. 
•Implementation defined - where the compiler and runtime are free to define their own behaviours and must document these behaviours themselves. 
One example of undefined behaviour is leaving variables of large array types un-initialised. To avoid incurring the processing cost of memset() calls to zero-initialise memory, developers sometimes forgo the practice of initialising these data types. Because there is no specification in the C standard of how implementations should handle un-initialised array types, this practice may cause unpredictable consequences at runtime. For that reason, many compilers and static analysers will flag it as a concern. This is a very simple example of the sort of loopholes that the MISRA C guidelines aim to eliminate. Other examples are: 
•Writing to a file stream opened as read-only, leading to potentially undesirable behaviour.  
•Using recursive functions, with the prospect of stack overflow occurring.  
•Accessing memory outside the bounds of a data structure (e.g. buffer overflow), which could present a potential attack surface for hackers to exploit. 

MISRA C is present in many functional safety standards that developers must adhere to. The guidelines are directly cited by or commonly practiced in projects following AUTOSAR, IEC 62304, IEC 61508, ISO 26262 and DO-178C processes. MISRA C also forms the basis of the Joint Strike Fighter C++ coding standard and NASA’s Jet Propulsion Library C coding standard, amongst others. 

The structure of MISRA C guidelines 
MISRA C guidelines restrict C language syntax and semantics to a predictable subset that meets the needs of safety/security-critical systems. Through rules and directives, these guidelines tackle coding practices that are known to be hazardous or insecure. The following gives illustrations of such rules/directives.
Rule: A source code requirement that is complete, objective and unambiguous. The guidelines classify rules as ‘decidable’ if they can be conclusively verified through techniques (such as static analysis) and ‘undecidable’ if no verification guarantee is possible.  
Example rule: “The value of an object with automatic storage duration shall not be read before it has been set.” (MISRA C:2012 Rule 9.1)  
Directive: A guideline that may be satisfied through code, processes, documentation, or functional requirement. Because directives can be subject to interpretation, analysis tools may be able to assist in checking compliance. If not, different validation techniques must be used.  
Example directive: “Any implementation-defined behaviour on which the output of the program depends shall be documented and understood.” (MISRA C:2012 Directive 1.1) 

Take this example that uses the C sizeof() operator in accordance with the C standard: 
void foo(int32_t x) 
    size_t x; 
    s = sizeof(int32_t[x]);   //Compliant to MISRA C 
    s = sizeof(int32_t[x++]); //Non-compliant to MISRA C 
As sizeof() does not execute expressions passed into it, but simply evaluates the type and size of the resulting expression at compile time, this code could result in unexpected behaviour at runtime. As such, usage is restricted by MISRA C:2012, Rule 13.6, stating that; “The operand of the size of operator shall not contain any expression which has potential side effects.”
This is a decidable rule - meaning a developer can use static analysis to find occurrences in code where this rule was violated. Once identified, developers can correct the error with a simple adjustment: 
void foo(int32_t x) 
   size_t x; 
   s = sizeof(int32_t[x]); //Compliant to MISRA C 
   s = sizeof(int32_t[x]); //Compliant to MISRA C 

The 25-year evolution of MISRA C guidelines, along with the increasing complexity of embedded software, has fostered decades of advancements in compliance-checking tools, and MISRA C itself recommends use of static analysis tools to ensure compliance.
How MISRA C applies to cybersecurity
Most principles for code safety also apply to code security, simply because well-written code is both safe and secure. A common security exploit is the buffer overflow, where the volume of data written to an area of memory exceeds the actual size of that memory allocation. A hacker can exploit this behaviour to overwrite protected areas of memory - potentially changing the execution path of programs or introducing their own malicious code. MISRA C covers this scenario in section 8.18: Pointers and Arrays - with rules that are pertinent to both safety and security.

For example, MISRA C:2012 Rule 18.2 states that; “A pointer resulting from arithmetic on a pointer operand shall address the same array as that pointer operand.” 

Consider the following example in that context. This code may introduce a buffer overflow condition due to the lack of validating the length of the incoming message, pMessage.

extern uint8_t buffer[16];

/* pMessage points to an external message
*  The first byte holds the length of the message

Figure 2: Example MISRA deviation record (Source: MISRA Compliance:2020 guide)
Figure 2: Example MISRA deviation record (Source: MISRA Compliance:2020 guide)

void processMessage (uint8_t const *pMessage)
   uint8_t length = *pMessage; /* Length not validated */
   for (uint8_t i = 0u; i < length; ++i)
   buffer[i] = *pMessage;

A static code analyser would report this as a MISRA C violation, as per the above rule. Once identified, developers can correct this behaviour with bounds-checking and an error handler on pMessage.

The MISRA C guidelines also include explicit guidelines for secure coding where appropriate, further helping developers to avoid insecure coding practices. In turn, static analysis tools implement a clear analysis method for detecting potential vulnerabilities.

An example of such a guideline would be; “The validity of values received from external sources shall be checked” (MISRA C:2012 Directive 4.14). By far the most important secure coding practice is to validate any data that comes from an external source, such as an RS232 port, user input, or a different domain. This implies a need for ‘defensive’ code to constantly check not just that the data received is within the expected bounds, but also to ensure that the data makes sense. For example, a history of commands received over time can be employed to check for abnormal patterns of use. 

Implementing MISRA C compliance

MISRA C guidelines do not list specific processes and tools for achieving compliance, as such details would unfairly limit what embedded development teams can procure and implement. Rather, the MISRA Compliance:2020 guide provides definitions of what must be covered within the software development process when making a claim of MISRA compliance. 

This guide states that claims of compliance must include: 
•Use of a disciplined software development process. 
•The exact guidelines applied. 
•The effectiveness of the enforcement methods. 
•The extent of any guideline deviations. 
•The status of any software components developed outside of the project. 

Embedded software teams must decide how to best apply MISRA rules/directives to their development and quality assurance processes. Given the complexity of contemporary embedded applications and the speed of release cycles, most teams include an automated checking tool in their compliance strategy - to reduce manual effort, improve coverage and minimise human error. MISRA Compliance:2020 recommends use of static analysis tools, but the guidelines also warn that automation cannot check all rules and directives fully.
The latest AMD4 and MISRA C:2023 editions cover C multithreading and atomic types to address the concurrency and inter-process techniques growing in use among embedded developers today. While many best practices focus on thread performance and memory optimisation, MISRA C guidelines focus exclusively on avoiding undefined and unpredictable concurrency behaviours that may compromise system safety/security.
The guidelines minimise potential concurrency issues by addressing multithreading features of the C language, including:  
•Restricting dynamic thread creation to enforce deterministic approaches to concurrency.?? 
•Ensuring that the application creates threads before linking mutexes to them.?? 
•Minimising the risk of deadlocks and data races. 
•Managing the safe use of thread objects and thread identifiers.? 
MISRA C also features guidelines that address undefined behaviours in atomic types that may compromise the system. These guidelines include: 
•Ensuring that the application configures atomic types?correctly.? 
•Preventing unintended removal of atomicity when referencing atomic types through pointers.?? 
•Restricting use of multiple atomic types in the same statement.? 
The new editions include other rules that reflect issues arising from real-world usage of the C language in recent years. These rules include restricting use of small integer macros and certain designated initialiser scenarios that may result in multiple, conflicting initialisations of the same element. 

To simplify and streamline compliance and configuration management, MISRA C:2023 consolidates all earlier MISRA C editions and the AMD4 enhancements into a single, comprehensive baseline document. 

The value of MISRA C in safety/security-critical applications 
Mature organisations have seen the long-term benefits of MISRA C compliance in their acceptance testing wins and customer satisfaction rates. New entrants are adopting MISRA as a competitive differentiator in highly regulated industries. The benefits of MISRA C also extend to non-critical code, helping to alleviate product issues and security exposures in the field. Whether teams have an external mandate or not, adopting MISRA C:2023 into development processes reduces the likelihood of unpredictable code behaviours. The MISRA C guidelines also help to assess and improve code over time, especially when paired with automated MISRA compliance tools.

Contact Details and Archive...

Print this page | E-mail this page

This website uses cookies primarily for visitor analytics. Certain pages will ask you to fill in contact details to receive additional information. On these pages you have the option of having the site log your details for future visits. Indicating you want the site to remember your details will place a cookie on your device. To view our full cookie policy, please click here. You can also view it at any time by going to our Contact Us page.