PVS-Studio - Analyzing Pull Requests in Azure DevOps Using Self-Hosted Agents - PVS-Studio Corporate Blog - Habr
PVS-Studio - Analyzing Pull Requests in Azure DevOps Using Self-Hosted Agents - PVS-Studio Corporate Blog - Habr
All streams Development Administrating Design Management Marketing PopSci Log in Sign up
151.42
Rating
PVS-Studio
Static Code Analysis for C, C++, C# and Java
Static code analysis is most effective when changing a project, as errors are always more difficult to fix in the future than at an early
stage. We continue expanding the options for using PVS-Studio in continuous development systems. This time, we'll show you how to
configure pull request analysis using self-hosted agents in Microsoft Azure DevOps, using the example of the Minetest game.
PVS-Studio is a static code analyzer of the code written in C, C++, C#, and Java to search for errors and security defects.
Azure DevOps is a cloud platform that allows you to develop, run applications, and store data on remote servers.
You can use Windows and Linux agent VMs to perform development tasks in Azure. However, running agents on the local equipment
has several important advantages:
The local host may have more resources than an Azure VM;
Ability to directly configure the environment and more flexible management of build processes;
You can complete more than 30 tasks per month for free.
https://habr.com/en/company/pvs-studio/blog/512680/ 1/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
In order for agents to be able to connect to project pools, they need a special Access Token. You can get it on the "Personal Access
Tokens" page, in the "User settings" menu.
After clicking on "New token", you must specify a name and select Read & manage Agent Pools (you may need to expand the full list via
"Show all scopes").
You need to copy the token, because Azure will not show it again, and you will have to make a new one.
A Docker container based on Windows Server Core will be used as the agent. The host is my desktop computer on Windows 10 x64 with
Hyper-V.
First, you will need to expand the amount of disk space available to Docker containers.
https://habr.com/en/company/pvs-studio/blog/512680/ 2/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
{
"registry-mirrors": [],
"insecure-registries": [],
"debug": true,
"experimental": false,
"data-root": "d:\\docker",
"storage-opts": [ "size=40G" ]
}
To create a Docker image for agents with the build system and everything necessary, let's add a Docker file with the following content in
the directory 'D:\docker-agent':
# escape=`
FROM mcr.microsoft.com/dotnet/framework/runtime
https://habr.com/en/company/pvs-studio/blog/512680/ 3/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
USER ContainerAdministrator
RUN reg add hklm\system\currentcontrolset\services\cexecsvc
/v ProcessShutdownTimeoutSeconds /t REG_DWORD /d 60
RUN reg add hklm\system\currentcontrolset\control
/v WaitToKillServiceTimeout /t REG_SZ /d 60000 /f
The result is a build system based on MSBuild for C++, with Chocolatey for installing PVS-Studio, CMake, and Git. Vcpkg is built for
convenient management of the libraries that the project depends on. Also, we have to download the latest version of the Azure
Pipelines Agent.
To initialize the agent from the ENTRYPOINT Docker file, the PowerShell script 'entrypoint.ps1' is called, to which you need to add the
URL of the project's "organization", the token of the agent pool, and the PVS-Studio license parameters:
try
{
C:\BuildTools\VC\Auxiliary\Build\vcvars64.bat
.\agent\config.cmd --unattended `
--url $organization_url `
--auth PAT `
--token $agents_token `
--replace;
.\agent\run.cmd
}
finally
{
# Agent graceful shutdown
# https://github.com/moby/moby/issues/25982
https://habr.com/en/company/pvs-studio/blog/512680/ 4/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
trigger: none
pr:
branches:
include:
https://habr.com/en/company/pvs-studio/blog/512680/ 5/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
- '*'
pool: Default
steps:
- script: git diff --name-only
origin/%SYSTEM_PULLREQUEST_TARGETBRANCH% >
diff-files.txt
displayName: 'Get committed files'
- script: |
cd C:\vcpkg
git pull --rebase origin
CMD /C ".\bootstrap-vcpkg -disableMetrics"
vcpkg install ^
irrlicht zlib curl[winssl] openal-soft libvorbis ^
libogg sqlite3 freetype luajit
vcpkg upgrade --no-dry-run
displayName: 'Manage dependencies (Vcpkg)'
- task: CMake@1
inputs:
cmakeArgs: -A x64
-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake
-DCMAKE_BUILD_TYPE=Release -DENABLE_GETTEXT=0 -DENABLE_CURSES=0 ..
displayName: 'Run CMake'
- task: MSBuild@1
inputs:
solution: '**/*.sln'
msbuildArchitecture: 'x64'
platform: 'x64'
configuration: 'Release'
maximumCpuCount: true
displayName: 'Build'
- script: |
IF EXIST .\PVSTestResults RMDIR /Q/S .\PVSTestResults
md .\PVSTestResults
PVS-Studio_Cmd ^
-t .\build\minetest.sln ^
-S minetest ^
-o .\PVSTestResults\minetest.plog ^
-c Release ^
-p x64 ^
-f diff-files.txt ^
-D C:\caches
PlogConverter ^
-t FullHtml ^
-o .\PVSTestResults\ ^
-a GA:1,2,3;64:1,2,3;OP:1,2,3 ^
.\PVSTestResults\minetest.plog
IF NOT EXIST "$(Build.ArtifactStagingDirectory)" ^
MKDIR "$(Build.ArtifactStagingDirectory)"
powershell -Command ^
"Compress-Archive -Force ^
'.\PVSTestResults\fullhtml' ^
'$(Build.ArtifactStagingDirectory)\fullhtml.zip'"
displayName: 'PVS-Studio analyze'
continueOnError: true
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'psv-studio-analisys'
publishLocation: 'Container'
displayName: 'Publish analysis report'
This script will work when a PR is received and will be executed on the agents assigned to the pool by default. You only need to give it a
https://habr.com/en/company/pvs-studio/blog/512680/ 6/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
The script saves the list of modified files obtained using git diff. Then the dependencies are updated, the project solution is generated
via CMake, and it is built.
If the build was successful, analysis of the changed files is started (the flag '-f diff-files.txt'), ignoring the auxiliary projects created by
CMake (select only the necessary project with the '-S minetest ' flag). To make determining relations between header and source C++
files faster, a special cache is created, which will be stored in a separate directory (the flag '-D C:\caches').
This way we can now get reports on analyzing changes in the project.
https://habr.com/en/company/pvs-studio/blog/512680/ 7/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
As mentioned at the beginning of the article, a nice bonus of using self-hosted agents is a noticeable acceleration of task execution, due
to local storage of intermediate files.
V519 The 'color_name' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 621, 627. string.cpp 627
This function should parse the color name with the transparency parameter (for example, Green#77) and return its code. Depending on
the result of checking the condition, the color_name variable is passed the result of splitting the string or a copy of the function
argument. However, the original argument is then converted to lowercase instead of the resulting string itself. As a result, it can't be
found in the color dictionary if the transparency parameter is present. We can fix this line like this:
color_name = lowercase(color_name);
https://habr.com/en/company/pvs-studio/blog/512680/ 8/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
The nearest_emergefull_d variable doesn't change during the loop operation, and its checking doesn't affect the algorithm execution
progress. Either this is the result of a sloppy copy-paste, or they forgot to perform some calculations with it.
V560 A part of conditional expression is always false: y > max_spawn_y. mapgen_v7.cpp 262
int MapgenV7::getSpawnLevelAtPoint(v2s16 p)
{
....
while (iters > 0 && y <= max_spawn_y) { // <=
if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) {
if (y <= water_level || y > max_spawn_y) // <=
return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point
The value of the 'y' variable is checked before the next iteration of the loop. A subsequent, opposite comparison will always return false
and actually doesn't affect the result of checking the condition.
V595 The 'm_client' pointer was utilized before it was verified against nullptr. Check lines: 183, 187. game.cpp 183
https://habr.com/en/company/pvs-studio/blog/512680/ 9/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
return;
}
Before accessing the m_client pointer, it is checked whether it is null using the assert macro. But this only applies to the debug build. So,
this precautionary measure is replaced with a dummy when building to release, and there is a risk of dereferencing the null pointer.
V616 The '(FT_RENDER_MODE_NORMAL)' named constant with the value of 0 is used in the bitwise operation. CGUITTFont.h 360
FT_RENDER_MODE_MAX
} FT_Render_Mode;
void update_load_flags()
{
// Set up our loading flags.
load_flags = FT_LOAD_DEFAULT | FT_LOAD_RENDER;
if (!useHinting()) load_flags |= FT_LOAD_NO_HINTING;
if (!useAutoHinting()) load_flags |= FT_LOAD_NO_AUTOHINT;
if (useMonochrome()) load_flags |=
FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO | FT_RENDER_MODE_MONO;
else load_flags |= FT_LOAD_TARGET_NORMAL; // <=
}
The FT_LOAD_TARGET_NORMAL macro is deployed to zero, and the bitwise "OR" will not set any flags in load_flags, the else branch can
be removed.
V636 The 'rect.getHeight() / 16' expression was implicitly cast from 'int' type to 'float' type. Consider utilizing an explicit type cast to
avoid the loss of a fractional part. An example: double A = (double)(X) / Y;. hud.cpp 771
void drawItemStack(....)
{
float barheight = rect.getHeight() / 16;
float barpad_x = rect.getWidth() / 16;
float barpad_y = rect.getHeight() / 16;
core::rect<s32> progressrect(
rect.UpperLeftCorner.X + barpad_x,
rect.LowerRightCorner.Y - barpad_y - barheight,
rect.LowerRightCorner.X - barpad_x,
rect.LowerRightCorner.Y - barpad_y);
}
Rect getters return integer values. The result of dividing integer numbers is written to a floating-point variable, and the fractional part
gets lost. It looks like there are mismatched data types in these calculations.
https://habr.com/en/company/pvs-studio/blog/512680/ 10/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. treegen.cpp 413
There are else-if sequences in the tree generation algorithm here. In the middle the next if block is on the same line with the closing
brace of the previous else statement. Perhaps, the code works correctly: before this if statement, blocks of the trunk are created,
followed by leaves. On the other hand, it's possible that else is missed. Only the author can say this for sure.
V668 There is no sense in testing the 'clouds' pointer against null, as the memory was allocated using the 'new' operator. The exception
will be generated in the case of memory allocation error. game.cpp 1367
bool Game::createClient(....)
{
if (m_cache_enable_clouds) {
clouds = new Clouds(smgr, -1, time(0));
if (!clouds) {
*error_message = "Memory allocation error (clouds)";
errorstream << *error_message << std::endl;
return false;
}
}
}
If new can't create an object, an std::bad_alloc exception is thrown, and it must be handled by the try-catch block. A check like this is
useless.
V781 The value of the 'i' index is checked after it was used. Perhaps there is a mistake in program logic. irrString.h 572
https://habr.com/en/company/pvs-studio/blog/512680/ 11/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
// are only equal if they have the same length
return (i == n) || (used == other.used);
}
Array elements are accessed before checking the index, which may lead to an error. Perhaps the author should rewrite the loop like this:
Other errors
This article covers the analysis of pull requests in Azure DevOps and doesn't aim to provide a detailed overview of errors found in the
Minetest project. Only some code fragments that I found interesting are written here. We suggest that the project authors don't follow
this article to correct errors, but perform a more thorough analysis of the warnings that PVS-Studio will issue.
Conclusion
Thanks to its flexible command-line configuration, PVS-Studio analysis can be integrated into a wide variety of CI/CD scenarios. And the
correct use of available resources pays off by increasing productivity.
Note that the pull request checking mode is only available in the Enterprise version of the analyzer. To get a demo Enterprise license,
specify this in the comments when requesting a license on the download page. You can learn more about the difference between
licenses on the Buy PVS-Studio page.
Tags: c++, azure devops, ci, continuous integration, devops, static code analysis, static code analyzer, open source, game development
Hubs: PVS-Studio corporate blog, C++, Microsoft Azure, Build automation, DevOps
PVS-Studio
Static Code Analysis for C, C++, C# and Java
16.0 4.0
Karma Rating
SIMILAR POSTS
Getting Started with the PVS-Studio Static Analyzer for C++ Development under Linux
+21 745 1 0
Errors that static code analysis does not find because it is not used
+20 1.4k 2 0
How to quickly check out interesting warnings given by the PVS-Studio analyzer for C and C++ code?
+22 523 1 0
https://habr.com/en/company/pvs-studio/blog/512680/ 12/13
8/15/2020 PVS-Studio: analyzing pull requests in Azure DevOps using self-hosted agents / PVS-Studio corporate blog / Habr
Comments 0
Only users with full accounts can post comments. Log in, please.
TOP POSTS
Audio over Bluetooth: most detailed information about profiles, codecs, and devices
+22 112k 10 8
Terms of service
https://habr.com/en/company/pvs-studio/blog/512680/ 13/13