Static Analysis for MISRA C#

MISRA C (Motor Industry Software Reliability Association) is a set of guidelines for writing safe, reliable, and maintainable C code, particularly for embedded systems. It is widely used in safety-critical applications such as automotive, aerospace, and medical devices. Below are some important examples of MISRA C rules, organized by categories, along with explanations and examples.

Use of Standard Types#

Rule: Avoid implicit conversions

Rule 10.1: The value of an expression shall not be implicitly converted to a type with a different essential type category.

Example (Non-compliant):

int32_t x = 10;

float y = x; // Implicit conversion from int32_t to float

Compliant:

int32_t x = 10;

float y = (float)x; // Explicit conversion

Avoiding Dangerous Constructs#

Rule: Do not use non-constant variables in constant expressions

Rule 8.7: Functions and objects should not be defined with both extern and static.

Example (Non-compliant):

static int x;

extern static int x; // Invalid declaration

Compliant:

static int x; // Either static…

// OR

extern int x; // … or extern, but not both

Control Flow#

Rule: Ensure predictable control flow

Rule 14.1: There shall be no unreachable code.

Example (Non-compliant):

void example(void) {

return;

int x = 10; // Unreachable code

}

Compliant:

void example(void) {

return;

}

Array and Pointer Usage#

Rule: Avoid pointer arithmetic

Rule 18.4: Pointer arithmetic shall not be used.

Example (Non-compliant):

int arr[10];

int *ptr = arr + 5; // Pointer arithmetic

Compliant:

int arr[10];

int *ptr = &arr[5]; // Use array indexing


Static Analysis-Friendly Code#

Rule: Initialize variables before use

Rule 9.1: All automatic variables shall be initialized before use.

Example (Non-compliant):

int x;

if (x == 0) { // Use of uninitialized variable

// Do something

}

Compliant:

int x = 0;

if (x == 0) {

// Do something

}

Avoiding Undefined Behavior#

Rule: Avoid division by zero

Rule 13.1: A loop counter shall not have a floating-point type.

Example (Non-compliant):

float i = 0.0;

while (i < 10.0) {

i += 0.1; // Floating-point loop counter

}

Compliant:

int i = 0;

while (i < 10) {

i++;

}

Error Handling#

Rule: Always check the return values of functions

Rule 22.2: A function that is declared void shall not return a value.

Example (Non-compliant):

void example(void) {

return 10; // Void function returning a value

}

Compliant:

void example(void) {

// No return value

}

No Overuse of Preprocessor Directives#

Rule: Avoid complex macros

Rule 19.4: Macros shall only expand to a single statement, expression, or do-while loop.

Example (Non-compliant):

#define COMPLEX_MACRO(x) if (x) { doSomething(); } else { doSomethingElse(); }

Compliant:

#define SIMPLE_MACRO(x) (x) ? doSomething() : doSomethingElse()

Avoiding Recursion#

Rule 17.2: Functions shall not call themselves, either directly or indirectly.

Example (Non-compliant):

int factorial(int n) {

if (n <= 1) {

return 1;

}

return n * factorial(n - 1); // Recursive call

}

Compliant:

int factorial(int n) {

int result = 1;

for (int i = 2; i <= n; i++) {

result *= i;

}

return result;

}

Memory Management#

Rule: Avoid dynamic memory allocation

Rule 20.4: Dynamic memory allocation and deallocation functions should not be used.

Example (Non-compliant):

int *ptr = (int *)malloc(sizeof(int)); // Dynamic memory allocation

free(ptr);

Compliant:

int arr[10]; // Use static memory instead of dynamic allocation

Summary of Importance#

Safety: Reduces undefined behavior and system crashes.

Reliability: Ensures deterministic behavior in embedded systems.

Portability: Makes code less dependent on compiler or hardware specifics.

Compliance: Helps meet standards like ISO 26262 and IEC 61508.

Following these examples helps improve code quality and ensures compliance with industry standards, which is crucial in safety-critical embedded applications.