﻿# 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\]](https://bit.ly/3o8XHdo)\)\. I'm using rootfs builds and systemd\-nspawn \([snr](https://github.com/mikhailnov/snr)\)\. First let's set up the necessary packages:

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

First with the utility [how\-to\-use\-pvs\-studio\-free](https://github.com/viva64/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:

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

Now we install [PVS\-Studio](https://pvs-studio.com/en/pvs-studio/download/) itself:

```cpp
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:

```cpp
#!/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:

```cpp
#!/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:

```cpp
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_:

```cpp
%__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](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:

```cpp
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\.