Integration of PVS-Studio in PlatformIO

Picture 5

Recently, in the PlatformIO embedded system development environment, support for PVS-Studio has appeared. In this article, you will learn how to test your code with a static analyzer using an open project as an example.

What is PlatformIO?


PlatformIO is a cross-platform microcontroller programming tool. The core of PlatformIO is a command-line tool, but it is recommended to use it as a plug-in for Visual Studio Code. A large number of modern chips and motherboards based on them are supported. It is able to automatically download suitable assembly systems, and the site has a large collection of libraries for managing plug-in electronic components. There is support for several static code analyzers, including PVS-Studio.

Import project


To demonstrate, let's take the ArduPod hexapod control program on the Arduino Mega board.


Create a new project for a suitable board and copy the source code:

Picture 2

In the folder / arduino / AP_Utils / examples / there are several examples of programs for configuring and running the hexapod, we will use servo_test.ino. The program for Arduino, as a rule, is created in the form of sketches in the INO format, which in this case is not entirely suitable. To make a correct .cpp file out of it, it is usually enough to change the file name extension, add the #include <Arduino.h> header to the beginning , and make sure that functions and global variables are declared before accessing them.

Picture 3

During the assembly process, errors may occur about the lack of required third-party libraries. However, PlatformIO will help you find them in your repository.

In file included from src\servo_test.cpp:20:0:
src/AP_Utils.h:10:37: fatal error: Adafruit_PWMServoDriver.h:
No such file or directory
*******************************************************************************
* Looking for Adafruit_PWMServoDriver.h dependency? Check our library registry!
*
* CLI> platformio lib search "header:Adafruit_PWMServoDriver.h"
* Web> https://platformio.org/lib/search?query=header:Adafruit_PWMServoDriver.h
*
*******************************************************************************
compilation terminated.

The link will show the appropriate options, and the installation of the dependency is done with one command in the terminal:

pio lib install "Adafruit PWM Servo Driver Library"

Configuring analyzers and starting a test


To configure the analyzers, you need to edit the platformio.ini config like this:

[env:megaatmega2560]
platform = atmelavr
board = megaatmega2560
framework = arduino
check_tool = pvs-studio
check_flags =
  pvs-studio:
    --analysis-mode=4 ; General analysis mode. Set to 32 for MISRA
    --exclude-path=/.pio/libdeps ; Ignore dependency libraries

The check_tool parameter indicates which code analyzers to use, and their configuration is done in the check_flags parameter . More detailed instructions can be found in the documentation on the official website: https://docs.platformio.org/en/latest/plus/check-tools/pvs-studio.html

Finally, you can start checking the project with a command in the terminal. Before the first test, the environment itself downloads the current analyzer distribution.

pio check

The result of checking the hexapod program


This time, the goal of the article is to demonstrate the integration of PVS-Studio with PlatformIO, and not to demonstrate the diagnostic capabilities of the analyzer. However, once the project has been verified, consider a couple of errors found to show that the project was successfully analyzed.

V519 There are identical sub-expressions to the left and to the right of the '-' operator: pow (t, 2) - pow (t, 2). AP_Utils.cpp 176

pointLeg* AP_Utils::traceLeg(uint8_t leg, float phi, float z,
  int resolution, uint8_t shape) {
  ....
  if(shape == ELLIPTIC) {
    ....
    float v = sqrt(pow(phi - legs[leg].phi, 2) + pow(z - legs[leg].z, 2));
    float u = sqrt(pow(phi - phi0, 2) + pow(z - z0, 2));
    float t = sqrt(pow(phi0 - legs[leg].phi, 2) + pow(z0 - legs[leg].z, 2));
    theta = acos((pow(t, 2) - pow(t, 2) - pow(v, 2))/(-2.0*t*u));
    ....
  }
  ....
}

Two identical expressions are subtracted from one another. It is unclear what the mathematical meaning of this difference is. Perhaps the programmer simply did not reduce the expression. Or perhaps a typo is allowed, and another argument must be in place of one of these t .

V550 An odd precise comparison: value! = - 1. It's probably better to use a comparison with defined precision: fabs (A - B)> Epsilon. AP_Utils.cpp 574

float AP_Utils::sr04_average(uint8_t trig, uint8_t echo,
  int unit, int samples, int time) {
  ....
  float average, pause, value;
  ....
  for(int i=0; i<samples; i++) {
    value = sr04(trig, echo, unit);
    if(value != -1) { // <=
      total += value;
      delay(pause);
    } else {
      i--;
    }
  }
  average = total/samples;
  ....
  return average;
}

A warning indicates an inaccurate comparison of floating point numbers. Due to the impossibility of accurate representation of real numbers by a finite number of bits, it is safer to establish the equality of fractional numbers by comparing their difference with a given accuracy index. For example, something like this:

bool is_equal(double x, double y) {
  return std::fabs(x - y) < 0.001f;
}

The only safe option to directly compare non-integer numbers is to assign constants to the variables, and then compare their values ​​with these constants. In this case, the value of the variable value anywhere not specifically assigned -1. This is how the called AP_Utils :: sr04 method works , which returns the checked value:

float AP_Utils::sr04(uint8_t trig, uint8_t echo, int unit) {
  ....
  float duration, distance;
  ....
  duration = pulseIn(echo, HIGH);
  distance = (346.3*duration*0.000001*unit)/2; // <=
  
  if((distance >= 0.02*unit) && (distance <= 4*unit)) {
    ....
    return(distance);
  } else {
    ....
    return 0;
  }
}

As you can see, the value is written the result of some calculations. Assignment -1 is nowhere to be seen, but AP_Utils :: sr04 can return 0, and this suggests that the comparison is not made with the result.

Conclusion


In this article, we examined the process of checking projects on microcontrollers with a static code analyzer in the programming environment for embedded PlatformIO systems. Let me remind you that everyone who wants to try PVS-Studio can use the trial mode , and for open projects there is an opportunity to get a free license .

For those who want to learn more about PVS-Studio features in more detail, I advise you to look at the following articles:




If you want to share this article with an English-speaking audience, then please use the link to the translation: Alexey Govorov. PVS-Studio Integration in PlatformIO .

All Articles