Кроссплатформенная проверка C и C++ проектов в PVS-Studio
- Введение
- Активация лицензии
- Подготовка к анализу проекта
- Анализ проекта
- Использование файла конфигурации
- Подавление сообщений анализатора и фильтрация отчёта согласно правилам подавления
- Описание кодов возврата
Введение
PVS-Studio поддерживает проверку кроссплатформенных проектов на C и С++, независимо от используемой сборочной системы. Для проверки таких проектов существует специальная утилита. Она имеет различные названия в зависимости от платформы: для Linux и macOS – pvs-studio-analyzer, для Windows – CompilerCommandsAnalyzer.exe. Все примеры запуска, описанные в этой документации, будут использовать имя pvs-studio-analyzer.
Для проверки проектов Visual Studio следует воспользоваться следующий документацией:
- Работа PVS-Studio в Visual Studio
- Проверка проектов Visual Studio / MSBuild / .NET из командной строки с помощью PVS-Studio
На Windows вы также можете использовать сервер мониторинга компиляции.
Примечание: pvs-studio-analyzer и CompilerCommandsAnalyzer.exe являются одной и той же кроссплатформенной утилитой и имеют незначительные отличия. Платформо-зависимые особенности будут описаны в данном документе. Все примеры запуска pvs-studio-analyzer являются кроссплатформенными, если в описании к ним не говорится обратное.
Активация лицензии
Для работы анализатора необходимо активировать лицензию одним из способов, предложенных в документации.
Если у вас нет лицензии, вы можете запросить её через форму обратной связи.
Подготовка к анализу проекта
Для запуска анализа проекта утилите pvs-studio-analyzer необходимо иметь представление о параметрах запуска компиляции для каждой единицы трансляции. Эти параметры могут быть получены из JSON Compilation Database (compile_commands.json) либо из файла трассировки сборки.
Важно: Для анализа проект должен успешно собираться.
Использование базы данных компиляции (Windows, Linux, macOS)
Многие сборочные системы (CMake, Ninja и др.) позволяют сгенерировать файл compile_commands.json. Для сборочных систем, не предусматривающих получение compile_commands.json напрямую, существуют разные утилиты (Bear, Text Toolkit, intercept-build и др.), позволяющие сгенерировать его.
Процесс генерации JSON Compilation Database и анализа подробно описан здесь.
Создание файла трассировки компиляции (только Linux)
Если у вас нет возможности сгенерировать compile_commands.json для своего проекта, вы можете воспользоваться режимом трассировки компиляции. Данный режим работает только на Linux и использует утилиту strace для перехвата вызовов компилятора.
Примечание: для мониторинга компиляции на Windows следует воспользоваться сервером мониторинга компиляции CLMonitor.
Важно: для трассировки компиляции в системе должен быть установлен strace версии 4.11 или старше, и включён системный вызов PTRACE.
Примечание: во многих дистрибутивах PTRACE включен по умолчанию. Однако, бывают исключения. Для включения PTRACE измените значение параметра kernel.yama.ptrace_scope в файле /etc/sysctl.d/10-ptrace.conf на 1.
Результат трассировки записывается в файл с именем strace_out (по умолчанию) в текущей директории, который впоследствии использует анализатор для получения параметров компиляции. При помощи флага -o можно задать произвольный путь, в который будет записана трассировка.
Перед запуском трассировки убедитесь, что в сборочном каталоге нет артефактов предыдущей сборки. Иначе сборочная система может опустить вызовы компилятора для неизменённых файлов, если она использует инкрементальный режим сборки.
Для запуска трассировки компиляции воспользуйтесь следующей командой:
pvs-studio-analyzer trace [-o <FILE>] -- build_command
build_command – команда, используемая для сборки проекта.
Пример:
pvs-studio-analyzer trace -- cmake build .
Анализ проекта
После формирования JSON Compilation Database или файла трассировки компиляции можно перейти к анализу проекта.
В общем случае для запуска анализа необходимо выполнить команду:
pvs-studio-analyzer analyze [-o /path/to/PVS-Studio.log] \
[-e /path/to/exclude-path]... \
[-j <N>]
Далее будет приведено описание всех флагов запуска анализа.
Описание общих флагов
‑‑cfg [FILE] (-c [FILE]) – задаёт файл конфигурации *.cfg, в который можно поместить некоторые параметры запуска анализатора (например, exclude-path, lic-file и др.). В следующем разделе будет дано описание настроек файла конфигурации. Вы можете использовать файл конфигурации, чтобы вынести туда общие параметры проверки различных проектов.
‑‑lic-file [FILE] (-l [FILE]) – путь до файла с лицензией. Для данного параметра есть соответствующая настройка в файле конфигурации.
‑‑threads [N] (-j [N]) – задаёт число потоков, на которое будет распараллелен анализ.
‑‑output-file [FILE] (-o [FILE]) – имя файла, в который будет записан отчёт анализатора. По умолчанию, если данный флаг не указан, отчёт будет записан в файл PVS-Studio.log в текущей директории. Вы можете задать данный параметр в файле конфигурации (*.cfg).
‑‑exclude-path [DIR] (-e [DIR]) – задаёт путь, по которому следует исключить файлы из анализа. Вы можете задать абсолютный или относительный путь. Также можно использовать шаблоны (glob) для исключения набора файлов. Если есть несколько директорий, которые нужно исключить из проверки, добавьте каждую через данный флаг или пропишите их в файле конфигурации.
‑‑analysis-mode [MODE] (-a [MODE]) – задаёт группу предупреждений, которые будут активированы при анализе вашего проекта.
- 64 – группа диагностик, позволяющих выявлять 64-битные ошибки.
- GA – группа диагностик общего назначения.
- OP – диагностики микро-оптимизаций.
- CS – группа диагностик, добавленных по просьбе пользователей.
- MISRA – группа диагностик, предназначенных для проверки кода на соответствие стандартам MISRA.
- AUTOSAR – группа диагностик, предназначенных для проверки кода на соответствие стандартам AUTOSAR.
- OWASP – группа диагностик, предназначенных для проверки кода на соответствие стандартам OWASP.
Подробнее про MISRA, AUTOSAR и OWASP можно прочитать здесь.
Если вы хотите задать несколько групп предупреждений, то следует разделить их через символ ';' или '+'. Например: 'GA;OP;64' или GA+OP+64. Вы можете не указывать кавычки, если используете в качестве разделителя '+'. Если вы используете в качестве разделителя символ ';', то следует обернуть выражение в кавычки или экранировать каждый символ "точка с запятой", т. к. в командной оболочке он обычно обозначает разделитель команд.
По умолчанию используется группа GA.
Также вы можете задать данный параметр в файле конфигурации (*.cfg).
‑‑sourcetree-root [DIR] (-r [DIR]) – флаг указывает, что в отчёте следует заменить корневую часть пути (DIR) на специальный символ. Таким образом путь до файла с предупреждением анализатора станет относительным. По умолчанию при генерации диагностических сообщений PVS-Studio выдаёт абсолютные пути до файлов, на которые анализатор выдал срабатывания. С помощью данной настройки можно задать корневую часть пути, которую анализатор будет автоматически подменять на специальный маркер. Замена произойдет, если путь до файла начинается с заданной корневой части ([DIR]). В дальнейшем отчёт с относительными путями можно использовать для просмотра результатов анализа в окружении с отличающимся расположением исходных файлов.
‑‑disableLicenseExpirationCheck – флаг устанавливает нулевой код возврата, если срок действия лицензии скоро истечёт. Данный флаг следует использовать, если вы встраиваете анализатор в системы непрерывной интеграции (Travis CI, CircleCI, GitLab CI/CD) или автоматизируете проверку коммитов и Pull Requests и срок действия вашей лицензии скоро закончится (осталось менее 30 дней).
Обратите внимание: если после обновления лицензии забыть убрать этот флаг, то pvs-studio-analyzer заменит возможный нулевой код возврата кодом 6.
‑‑file [FILE] (-f [FILE]) – задаёт путь до файла трассировки компиляции или JSON Compilation Database. По умолчанию, если этот флаг не указан, PVS-Studio ищет файл strace_out или compile_commands.json в текущем каталоге. Следует учесть, что PVS-Studio первым ищет файл compile_commands.json и только потом strace_out. Поэтому если у вас в рабочем каталоге лежат два этих файла, то предпочтение будет отдано первому. Если вы используете JSON Compilation DB, то обязательно указывайте расширение файла '.json', иначе он будет считаться как файл трассировки.
Данный флаг следует задавать, если файл трассировки компиляции или JSON Compilation Database сохранён по нестандартному пути.
‑‑quiet – не отображать процесс анализа.
‑‑preprocessor [NAME] – задаёт тип препроцессора, который анализатор будет ожидать при разборе препроцессированных файлов (*.PVS-Studio.i) Возможные значения:
- visualcpp,
- clang,
- gcc,
- bcc,
- bcc_clang64,
- iar,
- keil5,
- keil5_gnu,
- c6000.
Во время работы препроцессора выполняется раскрытие макросов и подстановка содержимого файлов, включенных через #include, в результирующий препроцессированный файл. Для корректной навигации компилятора и различных утилит (в том числе и PVS-Studio) по такому файлу препроцессор вставляет специальные #line-директивы. Они указывают на файл, содержимое которого было вставлено в данное место.
PVS-Studio нужно знать тип препроцессора для корректной обработки директив #line, специфичных для разных компиляторов.
По умолчанию, если этот флаг не указан, анализатор пытается сам определить тип препроцессора. Однако бывают ситуации, когда анализатор может некорректно определить его. В таком случае препроцессор можно указать явно.
Данный параметр можно задать в файле конфигурации (*.cfg).
‑‑platform [NAME] – флаг позволяет задать целевую платформу, под которую производится компиляция проекта.
Данный флаг ожидает следующие параметры:
- для Windows: win32, x64, Itanium, arm;
- для Linux: linux32, linux64, Itanium, arm;
- для macOS: macOS;
- для Embedded: pic8, tms (Texas instruments).
Информация о платформе нужна анализатору для корректного вывода модели данных.
По умолчанию, если вы не задали этот флаг, PVS-Studio попытается определить платформу на основе параметров запуска компилятора.
Также данный параметр может быть задан в файле конфигурации.
‑‑ignore-ccache – включает анализ всех исходных файлов, независимо от состояния ccache. Если в вашем проекте для ускорения сборки используется обёртка над вызовом компилятора (ccache), то анализ не найдёт файлы компиляции. Этот флаг позволяет опустить вызов ccache и обработать обёрнутую в него команду компилятора.
--incremental (-i) – флаг включает инкрементальный анализ проекта.
‑‑source-files [FILE] (-S [FILE]) – задаёт список исходных файлов для режима проверки списка файлов. Этот список представляет собой текстовый файл, где путь до каждого файла исходного кода расположен на новой строке. Допустимо использовать абсолютные и относительные пути. Относительные пути следует указывать относительно директории, из которой вы хотите запускать анализ.
Такой подход удобно использовать при анализе коммитов и Pull Request'ов.
‑‑regenerate-depend-info [OPTION] – обновляет информацию о зависимостях компиляции для каждого исходного файла. Информация о зависимостях хранится в файле depend_info.json.
Флаг поддерживает следующие режимы:
- run-analysis – обновить информацию о зависимостях и запустить анализ,
- skip-analysis – обновить информацию о зависимостях без запуска анализа.
Файл зависимостей нужен анализатору для корректной проверки списков файлов и для инкрементального анализа. Подробнее об этом можно прочитать здесь.
‑‑suppress-file [FILE] (-s [FILE]) – задаёт путь до файла с подавленными предупреждениями. Предупреждения, попавшие в файл подавления, игнорируются при формировании отчёта анализатора. Подробнее об этом можно узнать тут. По умолчанию файл подавления имеет имя suppress_file.suppress.json.
‑‑analyze-specified-system-paths — включение в анализ файлов из пользовательских системных каталогов, которые указаны через флаги компиляции: isystem, isysroot, system_include_dir и т. д.
--compiler [COMPILER_NAME[=COMPILER_TYPE]] (-C [COMPILER_NAME[=COMPILER_TYPE]]) – позволяет задать имя и тип компилятора. Данный флаг следует использовать, когда PVS-Studio не может распознать вызовы компилятора (при анализе по файлу трассировки) или запускает компилятор с неправильными флагами препроцессирования, так как вычисляет неверный тип компилятора.
COMPILE_NAME используется для фильтрации команд компилятора при разборе файла трассировки (strace_out).
COMPILE_TYPE – задаёт тип компилятора, что позволяет анализатору правильно запустить команду препроцессирования файла. Возможные значения: gcc, clang, keil5, keil5gnu, keil6, tiarmcgt, cl, clangcl, gccarm, iararm_v7_orolder, iararm, qcc, xc8. Если тип компилятора не указан, то анализатор попытаться вывести его по имени или через информацию о версии. А если не сможет, то будет считать его как GCC (на Linux, macOS) или cl (на Windows).
Например, следующая команда указывает анализатору, что в файле strace_out есть неизвестный компилятор и CustomCompiler его следует воспринимать, как GCC:
pvs-studio-analyzer analyzer -f /path/to/strace_out \
-C CustomCompiler=gcc
--env [VAR=VALUE] (-E [VAR=VALUE]) – задаёт переменную окружения, с которой будет производиться препроцессирование.
--rules-config [FILE] (-R [FILE]) – файл конфигурации диагностик (*.pvsconfig). Подробнее о конфигурации диагностик можно узнать здесь.
‑‑intermodular – включает режим межмодульного анализа. В этом режиме анализатор выполняет более глубокий анализ кода, но тратит на это больше времени.
Использование файла конфигурации
Файл конфигурации позволяет задать общие параметры запуска анализатора.
Для проекта можно создать отдельный файл конфигурации, в который следует поместить специфические параметры.
Параметры записываются как пара "ключ=значение". Вы можете использовать символ '#' для комментирования строк.
Возможные значения в конфигурационном файле:
exclude-path — задаёт путь (абсолютный или относительный) до файлов или директорий, которые должны быть исключены из анализа. Относительный путь следует указывать относительно директории, содержащей файл конфигурации. Также можно использовать шаблоны командных оболочек (glob) '?' и '*' для указания пути.
timeout — задаёт время (в секундах), по истечении которого будет прерван анализ единицы трансляции. По умолчанию на анализ одного файла отводится 10 минут (600 секунд). Если передать в качестве значения 0, то ограничение на время будет снято. Однако учтите, что снятие временного ограничения может привести к зависанию анализа.
platform – задаёт используемую платформу. Возможные варианты: win32, x64, Itanium, linux32, linux64, macOS, pic8, tms.
preprocessor — задаёт используемый препроцессор. Возможные варианты: visualcpp, clang, gcc, bcc, bcc_clang64, iar, keil5, keil5_gnu, c6000.
lic-file – задаёт абсолютный или относительный путь до файла лицензии. Путь может быть задан относительно директории, содержащей файл конфигурации.
analysis-mode – задаёт тип выдаваемых предупреждений. Тип представляет собой битовую маску. С помощью "побитового ИЛИ" можно задать несколько групп диагностик, которые будут использованы при анализе.
Возможные значения:
- '0' – полный анализ;
- '1' – 64-битные диагностики;
- '4' – диагностики общего назначения (рекомендуется и используется по умолчанию);
- '8' – диагностики микрооптимизаций;
- '16' – диагностики, реализованные по просьбе пользователей;
- '32' – диагностики на соответствие кода рекомендациям MISRA;
- '64' – диагностики на соответствие кода рекомендациям AUTOSAR;
- '128' – диагностики на соответствие кода рекомендациям OWASP.
output-file – полный или относительный путь к файлу, в который следует записать отчёт работы анализатора. По умолчанию отчёт будет записан в файл 'PVS-Studio.log'. Относительный путь следует указывать относительно каталога, из которого будет произведен запуск анализа. При распараллеливании анализа все процессы ядра PVS-Studio пишут отчёт в один файл. Следовательно, этот файл будет заблокирован пока последний процесс не запишет в него информацию.
funsigned-char — задаёт знаковость типа char. Если true — анализатор трактует char как unsigned char, если false — как знаковый char.
rules-config — задаёт путь до файла конфигурации диагностик (*.pvsconfig). Путь может быть задан относительно директории, содержащей файл конфигурации.
no-noise — позволяет исключить из отчёта все срабатывания 3-го уровня достоверности. Если true — срабатывания с низким уровнем достоверности не попадут в отчёт анализатора. По умолчанию — false.
errors-off — задаёт список деактивированных диагностик. Список задаётся через пробел или запятую: 'V1024 V591' или 'V1024, V591'. Диагностики, перечисленные в этом списке, не будут применены во время анализа.
analyzer-errors — задаёт список активных диагностик. Список может быть задан через пробел или через запятую: 'V1024 V591' или 'V1024, V591'. Во время анализа будут использованы только те диагностики, которые перечислены в этом списке.
Обратите внимание: список деактивированных диагностик, заданный через errors-off, имеет больший приоритет, чем список активированных.
Пример: зададим основные параметры запуска PVS-Studio в файле конфигурации и запустим анализ проекта, предав анализатору наш *.cfg файл.
Файл MyProject.cfg:
lic-file=~/.config/PVS-Studio/PVS-Studio.lic
exclude-path=*/tests/*
exclude-path=*/lib/*
exclude-path=*/third-party/*
platform=linux64
preprocessor=clang
analysis-mode=4
output-file=~/MyProject/MyProject.PVS-Studio.log
Запуск анализа (предполагается, что в текущем каталоге есть strace_out или compile_commands.json):
pvs-studio-analyzer analyze --cfg ./MyProject.cfg ....
Использование файла конфигурации позволяет упростить интеграцию анализатора с системами CI/CD.
Подавление сообщений анализатора и фильтрация отчёта согласно правилам подавления
В PVS-Studio существует механизм подавления предупреждений, который подходит для следующих сценариев:
- при внедрении анализатора в проект, когда PVS-Studio выдаёт большое количество срабатываний на весь код. Все эти срабатывания можно подавить и вернуться к ним, когда на это появится время. В таком случае PVS-Studio будет выдавать срабатывания только на новом коде при регулярных проверках вашего проекта;
- если вы хотите подавить ложные срабатывания анализатора без модификации файлов исходного кода.
Утилита pvs-studio-analyzer позволяет подавить сообщения анализатора и провести фильтрацию отчёта, исключив из него подавленные сообщения.
Создание baseline-уровня сообщений
Для подавления сообщений создаётся специальный файл (по умолчанию имеет имя suppress_file.suppress.json), куда записываются предупреждения анализатора, которые следует игнорировать.
Общий синтаксис запуска режима подавления выглядит следующим образом:
pvs-studio-analyzer suppress [-a <TYPES>] [-f <FILE...>] \
[-v <NUMBER...>] [-o <FILE>] [log]
[log] – путь до отчёта, который был создан анализатором. По умолчанию анализатор будет искать файл PVS-Studio.log в текущем каталоге.
‑‑analyzer [TYPES] (-a [TYPES]) – позволяет указать, предупреждения каких групп диагностик и их уровней достоверности будут перемещены в файл подавления. Параметр принимает строку вида 'Diagnostic group: Diagnostic level [, Diagnostic level]*', где Diagnostic group определяет группу диагностик (возможные группы: GA, 64, OP, CS, MISRA, AUTOSAR, OWASP), а Diagnostic level — уровень достоверности (возможные уровни: 1, 2, 3). Объединение разных групп и их уровней возможно через символ ';' или '+'.
Например: запись вида 'GA:1;OP:1' говорит анализатору, что при подавлении следует использовать только диагностики с первым уровнем достоверности из групп общего назначения и микрооптимизаций. По умолчанию фильтрация идёт по всем группам и уровням.
‑‑file [FILE...] (-f [FILE...]) – позволяет подавить все предупреждения для конкретного файла:
pvs-studio-analyzer suppress -f test.cpp -f test2.cpp /path/to/PVS-Studio.log
или для конкретного файла и строки в нем:
pvs-studio-analyzer suppress -f test.cpp:15 /path/to/PVS=Studio.log
--warning [NUMBER...] (-v[NUMBER...]) – задает номер диагностики, срабатывания которой необходимо подавить из отчета:
pvs-studio-analyzer suppress -v512 -v /path/to/PVS-Studio.log
--output [FILE], (-o[FILE]) – задаёт путь и имя для файла подавления. По умолчанию PVS-Studio записывает всю информацию о подавлении срабатываний в файл suppress_file.suppress.json в текущей директории.
Примечание: флаги ‑‑file, ‑‑warning и ‑‑analyzer можно комбинировать. Например, данная команда подавит все предупреждения V1040 на строке 12:
pvs-studio-analyzer suppress -f test.cpp:12 -v1040 /path/to/PVS-Studio.log
Следующая команда подавляет все диагностики общего назначения 3-его уровня для файла:
pvs-studio-analyzer suppress -f test.cpp -a 'GA:3' /path/to/PVS-Studio.log
Фильтрация отчёта по suppress-файлу
Вы можете отфильтровать предупреждения, которые ранее были помещены в файл подавления, из отчёта анализатора. Для этого следует выполнить команду:
pvs-studio-analyzer filter-suppressed [-o <FILE>] [-s <FILE>] [log]
--output [FILE] (-o [FILE]) – имя файла для записи отфильтрованного отчёта. По умолчанию, если флаг не задан, pvs-studio-analyzer перезапишет существующий файл отчёта.
--suppress-file [FILE] (-s [FILE]) – файл подавления сообщений. По умолчанию pvs-studio-analyzer ищет файл suppress_file.suppress.json в каталоге запуска.
[log] — файл отчёта, из которого следует отфильтровать предупреждения.
Утилита pvs-studio-analyzer всегда ищет файл подавления в режиме анализа для создания фильтрованного отчёта. Если файл имеет нестандартный путь, вы можете указать его через флаг -s:
pvs-studio-analyzer analyze -s /path/to/suppress_file.suppress.json ....
Описание кодов возврата
Утилита может возвращать следующие значения:
0 – анализ прошел успешно;
1 – разнообразные внутренние ошибки. Например, не удалось препроцессировать файл или при разборе файла трассировки произошла ошибка. Как правило, падение c таким кодом сопровождается описанием ошибки в stdout;
2 – срок действия лицензии истекает менее чем через месяц;
3 – во время анализа некоторых файлов произошла внутренняя ошибка;
5 – срок действия вашей лицензии истёк;
6 – утилита была запущена с флагом –disableLicenseExpirationCheck, и ей была передана новая лицензия сроком действия более 30 дней;
7 – ни одна единица компиляции не была принята к анализу. Например, все файлы были исключены из анализа с помощью настроек пользователя или путём маркировки всех каталогов исходного кода как путей к системным заголовкам;
8 – не было обнаружено ни одного вызова компилятора. Например, используется неизвестный компилятор или некорректно сгенерирован файл структуры проекта (strace_out или база данных команд компиляции);
9 – в отчёте не удалось заменить абсолютные пути на относительные. Например, во флаг ‑‑SourceTreeRoot был передан путь, который существует в системе, но не содержится ни в одном предупреждении в отчёте.
В режиме trace, анализатор по умолчанию возвращает тот же код, что получил от запускаемой программы. Если же вы хотите, чтобы анализатор игнорировал настоящий код возврата и всегда возвращал 0, то можете воспользоваться флагом -i или -- ignoreTraceReturnCode. Например:
pvs-studio-analyzer trace -i -- ....