>
>
Automatic static analysis using PVS-Stu…

Mikhail Novoselov
Articles: 1

Automatic static analysis using PVS-Studio when building RPM packages

There was a task to automate static analysis packages included in the distribution. The best tool for this is PVS-Studio, as it can catch compiler calls using strace, thus not requiring any changes in the build scripts. First, controled by pvs-studio-analyzer the build was started, and the log was collected. Then the log was analyzed resulting in the report. Let's look at how to set this up without making edits to each package.

The article was first posted [RU] in Russian at nixtux.ru. The article is now posted in our blog and translated with the author's permission.

As an operating system, we will consider rosa2019. 1 (dnf + rpm4 [RU]). I'm using rootfs builds and systemd-nspawn (snr). First let's set up the necessary packages:

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

First with the utility how-to-use-pvs-studio-free I have to add PVS-Studio headers to the source code. These sources will be stripped from the binaries and placed in debugsource sub-packages that are published in the repository. Let's install the utility from the repository:

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

Now we install PVS-Studio itself:

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

Here's the main point. As we know, RPM turns the %prep spec section into a shell script /var/tmp/*.sh and runs it, as it does with the %build and %install sections. We will make a wrapper that will run these scripts instead of %_buildshell (/bin/sh).

Next, we create the file /usr/bin/pvs-prep with the following text:

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

This script will add the header with the PVS-Studio ad to the source code at the %prep stage.

Now we create the file /usr/bin/pvs-builder with this text:

#!/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"

This script will run the %build script under the PVS-Studio tracer, and then create a report.

Now we make them executable:

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

Don't use /usr/local/bin, because it is not included in $PATH in RPM.

Now we append the following in the file /etc/rpm/macros:

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

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

And that's it. Each C/C++ project build will create an HTML report in the folder $HOME/pvs-logs/html-logs/package_name.

To avoid issues with mock, we can build a list of packages like this:

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

This will help us install build dependencies in the same system but allow deleting unnecessary packages if the installed dependencies of the current package conflict with the dependencies of one of the previous packages.