Интеграция PVS-Studio в PlatformIO

от автора

Picture 5

Недавно в среде разработки встраиваемых систем PlatformIO появилась поддержка PVS-Studio. В этой статье вы узнаете, как проверить свой код статическим анализатором на примере нескольких открытых проектов.

Что такое PlatformIO?

PlatformIO – это кроссплатформенный инструмент для программирования микроконтроллеров. Ядром PlatformIO является инструмент с интерфейсом командной строки, однако рекомендуется использовать его в виде плагина для Visual Studio Code. Поддерживается большое количество современных чипов и плат на их основе. Умеет автоматически загружать подходящие системы сборки, а на сайте собрана большая коллекция библиотек для управления подключаемыми электронными компонентами. Есть поддержка нескольких статических анализаторов кода, в том числе и PVS-Studio.

Импорт проекта

Для демонстрации возьмем программу управления гексаподом ArduPod на плате Arduino Mega.

Создадим новый проект для подходящей платы и скопируем исходный код:

Picture 2

В папке /arduino/AP_Utils/examples/ находятся несколько примеров программ для настройки и запуска гексапода, воспользуемся servo_test.ino. Программа для Arduino, как правило, создается в виде скетчей в формате INO, который в данном случае не совсем подходит. Для того чтобы сделать из него правильный .cpp файл обычно достаточно поменять расширение имени файла, добавить в начало заголовок #include <Arduino.h>, и убедиться, что функции и глобальные переменные объявлены до обращения к ним.

Picture 3

В процессе сборки могут возникнуть ошибки об отсутствии необходимых сторонних библиотек. Однако PlatformIO поможет найти их в своём репозитории.

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.

По ссылке будут показаны подходящие варианты, а установка зависимости производится одной командой в терминале:

pio lib install "Adafruit PWM Servo Driver Library"

Настройка анализаторов и запуск проверки

Для настройки анализаторов нужно отредактировать конфиг platformio.ini примерно таким образом:

[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

Параметр check_tool указывает, какие анализаторы кода применять, а их настройка производится в параметре check_flags. Более подробные инструкции находятся в документации на официальном сайте: https://docs.platformio.org/en/latest/plus/check-tools/pvs-studio.html

Наконец, можно запустить проверку проекта командой в терминале. Перед первой проверкой среда сама скачает актуальный дистрибутив анализатора.

pio check

Результат проверки программы гексапода

В этот раз целью статьи является демонстрация интеграции PVS-Studio с PlatformIO, а не демонстрация диагностических возможностей анализатора. Однако, раз проект проверен, рассмотрим парочку найденных ошибок, чтобы показать, что проект удалось успешно проанализировать.

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));     ....   }   .... }

Два одинаковых выражения вычитаются одно из другого. Непонятно, каков математический смысл этой разности. Возможно, программист просто не стал сокращать выражение. А возможно, допущена опечатка, и на месте одной из этих 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; } 

Предупреждение указывает на неаккуратное сравнение чисел с плавающей запятой. Из-за невозможности точного представления вещественных чисел конечным количеством бит, безопаснее устанавливать равенство дробных чисел через сравнение их разности с заданным показателем точности. Например, как-то так:

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

Единственным безопасным вариантом прямого сравнения нецелых чисел является присвоение переменным значений констант, и последующее сравнение их значений с этими константами. В данном случае значению переменной value нигде конкретно не присваивается -1. Вот как устроен вызываемый метод AP_Utils::sr04, который и возвращает проверяемое значение:

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;   } }

Как видно, в value запишется результат некоторых вычислений. Присваивания -1 нигде не видно, зато AP_Utils::sr04 может вернуть 0, и это наводит на мысль, что сравнение производится не с тем результатом.

Заключение

В этой статье мы рассмотрели процесс проверки проектов на микроконтроллерах статическим анализатором кода в среде для программирования встраиваемых систем PlatformIO. Напомню, что все желающие опробовать PVS-Studio могут воспользоваться ознакомительным режимом, а для открытых проектов есть возможность получить бесплатную лицензию.

Тем, кто желает узнать о возможностях PVS-Studio более подробно, советую посмотреть следующие статьи:

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Alexey Govorov. PVS-Studio Integration in PlatformIO.

ссылка на оригинал статьи https://habr.com/ru/company/pvs-studio/blog/491218/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *