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

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

В процессе сборки могут возникнуть ошибки об отсутствии необходимых сторонних библиотек. Однако 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 более подробно, советую посмотреть следующие статьи:
- Причины внедрить в процесс разработки статический анализатор кода PVS-Studio
- Знакомство со статическим анализатором кода PVS-Studio на Windows
- Почему embedded-разработчикам следует использовать статический анализ кода
- PVS-Studio: поддержка стандартов кодирования MISRA C и MISRA C++

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Alexey Govorov. PVS-Studio Integration in PlatformIO.
ссылка на оригинал статьи https://habr.com/ru/company/pvs-studio/blog/491218/
Добавить комментарий