>
>
Автоматический статический анализ с пом…

Михаил Новоселов
Статей: 1

Автоматический статический анализ с помощью PVS-Studio при сборке RPM-пакетов

Возникла задача автоматизировать статический анализ пакетов в составе дистрибутива. Наилучший инструмент для этого — PVS-Studio, потому что умеет перехватывать вызовы компилятора с помощью strace, таким образом, не требуя никаких изменений в сборочных скриптах. Сначала под наблюдением pvs-studio-analyzer запускается сборка, собирает лог, затем запускается анализатор этого лога и формируется отчет. Рассмотрим, как такое настроить, избежав внесения правок в каждый пакет.

Эта статья впервые была опубликована (на русском языке) на сайте nixtux.ru. Статья размещена в нашем блоге и переведена с разрешения автора.

В качестве операционной системы будем рассматривать rosa2019.1 (dnf + rpm4). Я использую сборки rootfs и systemd-nspawn (snr). Сначала установим необходимые для работы пакеты:

dnf install git-core bash abf basesystem-build how-to-use-pvs-studio-free

С помощью утилиты how-to-use-pvs-studio-free нужно в исходники добавить заголовки PVS-Studio. Эти исходники затем будут отстрипаны от бинарников и попадут в debugsource-подпакеты, которые публикуются в репозиторий. Установим ее из репозитория:

sudo dnf install how-to-use-pvs-studio-free

Ставим саму PVS-Studio:

wget  https://files.viva64.com/pvs-studio-latest.rpm -O pvs-studio-latest.rpm
sudo dnf install pvs-studio-latest.rpm

Теперь суть в следующем. Как известно, RPM превращает секцию спека %prep в shell-скрипт /var/tmp/*.sh и запускает его, аналогично делает с секциями %build и %install. Мы сделаем обертку, которая будет запускать эти скрипты вместо %_buildshell (/bin/sh).

Создаем файл /usr/bin/pvs-prep со следующим текстом:

#!/bin/sh
set -eu
sh "$2"
( cd "$1"
how-to-use-pvs-studio-free -c 2 -m .
)

Этот скрипт будет на стадии %prep добавлять шапку с рекламой PVS-Studio в исходники.

Создаем файл /usr/bin/pvs-builder со следующим текстом:

#!/bin/bash
set -eu
name="$1"
script="$2"
test -f "$script"
[ -n "$2" ]
/usr/bin/pvs-studio-analyzer trace -- /bin/bash -e "$script"
mkdir -p "$HOME/pvs-logs/raw-logs"
pvs-studio-analyzer analyze -o "$HOME/pvs-logs/${name}" 
  -j "$(nproc)" #-C /usr/bin/clang
rm -fr "$HOME/pvs-logs/html-logs/${name}"
mkdir -p "$HOME/pvs-logs/html-logs/${name}"
plog-converter -a GA:1,2 -t fullhtml "$HOME/pvs-logs/${name}" 
  -o "$HOME/pvs-logs/html-logs/${name}"
mv -v "$HOME/pvs-logs/html-logs/${name}/fullhtml"/* 
  "$HOME/pvs-logs/html-logs/${name}/"
rm -fr "$HOME/pvs-logs/html-logs/${name}/fullhtml"

Этот скрипт будет запускать скрипт %build под трассировщиком PVS-Studio, а затем создавать отчет.

Делаем их исполняемыми:

chmod +x /usr/bin/pvs-builder /usr/bin/pvs-prep

Не используем /usr/local/bin, поскольку он не входит в $PATH в RPM.

Теперь в файл /etc/rpm/macros дописываем:

%__spec_prep_cmd /usr/bin/pvs-prep "%{_sourcedir}"
%__spec_build_cmd /usr/bin/pvs-builder %{name}

(см. https://github.com/rpm-software-management/rpm/issues/1399)

И всё. Каждая сборка проекта на C/C++ будет создавать HTML-отчет в папке $HOME/pvs-logs/html-logs/имя_пакета.

Чтобы не мучиться с mock, можно собирать список пакетов так:

cat list_sec_sorted.txt | while read -r line; do pushd $line 
  && dnf builddep --allowerasing -y *.spec 
  && abf rpmbuild ; popd; done

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