SlideShare a Scribd company logo
PVS-Studio and Continuous Integration:
TeamCity. Analysis of the Open
RollerCoaster Tycoon 2 project
Author: Vladislav Stolyarov
Date: 20.07.2020
Tags: DevOps, Cpp
One of the most relevant scenarios for using the PVS-Studio analyzer is its integration into CI systems.
Even though a project analysis by PVS-Studio can already be embedded with just a few commands into
almost any continuous integration system, we continue to make this process even more convenient.
PVS-Studio now supports converting the analyzer output to the TeamCity format-TeamCity Inspections
Type. Let's see how it works.
About the software used
PVS-Studio is a static analyzer of C, C++, C#, and Java code designed to facilitate the task of finding and
correcting various types of errors. The analyzer can be used on Windows, Linux, and macOS. In this
article, we will actively use not only the analyzer itself, but also some utilities from its distribution.
CLMonitor is a monitoring server that performs monitoring of compiler runs. It has to be run
immediately before building a project. In monitoring mode, the server will intercept runs of all
supported compilers. It is worth noting that this utility can only be used for analyzing C/C++ projects.
PlogConverter is a utility for converting the analyzer report into different formats.
About the checked project
Let's try this feature on a practical example by analyzing the OpenRCT2 project.
OpenRCT2 is an open implementation of the RollerCoaster Tycoon 2 (RCT2) game, expanding it with
new features and fixed bugs. The gameplay revolves around the construction and maintenance of an
amusement park that houses rides, stores, and facilities. The player has to try to make profit and
maintain the good reputation of the park, while keeping the guests happy. OpenRCT2 allows you to play
both by following the script and in the sandbox. Scenarios require a player to complete a specific task in
a set time, while the sandbox allows a player to build a more flexible park without any restrictions or
finances.
Configuration
In order to save time, I will probably skip the installation process and start from the point when the
TeamCity server is running on my computer. We need to go to: localhost:{the port specified during
installation}(in my case, localhost:9090) and enter the authorization data. After entering we will get:
Click on Create Project. Next, select Manually and fill in the fields.
After clicking Create, we see the window with settings.
Click Create build configuration.
Fill in the fields and click Create. We see the window suggesting to select a version control system. Since
the sources are already located locally, click Skip.
Finally, we go to the project settings.
We'll add the build steps. To do this, click: Build steps -> Add build step.
Here we choose:
• Runner type -> Command Line
• Run -> Custom Script
Since we will perform analysis during the project compilation, the build and analysis must be one step,
therefore we will fill in the Custom Script field:
We will focus on individual steps later. It is important that loading the analyzer, building the project,
analyzing it, the report output, and formatting it should take only eleven lines of code.
The last thing we need to do is to set environment variables, which, in my case, outline some ways to
improve their readability. To do this, go to: Parameters -> Add new parameter and add three variables:
Just click on Run in the upper-right corner. While the project is being built and analyzed, let me will tell
you about the script.
The script itself
First, we need to download the latest PVS-Studio distribution. To do this, we use the Chocolatey package
manager. For those who want to learn more about this, there is a special article:
choco install pvs-studio -y
Next, run the CLMonitor project build monitoring utility.
%CLmon% monitor –-attach
Then we will build the project. The MSB environment variable represents the path to the MSBuild
version that I need to build.
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
Enter the username and license key for PVS-Studio:
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
After the build is complete, we will run CLMonitor again to generate preprocessed files and perform
static analysis:
%CLmon% analyze -l "c:ptest.plog"
After that, we will use another utility from our distribution. PlogConverter converts a report from
standard to a TeamCity-specific format. This allows us to view it directly in the build window.
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
The last action is to output the formatted report to stdout, where it will be picked up by the TeamCity
parser.
type "C:tempptest.plog_TeamCity.txt"
Full script code:
choco install pvs-studio -y
%CLmon% monitor --attach
set platform=x64
%MSB% %ProjPath% /t:clean
%MSB% %ProjPath% /t:rebuild /p:configuration=release
%MSB% %ProjPath% /t:g2
%MSB% %ProjPath% /t:PublishPortable
%PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
%CLmon% analyze -l "c:ptest.plog"
%PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp"
type "C:tempptest.plog_TeamCity.txt"
In the meantime, the build and analysis of the project has been completed successfully, so we can go to
the Projects tab and make sure of it.
Now click on Inspections Total to view the analyzer report:
Warnings are grouped by diagnostic rule numbers. To navigate along the code, click on the line number
with the warning. Clicking on the question mark in the upper-right corner will open a new tab with
documentation. You can also navigate along the code by clicking on the line number with the analyzer
warning. Navigation from a remote computer is possible when using the SourceTreeRoot marker. Those
who are interested in this mode of the analyzer operation are welcome to read the related
documentation section.
Viewing the analysis results
After we are done with the deployment and configuration of the build, I suggest taking a look at some
interesting warnings found in the reviewed project.
Warning N1
V773 [CWE-401] The exception was thrown without releasing the 'result' pointer. A memory leak is
possible. libopenrct2 ObjectFactory.cpp 443
Object* CreateObjectFromJson(....)
{
Object* result = nullptr;
....
result = CreateObject(entry);
....
if (readContext.WasError())
{
throw std::runtime_error("Object has errors");
}
....
}
Object* CreateObject(const rct_object_entry& entry)
{
Object* result;
switch (entry.GetType())
{
case OBJECT_TYPE_RIDE:
result = new RideObject(entry);
break;
case OBJECT_TYPE_SMALL_SCENERY:
result = new SmallSceneryObject(entry);
break;
case OBJECT_TYPE_LARGE_SCENERY:
result = new LargeSceneryObject(entry);
break;
....
default:
throw std::runtime_error("Invalid object type");
}
return result;
}
The analyzer noticed the error that after dynamic memory allocation in CreateObject, when an
exception occurs, the memory is not cleared, and consequently, a memory leak occurs.
Warning N2
V501 There are identical sub-expressions '(1ULL << WIDX_MONTH_BOX)' to the left and to the right of
the '|' operator. libopenrct2ui Cheats.cpp 487
static uint64_t window_cheats_page_enabled_widgets[] =
{
MAIN_CHEAT_ENABLED_WIDGETS |
(1ULL << WIDX_NO_MONEY) |
(1ULL << WIDX_ADD_SET_MONEY_GROUP) |
(1ULL << WIDX_MONEY_SPINNER) |
(1ULL << WIDX_MONEY_SPINNER_INCREMENT) |
(1ULL << WIDX_MONEY_SPINNER_DECREMENT) |
(1ULL << WIDX_ADD_MONEY) |
(1ULL << WIDX_SET_MONEY) |
(1ULL << WIDX_CLEAR_LOAN) |
(1ULL << WIDX_DATE_SET) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_MONTH_UP) |
(1ULL << WIDX_MONTH_DOWN) |
(1ULL << WIDX_YEAR_BOX) |
(1ULL << WIDX_YEAR_UP) |
(1ULL << WIDX_YEAR_DOWN) |
(1ULL << WIDX_DAY_BOX) |
(1ULL << WIDX_DAY_UP) |
(1ULL << WIDX_DAY_DOWN) |
(1ULL << WIDX_MONTH_BOX) | // <=
(1ULL << WIDX_DATE_GROUP) |
(1ULL << WIDX_DATE_RESET),
....
};
Few, but a static code analyzer would be able to pass this test for attention. It is diligence that this
example of copy paste checks.
Warnings N3
V703 It is odd that the 'flags' field in derived class 'RCT12BannerElement' overwrites field in base class
'RCT12TileElementBase'. Check lines: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570
struct RCT12SpriteBase
{
....
uint8_t flags;
....
};
struct rct1_peep : RCT12SpriteBase
{
....
uint8_t flags;
....
};
Of course, using the same name variable both in the base and derived classes is not always an error.
However, inheritance technology itself assumes that all fields of the parent class are present in the child
class. By declaring a field with the same name in the derived class, we create confusion.
Warning N4
V793 It is odd that the result of the 'imageDirection / 8' statement is a part of the condition. Perhaps,
this statement should have been compared with something else. libopenrct2 ObservationTower.cpp 38
void vehicle_visual_observation_tower(...., int32_t imageDirection, ....)
{
if ((imageDirection / 8) && (imageDirection / 8) != 3)
{
....
}
....
}
Let's look at it in more detail. The imageDirection / 8 expression will be false if imageDirection is in the
range from -7 to 7. Second part: (imageDirection / 8) != 3 checks imageDirection for being outside the
range: from -31 to -24 and from 24 to 31, respectively. It seems rather strange to check numbers for
falling into a certain range in this way, and even if there is no error in this code fragment, I would
recommend rewriting these conditions to more explicit ones. This would significantly simplify the lives
of people who will read and maintain this code afterwards.
Warning N5
V587 An odd sequence of assignments of this kind: A = B; B = A;. Check lines: 1115, 1118. libopenrct2ui
MouseInput.cpp 1118
void process_mouse_over(....)
{
....
switch (window->widgets[widgetId].type)
{
case WWT_VIEWPORT:
ebx = 0;
edi = cursorId; // <=
// Window event WE_UNKNOWN_0E was called here,
// but no windows actually implemented a handler and
// it's not known what it was for
cursorId = edi; // <=
if ((ebx & 0xFF) != 0)
{
set_cursor(cursorId);
return;
}
break;
....
}
....
}
This code fragment was most likely obtained by decompilation. Then, judging by the comment left, a
part of the non-working code was deleted. However, there is still a couple of operations on cursorId that
also don't make much sense.
Warning N6
V1004 [CWE-476] The 'player' pointer was used unsafely after it was verified against nullptr. Check lines:
2085, 2094. libopenrct2 Network.cpp 2094
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player) // <=
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
}
newPlayers.push_back(player->Id); // <=
}
....
}
This code is quite simple to correct - one either needs to check player for a null pointer for the third
time, or add it to the body of the conditional operator. I would suggest the second option:
void Network::ProcessPlayerList()
{
....
auto* player = GetPlayerByID(pendingPlayer.Id);
if (player == nullptr)
{
// Add new player.
player = AddPlayer("", "");
if (player)
{
*player = pendingPlayer;
if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER)
{
_serverConnection->Player = player;
}
newPlayers.push_back(player->Id);
}
}
....
}
Warning N7
V547 [CWE-570] Expression 'name == nullptr' is always false. libopenrct2 ServerList.cpp 102
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
....
}
else
{
....
entry.name = (name == nullptr ? "" : json_string_value(name));
....
}
....
}
You can get rid of a hard-to-read line of code in one fell swoop and solve the problem with checking for
nullptr. I would change the code as follows:
std::optional<ServerListEntry> ServerListEntry::FromJson(...)
{
auto name = json_object_get(server, "name");
.....
if (name == nullptr || version == nullptr)
{
name = ""
....
}
else
{
....
entry.name = json_string_value(name);
....
}
....
}
Warning N8
V1048 [CWE-1164] The 'ColumnHeaderPressedCurrentState' variable was assigned the same value.
libopenrct2ui CustomListView.cpp 510
void CustomListView::MouseUp(....)
{
....
if (!ColumnHeaderPressedCurrentState)
{
ColumnHeaderPressed = std::nullopt;
ColumnHeaderPressedCurrentState = false;
Invalidate();
}
}
The code looks quite strange. I think there was a typo either in the condition or when reassigning the
false value to the ColumnHeaderPressedCurrentStatevariable.
Conclusion
As we can see, it is quite easy to integrate the PVS-Studio static analyzer into your TeamCity project. To
do this, you just need to write one small configuration file. For its part, checking the code will allow you
to detect problems immediately after the build, which will help you fix them when the complexity and
cost of edits are still small.

More Related Content

What's hot (20)

PDF
Top 10 bugs in C++ open source projects, checked in 2016
PVS-Studio
 
PDF
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
PDF
A fresh eye on Oracle VM VirtualBox
PVS-Studio
 
PDF
PVS-Studio advertisement - static analysis of C/C++ code
Andrey Karpov
 
PDF
Errors that static code analysis does not find because it is not used
Andrey Karpov
 
PDF
Reanalyzing the Notepad++ project
PVS-Studio
 
PDF
Checking Notepad++: five years later
PVS-Studio
 
PPTX
PVS-Studio. Static code analyzer. Windows/Linux, C/C++/C#. 2017
Andrey Karpov
 
PDF
Re-checking the ReactOS project - a large report
PVS-Studio
 
PDF
Analysis of bugs in Orchard CMS
PVS-Studio
 
PDF
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
PVS-Studio
 
PDF
Analyzing Wine: One Year Later
PVS-Studio
 
PDF
Picking Mushrooms after Cppcheck
Andrey Karpov
 
PDF
Top 10 C# projects errors found in 2016
PVS-Studio
 
PDF
Source code of WPF samples by Microsoft was checked
PVS-Studio
 
PDF
Linux version of PVS-Studio couldn't help checking CodeLite
PVS-Studio
 
PPTX
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
Andrey Karpov
 
PDF
A Slipshod Check of the Visual C++ 2013 Library (update 3)
Andrey Karpov
 
PDF
The Little Unicorn That Could
PVS-Studio
 
PDF
Of complicacy of programming, or won't C# save us?
PVS-Studio
 
Top 10 bugs in C++ open source projects, checked in 2016
PVS-Studio
 
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
A fresh eye on Oracle VM VirtualBox
PVS-Studio
 
PVS-Studio advertisement - static analysis of C/C++ code
Andrey Karpov
 
Errors that static code analysis does not find because it is not used
Andrey Karpov
 
Reanalyzing the Notepad++ project
PVS-Studio
 
Checking Notepad++: five years later
PVS-Studio
 
PVS-Studio. Static code analyzer. Windows/Linux, C/C++/C#. 2017
Andrey Karpov
 
Re-checking the ReactOS project - a large report
PVS-Studio
 
Analysis of bugs in Orchard CMS
PVS-Studio
 
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
PVS-Studio
 
Analyzing Wine: One Year Later
PVS-Studio
 
Picking Mushrooms after Cppcheck
Andrey Karpov
 
Top 10 C# projects errors found in 2016
PVS-Studio
 
Source code of WPF samples by Microsoft was checked
PVS-Studio
 
Linux version of PVS-Studio couldn't help checking CodeLite
PVS-Studio
 
PVS-Studio 5.00, a solution for developers of modern resource-intensive appl...
Andrey Karpov
 
A Slipshod Check of the Visual C++ 2013 Library (update 3)
Andrey Karpov
 
The Little Unicorn That Could
PVS-Studio
 
Of complicacy of programming, or won't C# save us?
PVS-Studio
 

Similar to PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerCoaster Tycoon 2 project (20)

PDF
A Long-Awaited Check of Unreal Engine 4
Andrey Karpov
 
PDF
PVS-Studio in the Clouds: CircleCI
Andrey Karpov
 
PDF
How the PVS-Studio Team Improved Unreal Engine's Code
PVS-Studio
 
PPT
Introduction to Code Composer Studio 4
Pantech ProLabs India Pvt Ltd
 
PDF
Heading for a Record: Chromium, the 5th Check
PVS-Studio
 
PDF
HPX and PVS-Studio
PVS-Studio
 
PPT
Program development tools
Pantech ProLabs India Pvt Ltd
 
PDF
Checking Bitcoin
Andrey Karpov
 
PDF
Firefox Easily Analyzed by PVS-Studio Standalone
Andrey Karpov
 
PDF
Long-Awaited Check of CryEngine V
PVS-Studio
 
PDF
War of the Machines: PVS-Studio vs. TensorFlow
PVS-Studio
 
DOC
SivaBorra
Siva Borra
 
PDF
Information sheet PVS-Studio
PVS-Studio
 
ODT
Using Open Source Tools For STR7XX Cross Development
Giacomo Antonino Fazio
 
PDF
Checking Oracle VM VirtualBox. Part 1
Andrey Karpov
 
PDF
PVS-Studio in the Clouds: Travis CI
Andrey Karpov
 
PPTX
Effective C++
Andrey Karpov
 
PPTX
Static analysis as means of improving code quality
Andrey Karpov
 
PDF
The Development History of PVS-Studio for Linux
PVS-Studio
 
PDF
Alvaro Denis Resume
Alvaro Denis Acosta Quesada
 
A Long-Awaited Check of Unreal Engine 4
Andrey Karpov
 
PVS-Studio in the Clouds: CircleCI
Andrey Karpov
 
How the PVS-Studio Team Improved Unreal Engine's Code
PVS-Studio
 
Introduction to Code Composer Studio 4
Pantech ProLabs India Pvt Ltd
 
Heading for a Record: Chromium, the 5th Check
PVS-Studio
 
HPX and PVS-Studio
PVS-Studio
 
Program development tools
Pantech ProLabs India Pvt Ltd
 
Checking Bitcoin
Andrey Karpov
 
Firefox Easily Analyzed by PVS-Studio Standalone
Andrey Karpov
 
Long-Awaited Check of CryEngine V
PVS-Studio
 
War of the Machines: PVS-Studio vs. TensorFlow
PVS-Studio
 
SivaBorra
Siva Borra
 
Information sheet PVS-Studio
PVS-Studio
 
Using Open Source Tools For STR7XX Cross Development
Giacomo Antonino Fazio
 
Checking Oracle VM VirtualBox. Part 1
Andrey Karpov
 
PVS-Studio in the Clouds: Travis CI
Andrey Karpov
 
Effective C++
Andrey Karpov
 
Static analysis as means of improving code quality
Andrey Karpov
 
The Development History of PVS-Studio for Linux
PVS-Studio
 
Alvaro Denis Resume
Alvaro Denis Acosta Quesada
 
Ad

More from Andrey Karpov (20)

PDF
60 антипаттернов для С++ программиста
Andrey Karpov
 
PDF
60 terrible tips for a C++ developer
Andrey Karpov
 
PPTX
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Andrey Karpov
 
PDF
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
PDF
PVS-Studio in 2021 - Feature Overview
Andrey Karpov
 
PDF
PVS-Studio в 2021 - Примеры ошибок
Andrey Karpov
 
PDF
PVS-Studio в 2021
Andrey Karpov
 
PPTX
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Andrey Karpov
 
PPTX
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
PPTX
Does static analysis need machine learning?
Andrey Karpov
 
PPTX
Typical errors in code on the example of C++, C#, and Java
Andrey Karpov
 
PPTX
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
Andrey Karpov
 
PPTX
Game Engine Code Quality: Is Everything Really That Bad?
Andrey Karpov
 
PPTX
C++ Code as Seen by a Hypercritical Reviewer
Andrey Karpov
 
PPTX
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
Andrey Karpov
 
PPTX
Static Code Analysis for Projects, Built on Unreal Engine
Andrey Karpov
 
PPTX
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Andrey Karpov
 
PPTX
The Great and Mighty C++
Andrey Karpov
 
PPTX
Static code analysis: what? how? why?
Andrey Karpov
 
PDF
Zero, one, two, Freddy's coming for you
Andrey Karpov
 
60 антипаттернов для С++ программиста
Andrey Karpov
 
60 terrible tips for a C++ developer
Andrey Karpov
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Andrey Karpov
 
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
PVS-Studio in 2021 - Feature Overview
Andrey Karpov
 
PVS-Studio в 2021 - Примеры ошибок
Andrey Karpov
 
PVS-Studio в 2021
Andrey Karpov
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Andrey Karpov
 
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
Does static analysis need machine learning?
Andrey Karpov
 
Typical errors in code on the example of C++, C#, and Java
Andrey Karpov
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
Andrey Karpov
 
Game Engine Code Quality: Is Everything Really That Bad?
Andrey Karpov
 
C++ Code as Seen by a Hypercritical Reviewer
Andrey Karpov
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
Andrey Karpov
 
Static Code Analysis for Projects, Built on Unreal Engine
Andrey Karpov
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Andrey Karpov
 
The Great and Mighty C++
Andrey Karpov
 
Static code analysis: what? how? why?
Andrey Karpov
 
Zero, one, two, Freddy's coming for you
Andrey Karpov
 
Ad

Recently uploaded (20)

PDF
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
PDF
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PDF
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PDF
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
PPTX
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
PDF
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
PDF
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 
PDF
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PPTX
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PPTX
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
PDF
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PPTX
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
PPTX
Homogeneity of Variance Test Options IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PDF
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
PPTX
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
Top Agile Project Management Tools for Teams in 2025
Orangescrum
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
MiniTool Partition Wizard Free Crack + Full Free Download 2025
bashirkhan333g
 
AEM User Group: India Chapter Kickoff Meeting
jennaf3
 
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
Download Canva Pro 2025 PC Crack Full Latest Version
bashirkhan333g
 
Wondershare PDFelement Pro Crack for MacOS New Version Latest 2025
bashirkhan333g
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
Hardware(Central Processing Unit ) CU and ALU
RizwanaKalsoom2
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
Help for Correlations in IBM SPSS Statistics.pptx
Version 1 Analytics
 
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
Agentic Automation Journey Session 1/5: Context Grounding and Autopilot for E...
klpathrudu
 
Homogeneity of Variance Test Options IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
IDM Crack with Internet Download Manager 6.42 Build 43 with Patch Latest 2025
bashirkhan333g
 
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 

PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerCoaster Tycoon 2 project

  • 1. PVS-Studio and Continuous Integration: TeamCity. Analysis of the Open RollerCoaster Tycoon 2 project Author: Vladislav Stolyarov Date: 20.07.2020 Tags: DevOps, Cpp One of the most relevant scenarios for using the PVS-Studio analyzer is its integration into CI systems. Even though a project analysis by PVS-Studio can already be embedded with just a few commands into almost any continuous integration system, we continue to make this process even more convenient. PVS-Studio now supports converting the analyzer output to the TeamCity format-TeamCity Inspections Type. Let's see how it works. About the software used PVS-Studio is a static analyzer of C, C++, C#, and Java code designed to facilitate the task of finding and correcting various types of errors. The analyzer can be used on Windows, Linux, and macOS. In this article, we will actively use not only the analyzer itself, but also some utilities from its distribution. CLMonitor is a monitoring server that performs monitoring of compiler runs. It has to be run immediately before building a project. In monitoring mode, the server will intercept runs of all supported compilers. It is worth noting that this utility can only be used for analyzing C/C++ projects. PlogConverter is a utility for converting the analyzer report into different formats.
  • 2. About the checked project Let's try this feature on a practical example by analyzing the OpenRCT2 project. OpenRCT2 is an open implementation of the RollerCoaster Tycoon 2 (RCT2) game, expanding it with new features and fixed bugs. The gameplay revolves around the construction and maintenance of an amusement park that houses rides, stores, and facilities. The player has to try to make profit and maintain the good reputation of the park, while keeping the guests happy. OpenRCT2 allows you to play both by following the script and in the sandbox. Scenarios require a player to complete a specific task in a set time, while the sandbox allows a player to build a more flexible park without any restrictions or finances. Configuration In order to save time, I will probably skip the installation process and start from the point when the TeamCity server is running on my computer. We need to go to: localhost:{the port specified during installation}(in my case, localhost:9090) and enter the authorization data. After entering we will get:
  • 3. Click on Create Project. Next, select Manually and fill in the fields. After clicking Create, we see the window with settings.
  • 4. Click Create build configuration.
  • 5. Fill in the fields and click Create. We see the window suggesting to select a version control system. Since the sources are already located locally, click Skip.
  • 6. Finally, we go to the project settings.
  • 7. We'll add the build steps. To do this, click: Build steps -> Add build step.
  • 8. Here we choose: • Runner type -> Command Line • Run -> Custom Script Since we will perform analysis during the project compilation, the build and analysis must be one step, therefore we will fill in the Custom Script field:
  • 9. We will focus on individual steps later. It is important that loading the analyzer, building the project, analyzing it, the report output, and formatting it should take only eleven lines of code. The last thing we need to do is to set environment variables, which, in my case, outline some ways to improve their readability. To do this, go to: Parameters -> Add new parameter and add three variables:
  • 10. Just click on Run in the upper-right corner. While the project is being built and analyzed, let me will tell you about the script. The script itself First, we need to download the latest PVS-Studio distribution. To do this, we use the Chocolatey package manager. For those who want to learn more about this, there is a special article: choco install pvs-studio -y Next, run the CLMonitor project build monitoring utility. %CLmon% monitor –-attach Then we will build the project. The MSB environment variable represents the path to the MSBuild version that I need to build. %MSB% %ProjPath% /t:clean %MSB% %ProjPath% /t:rebuild /p:configuration=release %MSB% %ProjPath% /t:g2 %MSB% %ProjPath% /t:PublishPortable Enter the username and license key for PVS-Studio: %PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key%
  • 11. After the build is complete, we will run CLMonitor again to generate preprocessed files and perform static analysis: %CLmon% analyze -l "c:ptest.plog" After that, we will use another utility from our distribution. PlogConverter converts a report from standard to a TeamCity-specific format. This allows us to view it directly in the build window. %PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp" The last action is to output the formatted report to stdout, where it will be picked up by the TeamCity parser. type "C:tempptest.plog_TeamCity.txt" Full script code: choco install pvs-studio -y %CLmon% monitor --attach set platform=x64 %MSB% %ProjPath% /t:clean %MSB% %ProjPath% /t:rebuild /p:configuration=release %MSB% %ProjPath% /t:g2 %MSB% %ProjPath% /t:PublishPortable %PVS-Studio_cmd% credentials --username %PVS_Name% --serialNumber %PVS_Key% %CLmon% analyze -l "c:ptest.plog" %PlogConverter% "c:ptest.plog" --renderTypes=TeamCity -o "C:temp" type "C:tempptest.plog_TeamCity.txt" In the meantime, the build and analysis of the project has been completed successfully, so we can go to the Projects tab and make sure of it.
  • 12. Now click on Inspections Total to view the analyzer report:
  • 13. Warnings are grouped by diagnostic rule numbers. To navigate along the code, click on the line number with the warning. Clicking on the question mark in the upper-right corner will open a new tab with documentation. You can also navigate along the code by clicking on the line number with the analyzer warning. Navigation from a remote computer is possible when using the SourceTreeRoot marker. Those who are interested in this mode of the analyzer operation are welcome to read the related documentation section. Viewing the analysis results After we are done with the deployment and configuration of the build, I suggest taking a look at some interesting warnings found in the reviewed project. Warning N1 V773 [CWE-401] The exception was thrown without releasing the 'result' pointer. A memory leak is possible. libopenrct2 ObjectFactory.cpp 443 Object* CreateObjectFromJson(....) { Object* result = nullptr; .... result = CreateObject(entry); .... if (readContext.WasError()) { throw std::runtime_error("Object has errors");
  • 14. } .... } Object* CreateObject(const rct_object_entry& entry) { Object* result; switch (entry.GetType()) { case OBJECT_TYPE_RIDE: result = new RideObject(entry); break; case OBJECT_TYPE_SMALL_SCENERY: result = new SmallSceneryObject(entry); break; case OBJECT_TYPE_LARGE_SCENERY: result = new LargeSceneryObject(entry); break; .... default: throw std::runtime_error("Invalid object type"); } return result; } The analyzer noticed the error that after dynamic memory allocation in CreateObject, when an exception occurs, the memory is not cleared, and consequently, a memory leak occurs. Warning N2 V501 There are identical sub-expressions '(1ULL << WIDX_MONTH_BOX)' to the left and to the right of the '|' operator. libopenrct2ui Cheats.cpp 487 static uint64_t window_cheats_page_enabled_widgets[] = { MAIN_CHEAT_ENABLED_WIDGETS | (1ULL << WIDX_NO_MONEY) | (1ULL << WIDX_ADD_SET_MONEY_GROUP) | (1ULL << WIDX_MONEY_SPINNER) | (1ULL << WIDX_MONEY_SPINNER_INCREMENT) | (1ULL << WIDX_MONEY_SPINNER_DECREMENT) | (1ULL << WIDX_ADD_MONEY) | (1ULL << WIDX_SET_MONEY) | (1ULL << WIDX_CLEAR_LOAN) | (1ULL << WIDX_DATE_SET) | (1ULL << WIDX_MONTH_BOX) | // <= (1ULL << WIDX_MONTH_UP) | (1ULL << WIDX_MONTH_DOWN) | (1ULL << WIDX_YEAR_BOX) | (1ULL << WIDX_YEAR_UP) | (1ULL << WIDX_YEAR_DOWN) | (1ULL << WIDX_DAY_BOX) | (1ULL << WIDX_DAY_UP) | (1ULL << WIDX_DAY_DOWN) | (1ULL << WIDX_MONTH_BOX) | // <= (1ULL << WIDX_DATE_GROUP) | (1ULL << WIDX_DATE_RESET), .... }; Few, but a static code analyzer would be able to pass this test for attention. It is diligence that this example of copy paste checks.
  • 15. Warnings N3 V703 It is odd that the 'flags' field in derived class 'RCT12BannerElement' overwrites field in base class 'RCT12TileElementBase'. Check lines: RCT12.h:570, RCT12.h:259. libopenrct2 RCT12.h 570 struct RCT12SpriteBase { .... uint8_t flags; .... }; struct rct1_peep : RCT12SpriteBase { .... uint8_t flags; .... }; Of course, using the same name variable both in the base and derived classes is not always an error. However, inheritance technology itself assumes that all fields of the parent class are present in the child class. By declaring a field with the same name in the derived class, we create confusion. Warning N4 V793 It is odd that the result of the 'imageDirection / 8' statement is a part of the condition. Perhaps, this statement should have been compared with something else. libopenrct2 ObservationTower.cpp 38 void vehicle_visual_observation_tower(...., int32_t imageDirection, ....) { if ((imageDirection / 8) && (imageDirection / 8) != 3) { .... } .... } Let's look at it in more detail. The imageDirection / 8 expression will be false if imageDirection is in the range from -7 to 7. Second part: (imageDirection / 8) != 3 checks imageDirection for being outside the range: from -31 to -24 and from 24 to 31, respectively. It seems rather strange to check numbers for falling into a certain range in this way, and even if there is no error in this code fragment, I would recommend rewriting these conditions to more explicit ones. This would significantly simplify the lives of people who will read and maintain this code afterwards. Warning N5 V587 An odd sequence of assignments of this kind: A = B; B = A;. Check lines: 1115, 1118. libopenrct2ui MouseInput.cpp 1118 void process_mouse_over(....) { .... switch (window->widgets[widgetId].type) { case WWT_VIEWPORT: ebx = 0; edi = cursorId; // <= // Window event WE_UNKNOWN_0E was called here, // but no windows actually implemented a handler and // it's not known what it was for cursorId = edi; // <= if ((ebx & 0xFF) != 0) {
  • 16. set_cursor(cursorId); return; } break; .... } .... } This code fragment was most likely obtained by decompilation. Then, judging by the comment left, a part of the non-working code was deleted. However, there is still a couple of operations on cursorId that also don't make much sense. Warning N6 V1004 [CWE-476] The 'player' pointer was used unsafely after it was verified against nullptr. Check lines: 2085, 2094. libopenrct2 Network.cpp 2094 void Network::ProcessPlayerList() { .... auto* player = GetPlayerByID(pendingPlayer.Id); if (player == nullptr) { // Add new player. player = AddPlayer("", ""); if (player) // <= { *player = pendingPlayer; if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER) { _serverConnection->Player = player; } } newPlayers.push_back(player->Id); // <= } .... } This code is quite simple to correct - one either needs to check player for a null pointer for the third time, or add it to the body of the conditional operator. I would suggest the second option: void Network::ProcessPlayerList() { .... auto* player = GetPlayerByID(pendingPlayer.Id); if (player == nullptr) { // Add new player. player = AddPlayer("", ""); if (player) { *player = pendingPlayer; if (player->Flags & NETWORK_PLAYER_FLAG_ISSERVER) { _serverConnection->Player = player; } newPlayers.push_back(player->Id); } } .... } Warning N7
  • 17. V547 [CWE-570] Expression 'name == nullptr' is always false. libopenrct2 ServerList.cpp 102 std::optional<ServerListEntry> ServerListEntry::FromJson(...) { auto name = json_object_get(server, "name"); ..... if (name == nullptr || version == nullptr) { .... } else { .... entry.name = (name == nullptr ? "" : json_string_value(name)); .... } .... } You can get rid of a hard-to-read line of code in one fell swoop and solve the problem with checking for nullptr. I would change the code as follows: std::optional<ServerListEntry> ServerListEntry::FromJson(...) { auto name = json_object_get(server, "name"); ..... if (name == nullptr || version == nullptr) { name = "" .... } else { .... entry.name = json_string_value(name); .... } .... } Warning N8 V1048 [CWE-1164] The 'ColumnHeaderPressedCurrentState' variable was assigned the same value. libopenrct2ui CustomListView.cpp 510 void CustomListView::MouseUp(....) { .... if (!ColumnHeaderPressedCurrentState) { ColumnHeaderPressed = std::nullopt; ColumnHeaderPressedCurrentState = false; Invalidate(); } } The code looks quite strange. I think there was a typo either in the condition or when reassigning the false value to the ColumnHeaderPressedCurrentStatevariable.
  • 18. Conclusion As we can see, it is quite easy to integrate the PVS-Studio static analyzer into your TeamCity project. To do this, you just need to write one small configuration file. For its part, checking the code will allow you to detect problems immediately after the build, which will help you fix them when the complexity and cost of edits are still small.