Misra is… well, through many years of mistakes and mistakes the software engineers had been developing a series of recommendations or guidelines about things that should be avoided when developing a program in C for microcontrollers. that is why they create MISRA.
MISRA C is a set of software development guidelines for the C programming language developed by The MISRA Consortium. Its aims are to facilitate code safety, security, portability and reliability in the context of embedded systems, specifically those systems programmed in ISO C / C90 / C99. (wikipedia)
MISRA guidelines are classified as mandatory, required, or advisory. Compliance demands that no “mandatory” guidelines are violated. However, “required” guidelines permit certain violations if there are documented justifications. These deviations are allowed if and only if safety and security are not impacted and there is no acceptable workaround. An example would be third-party custom code that can’t be altered. (synopsys web page)
There are several software that performs what is called static analysis, amount this analysis performs a MISRA check and can give you information when a rule had been violated, some of this well-known software are PC-Lint, QAC, Polyspace, and a long, etc. The problem with this software is they are quite expensive, But there is an open-source alternative good enough to validate the majority of MISRA rules, cppcheck
To install the program type
Linux
$ sudo pacman -S cppcheck
Windows
$ choco install cppcheck
To run cppcheck within the template just type the following make target
$ make lint
mkdir -p Build/checks
cppcheck --addon=misra.json --suppressions-list=.msupress --inline-suppr --quiet --std=c99 --template=gcc --force --platform=unix32 --cppcheck-build-dir=Build/checks app
app/app_ints.c:10:6: warning: A compatible declaration shall be visible when an object or function with external linkage is defined [misra-c2012-8.4]
void NMI_Handler( void )
^
app/app_ints.c:18:6: warning: A compatible declaration shall be visible when an object or function with external linkage is defined [misra-c2012-8.4]
void HardFault_Handler( void )
^
The MISRA rules are defined inside the file .misra and these definitions are used to display the messages when a rule has been violated.
NOTE: cppcheck is not authorized to be shipped with these rules ( neither our template ), and the official documentation needs to be acquire by each user, it is relatively cheap and the lates version can be bought at the following link
The file .misra is empty and once you purchase the rules you can write them. On Apendix A page 196, you will find a summary of all the MISRA rules
Just copy and paste them in the .misra file, ccpcheck will look for this file every time you called with the flag --addon=misra.json
Appendix A Summary of guidelines
The file does not contain those rules are not supported by cppcheck addon
A standard C environment
Rule 1.3 Required
There shall be no occurrence of undefined or critical unspecified behaviour
Unused code
Rule 2.1 Required
A project shall not contain unreachable code
Rule 2.2 Required
There shall be no dead code
Rule 2.3 Advisory
A project should not contain unused type declarations
Rule 2.4 Advisory
A project should not contain unused macro declarations
...
...
Rule suppression
To suppress a MISRA violation message a comment needs to be written next to the line where the violation is with the following syntax cppcheck-suppress misra-c2012-<rule number> ; suppression comment
. The justification comment must be provided to explain why the rule has been suppressed.
volatile static uint32_t Test_Bfx8; /* cppcheck-suppress misra-c2012-8.9 ; the variable is only for testing pourpose */
or
/* cppcheck-suppress misra-c2012-8.9 ; the variable is only for testing pourpose */
volatile static uint32_t Test_Bfx8;
or even multi-line to provide a better explanation of why suppression is applied
/* cppcheck-suppress misra-c2012-8.9 ;
the variable is only for testing pourpose and it wont be included
in the final release code */
volatile static uint32_t Test_Bfx8;
To suppress a rule for an entire file, extra steps need to be performed since cppcheck does not have the possibility to make this global suppress using a code comment. The special file .msupress was created for this purpose, and justification must also be provided for each global suppression or for a set of files.
// cppcheck does not have a suitable way to ignore certain files if a path is not given, niether to
// ignore a specific misra warning in a entire file. This file was created to somehow workaraund
// this issue
// justification: The files belong to a external payed library beyond the scope of this program
misra-c2012-21.1:source/cmsis-stm32g0xx/core/cmsis_gcc.h
misra-c2012-15.7:source/cmsis-stm32g0xx/core/cmsis_gcc.h
Run the MISRA check and clean all the warnings in your project, if some rules need to be avoided, please provide the right justification. Cppcheck is already configured in the makefile, it will only run on folder app/ because the HAL library is provided by a third party and it is supposed to be already MISRA compliance.
Now with cppcheck you can make all your code MISRA compliance, make sure to lint the code every time before compiling. You could achieve this automatically modifying the next line in the makefile (just add the target lint before $(TARGET))
#Instrucciones de compilacion
all : build lint $(TARGET)
From scratch
Ok, but i do not use your template and i wish to run the misra rules in my own projects, don't worry this is the entire guide from scratch. To call cppcheck is as simple as typing, where <options>
are basically flags to decide the things to 'lint”. While the <directory to lint>
is where the actual files to analyze are, can be more than one of course
$ cppcheck <options> <directory to lint>
Cppcheck is not limited to MISRA rule validation and there are several options we need to config, let me show you some of them
- --inline-suppr comments to suppress lint warnings
- --quiet spit only useful information
- --enable=warning, style enable warnings
- --error-exitcode=1 return error code if there are warnings
- --std=c99 check against C99
- --template=gcc display warning gcc style
- --force evaluate all the #if sentences
- --platform=unix32 lint against a unix32 platform, but we are using arm32
- --cppcheck-build-dir=Build/checks set the output directory
- --addon=misra.json validate MISRA rules
- --suppressions-list=.msupress use the file to look for rule suppresion
Since i use makefiles a lot, I always declare a variable to store all the flags, and call cppcheck using a make target
#Linter ccpcheck flags
LNFLAGS = --inline-suppr # comments to suppress lint warnings
LNFLAGS += --quiet # spit only useful information
LNFLAGS += --enable=warning,style # enable warnings
LNFLAGS += --error-exitcode=1 # return error code if there are warnings
LNFLAGS += --std=c99 # check against C11
LNFLAGS += --template=gcc # display warning gcc style
LNFLAGS += --force # evaluate all the #if sentences
LNFLAGS += --platform=unix32 # lint againt a unix32 platform, but we are using arm32
LNFLAGS += --cppcheck-build-dir=Build/checks
#---Run Static analysis
lint :
mkdir -p Build/checks
cppcheck --addon=misra.json --suppressions-list=.msupress $(LNFLAGS) app
One important thing is to create the file misra.json and place there the following code, otherwise cppcheck won’t be able to work with the rules
{
"script": "misra.py",
"args": [
"--rule-texts=.misra"
]
}
To run the validation rules just type
$ make lint