Хабрахабр

Независимый обзор PVS-Studio (Linux, C++)

И вот что из этого получилось. Увидел публикацию о том, что PVS таки научился анализировать под Линуксами, и решил попробовать на своих проектах.

Содержание

  1. Плюсы
  2. Минусы
  3. Итоги
  4. Послесловие

Отзывчивая поддержка

Я запросил пробный ключ, в тот же день мне его прислали.

Достаточно понятная документация

Справка к консольным командам также имеется (хотя тут есть нарекания, см. Запустить анализатор удалось без особых проблем. раздел Минусы).

Возможность многопоточного анализа

Это сильно экономит время. У анализатора есть "стандартная" опция -j, позволяющая производить анализ параллельно в нескольких задачах.

Хорошая визуализация

Веб-морда удобная, лаконичная, с подсказками рядом со строками в коде и ссылками на описания диагностик. Много разных форматор вывода, от текстового до небольшой веб-морды.

Простая интеграция в сборку

Вся документация есть на их сайте, скажу только, что если ваш проект собирается с помощью CMake, то всё очень просто.

Хорошие описания диагностик

Если генерировать вывод в режиме fullhtml, то у каждого сообщения есть ссылка на описание диагностики, с разъяснениями, примерами кода и дополнительными ссылками.

Незнание анализатором языка C++

К сожалению, PVS иногда ошибается в синтаксисе и генерирует ложноположительные сообщения при совершенно корректном коде.

Например, есть функция, возвращающая void:

template <typename T>
auto copy (const void * source, void * destination) -> std::enable_if_t < std::is_copy_constructible<T>::value >
{ new (destination) T(*static_cast<const T *>(source));
}

Но PVS выдал вот такие сообщения: Да, ключевое слово auto может означать void, на то оно и auto.

dynamic_tuple_management.hpp:29:1: error: V591 Non-void function should return a value.
dynamic_tuple_management.hpp:29:1: error: V2542 Function with a non-void return type should return a value from all exit paths.

Очень тормознутый сайт

Но при нажатии на ссылку ждать приходится достаточно долго, а иногда бывает и 504 Gateway Time-out. Да, в веб-морде рядом с каждым сообщением есть ссылка на соответствующее описание диагностики с примерами.

Язык

Но ссылки из отчёта всегда ведут на английскую версию. Все описания есть на русском, это отлично. В интерфейсе такой возможности я не нашёл. Было бы неплохо иметь возможность переключать язык, чтобы просматривать диагностики можно было сразу на русском.

Неудобно работать с уровнями диагностик через консоль

Начнём с того, что у двух используемых команд (это pvs-studio-analyzer и plog-converter) разные форматы задания диагностик.

Справка к pvs-studio-analyzer гласит:

-a [MODE], --analysis-mode [MODE] MODE defines the type of warnings: 1 - 64-bit errors; 2 - reserved; 4 - General Analysis; 8 - Micro-optimizations; 16 - Customers Specific Requests; 32 - MISRA. Modes can be combined by adding the values Default: 4

Пытался перечислять через запятую: Долго пытался понять, куда же нужно добавлять ("adding the values") ключи.

pvs-studio-analyzer analyze ... -a 1,4,16

Пытался прописывать ключ несколько раз:

pvs-studio-analyzer analyze ... -a 1 -a 4 -a 16

И нужно суммировать, а не добавлять значения. И только потом я догадался, что это же битовые маски! Например, чтобы получить общие диагностики, диагностики по микрооптимизациям и MISRA, нужно их просуммировать (4 + 8 + 32 = 44):

pvs-studio-analyzer analyze ... -a 44

Всё это просуммировать можно было и внутри, а пользователю выставить набор флагов. Использование битовых масок в пользовательских интерфейсах это, как правило, дурной тон.

У неё другие заморочки. Кроме того, есть ещё утилита plog-converter, которая генерирует человекочитаемую информацию о статическом анализе.

Справка к программе plog-converter сообщает:

-a, --analyzer Specifies analyzer(s) and level(s) to be used for filtering, i.e. 'GA:1,2;64:1;OP:1,2,3;CS:1;MISRA:1,2' Default: GA:1,2

Здесь появились какие-то "уровни", которых раньше нигде не было, и в документации я про них тоже ничего не нашёл.

Поэтому я всё выставлял по максимуму. В общем, непонятно.

Куча бестолковой ругани на Catch

И львиная доля сообщений (!!! В двух из трёх проектов, которые я анализировал, используется библиотека модульного тестирования Catch2. 90 из 138 в одном и 297 из 344 в другом !!!) имеют следующий вид:

Catch2

Не учитывает многопоточность

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

Многопоточность

Не знаю. Впрочем, может ли вообще такое учесть статический анализатор?

Правда, стоит иметь в виду, что кое-какие недоработки уже были отловлены и исправлены ранее с помощью Cppcheck и scan-build. PVS не нашёл ни одной настоящей ошибки в моих открытых проектах Burst и Proxima, а также в рабочем проекте, который я, по понятным причинам, предъявить не могу.

В целом впечатление от всех этих анализаторов примерно одинаковое: да, что-то они ловят, иногда даже что-то важное, но в целом компилятора хватает.

Лучше не создавать проблемы, чем героически их преодолевать. Возможно (и лично мне приятно так думать), что наша команда использует такие практики разработки ПО, которые позволяют генерировать минимальное количество говнокода.

Поэтому беру на себя смелость дать несколько советов о том, как писать на языке C++ так, чтобы не отстреливать никому ноги и не огребать граблями по лбу.

Используйте диагностики компилятора по максимуму

Наша команда использует (и вам советует) следующие опции компиляции:

-Werror -Wall
-Wextra
-Wpedantic -Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wenum-compare
-Wfloat-equal
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wredundant-decls
-Wsign-conversion
-Wsign-promo

Включите их в своём проекте, узнаете много нового о своём коде.

Придерживайтесь стандарта

Старайтесь не использовать платформозависимые вещи, если есть стандартные аналоги, а если уж без них совсем не обойтись, заворачивайте их в специальные блоки под макросню (или как-то ещё) и просто не давайте скомпилировать ваш код в неподдерживаемых условиях.

Придерживайтесь стандартной семантики операций

И так далее, и так далее. Сложение должно быть сложением, умножение — умножением, вызов функции — вызовом функции, копирование должно копировать, перенос — переносить, контейнер должен быть итерируем, итератор должен иметь продвижение ++ и разыменование *.

Есть устоявшиеся соглашения, которые не обязательны к исполнению, но которые ожидают увидеть все пользователи и читатели вашего кода. Думаю, мысль понятна. Не старайтесь перехитрить других, а то перехитрите сами себя.

Пишите совместимый код

Очень желательно, чтобы интерфейсы ваших классов и функций могли быть использованы со стандартными и другими библиотеками (например, Бустом). В первую очередь я имею в виду стандартную библиотеку.

За редкими исключениями там вы увидите достойный пример для подражания. Не стесняйтесь подсматривать в интерфейсы STL и Boost.

Используйте по максимуму открытые инструменты

Для того же статического анализа существуют как минимум два открытых бесплатных инструмента, которые на счёт "раз" подключаются к любому проекту с системой сборки CMake.

Подробнее об этом можно почитать в моей недавней публикации.

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

Нужно искать и устранять причину. Это лишь следствие.

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть