SlideShare a Scribd company logo
Static Code Analysis for Projects,
Built on Unreal Engine
Ilya Gainulin
PVS-Studio
gainulin@viva64.com
I Am Looking for Errors in Your Code
2
Results of Incorrect Type Casing
in the ShareX Project
3
Results of Incorrect Type Casing
in the ShareX Project
Incorrect code:
float pixelWeight = color.Alpha / 255;
Fixed code:
float pixelWeight = (float)color.Alpha / 255;
4
type Byte
Collaboration with Epic Games
5
What Is Static Analysis?
Static analysis is a way to check a program’s code without executing the
program.
6
Why Do You Need Static Analysis?
• Detect errors early in the program development process.
• Get recommendations on code formatting.
• Check your spelling.
• Calculate various software metrics
7
Cost to Fix a Bug
Fix earlier,
save money!
8
Why Do You Need Static Analysis?
• Detect errors early in the program development process.
• Get recommendations on code formatting.
• Check your spelling.
• Calculate various software metrics
9
Static Analysis Advantages?
• Detecting potential problems in code early
• Full code coverage
• Easy to use
10
Static Analysis Advantages
11
Static Analysis Advantages
12
Static Analysis Advantages
13
Mono
V3012 The '?:' operator, regardless of its conditional expression, always
returns one and the same value: Color.FromArgb (150, 179, 225).
ProfessionalColorTable.cs 258
Static Analysis Disadvantages
• Unavoidable false positives
• Static analysis is usually not as good at detecting
memory leaks and parallel errors
14
Static Analysis Disadvantages
void OutstandingIssue(const char *strCount)
{
unsigned nCount;
sscanf_s(strCount, "%u", &nCount);
int array[10];
memset(array, 0, nCount * sizeof(int));
}
15
Static Analyzers Are Not Isolated Tools and Rare
Checks – They Are a Part of DevOps
16
Написание кода Компиляция Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Commit кода
Static Analyzers Are Not Isolated Tools and Rare
Checks – They Are a Part of DevOps
17
Написание кода Компиляция
Полный статический
анализ на билд
сервере
Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Commit кода
Static Analyzers Are Not Isolated Tools and Rare
Checks – They Are a Part of DevOps
18
Static Analyzers Are Not Isolated Tools and Rare
Checks – They Are a Part of DevOps
Написание кода Компиляция
Полный статический
анализ на билд
сервере
Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Инкрементальный
статический анализ
на машине
разработчика
Commit кода
19
Incremental Analysis
• A decrease in analysis time, because only fixed or new code is
processed.
• Works well for early error detection.
20
Ways to Use Static Analysis in a UE Project
• Tracking compiler runs.
• Direct integration with the build system.
21
22
Invoking CL.exe
compiler
MSBuild
Unreal Build
Tool
Building Unreal Engine
projects
Build finished
Gathering
information
The Simplest Way to Check a UE Project: Catch All Compiler Calls
Tracking Compiler Runs from a GUI Application
23
Tracking Compiler Runs from a GUI Application
24
Tracking Compiler Runs from a GUI Application
25
Direct Integration into Build System and VS
• Run analysis directly from the Visual Studio IDE.
• Run the analysis automatically when building a UE project.
• Run incremental analysis.
26
Common assembly scenario of a C++ project in VS
27
Common assembly scenario of a C++ project in VS
28
Particularities of Building a UE Project
• Instead of Visual Studio’s standard build system, the UnrealBuildTool
(UBT) is used.
• Project files have the .uproject extension.
29
Particularities of Building a UE Project
30
What’s the Problem?
• The project file may not contain paths to source files that need to be
checked.
• Not all compilation options required for correct preprocessing are
present.
31
What’s the Solution?
• Write your own toolchain for the build system, so as to embed the
static analyzer launch into UBT.
• Pass a parameter to the UBT build system. That parameter would
demonstrate the need for analysis.
32
What’s the Solution?
33
Some of the Current toolchain’s Limitations
• Only builds a project or only analyzes the project.
• No .cpp file analysis, if an included .h file has been changed.
34
The Project Analysis After Its Build
• Modifying the Build.bat and Rebuild.bat scripts.
35
The Project Analysis After Its Build
36
The Project Analysis After Its Build
37
The .cpp File Analysis in Scenarios with the
Connected Modified .h File
• Remove and restore the cache file UBT uses.
38
The .cpp File Analysis in Scenarios with the
Connected Modified .h File
39
Errors in Unreal Engine Code
static bool PositionIsInside(....)
{
return
Position.X >= Control.Center.X - BoxSize.X * 0.5f &&
Position.X <= Control.Center.X + BoxSize.X * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f;
}
40
Errors in Unreal Engine Code
static bool PositionIsInside(....)
{
return
Position.X >= Control.Center.X - BoxSize.X * 0.5f &&
Position.X <= Control.Center.X + BoxSize.X * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f;
}
PVS-Studio warns: V501 There are identical sub-expressions 'Position.Y >=
Control.Center.Y — BoxSize.Y * 0.5f' to the left and to the right of the '&&'
operator. svirtualjoystick.cpp 97
41
Errors in Unreal Engine Code
static bool PositionIsInside(....)
{
return
Position.X >= Control.Center.X - BoxSize.X * 0.5f &&
Position.X <= Control.Center.X + BoxSize.X * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f &&
Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f;
Position.Y <= Control.Center.Y + BoxSize.Y * 0.5f;
}
PVS-Studio warns: V501 There are identical sub-expressions 'Position.Y >=
Control.Center.Y — BoxSize.Y * 0.5f' to the left and to the right of the '&&'
operator. svirtualjoystick.cpp 97
42
enum ECubeFace;
ECubeFace CubeFace;
friend FArchive& operator<<(FArchive& Ar, FResolveParams&
ResolveParams)
{
....
if(Ar.IsLoading())
{
ResolveParams.CubeFace = (ECubeFace)ResolveParams.CubeFace;
}
....
}
43
enum ECubeFace;
ECubeFace CubeFace;
friend FArchive& operator<<(FArchive& Ar, FResolveParams&
ResolveParams)
{
....
if(Ar.IsLoading())
{
ResolveParams.CubeFace = (ECubeFace)ResolveParams.CubeFace;
}
....
}
PVS-Studio warns: V570 The 'ResolveParams.CubeFace' variable is assigned to itself.
rhi.h 1279
44
bool VertInfluencedByActiveBone(
FParticleEmitterInstance* Owner, USkeletalMeshComponent* InSkelMeshComponent,
int32 InVertexIndex, int32* OutBoneIndex = NULL);
void UParticleModuleLocationSkelVertSurface::Spawn(....)
{
int32 BoneIndex1, BoneIndex2, BoneIndex3;
BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE;
if(!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[0], &BoneIndex1) &&
!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[1], &BoneIndex2) &&
!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[2]) &BoneIndex3)
{
....
}
45
bool VertInfluencedByActiveBone(
FParticleEmitterInstance* Owner, USkeletalMeshComponent* InSkelMeshComponent,
int32 InVertexIndex, int32* OutBoneIndex = NULL);
void UParticleModuleLocationSkelVertSurface::Spawn(....)
{
int32 BoneIndex1, BoneIndex2, BoneIndex3;
BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE;
if(!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[0], &BoneIndex1) &&
!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[1], &BoneIndex2) &&
!VertInfluencedByActiveBone(
Owner, SourceComponent, VertIndex[2]) &BoneIndex3)
{
....
}
46
The Analyzer’s Warning About a Sneaky Error
PVS-Studio warns: V564 The '&' operator is applied to bool type value.
You've probably forgotten to include parentheses or intended to use the
'&&' operator. particlemodules_location.cpp 2120
47
void GetRenderData(....)
{
....
FT_Bitmap* Bitmap = nullptr;
if( Slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO )
{
FT_Bitmap NewBitmap;
....
Bitmap = &NewBitmap;
}
....
OutRenderData.RawPixels.AddUninitialized(
Bitmap->rows * Bitmap->width );
....
}
48
void GetRenderData(....)
{
....
FT_Bitmap* Bitmap = nullptr;
if( Slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO )
{
FT_Bitmap NewBitmap;
....
Bitmap = &NewBitmap;
}
....
OutRenderData.RawPixels.AddUninitialized(
Bitmap->rows * Bitmap->width );
....
}
49
PVS-Studio: V506 Pointer to local variable
'NewBitmap' is stored outside the scope of this
variable. Such a pointer will become invalid.
fontcache.cpp 466
void UGameplayStatics::DeactivateReverbEffect(....)
{
if (GEngine || !GEngine->UseSound())
{
return;
}
UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....);
....
}
50
void UGameplayStatics::DeactivateReverbEffect(....)
{
if (GEngine || !GEngine->UseSound())
{
return;
}
UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....);
....
}
PVS-Studio: V522 Dereferencing of the null pointer 'GEngine' might take place. Check the
logical condition. gameplaystatics.cpp 988
51
void UGameplayStatics::DeactivateReverbEffect(....)
{
if (GEngine || !GEngine->UseSound())
if (GEngine == nullptr || !GEngine->UseSound())
{
return;
}
UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....);
....
}
PVS-Studio: V522 Dereferencing of the null pointer 'GEngine' might take place. Check the
logical condition. gameplaystatics.cpp 988
52
template< typename DefinitionType >
FORCENOINLINE void Set(....)
{
....
if ( DefinitionPtr == NULL )
{
WidgetStyleValues.Add( PropertyName,
MakeShareable( new DefinitionType( InStyleDefintion ) ) );
}
else
{
WidgetStyleValues.Add( PropertyName,
MakeShareable( new DefinitionType( InStyleDefintion ) ) );
}
}
53
template< typename DefinitionType >
FORCENOINLINE void Set(....)
{
....
if ( DefinitionPtr == NULL )
{
WidgetStyleValues.Add( PropertyName,
MakeShareable( new DefinitionType( InStyleDefintion ) ) );
}
else
{
WidgetStyleValues.Add( PropertyName,
MakeShareable( new DefinitionType( InStyleDefintion ) ) );
}
}
54
PVS-Studio: V523 The 'then' statement is
equivalent to the 'else' statement. paths.cpp
703
Conclusion
• Static analysis of UE projects is not too complicated.
• Combine static analysis with other testing methods.
55
Thank You for Your Attention
56

More Related Content

PPTX
Ue4 bone controller
PPTX
комп’ютерні програми і мови програмування
PPTX
脱! 俺たちは雰囲気でBPをいじっている
PPT
редагування даних таблиці 7 клас
PDF
UE4におけるエフェクトの為のエンジン改造事例
PDF
UE4のローカライズ機能紹介 (UE4 Localization Deep Dive)
PDF
.NET Framework におけるタイムゾーンの取り扱い
Ue4 bone controller
комп’ютерні програми і мови програмування
脱! 俺たちは雰囲気でBPをいじっている
редагування даних таблиці 7 клас
UE4におけるエフェクトの為のエンジン改造事例
UE4のローカライズ機能紹介 (UE4 Localization Deep Dive)
.NET Framework におけるタイムゾーンの取り扱い

What's hot (20)

PPTX
UE4におけるLoadingとGCのProfilingと最適化手法
PDF
徹底解説!UE4を使ったモバイルゲーム開発におけるコンテンツアップデートの極意!
PDF
UE4 Performance and Profiling | Unreal Dev Day Montreal 2017 (日本語訳)
PDF
新しくなったモノビットエンジンを使って10万人規模のサーバを構築するノウハウを公開!2017年10月27日モノビットエンジン勉強会
PDF
猫でも分かるUE4.22から入ったSubsystem
PDF
Comics masha and the internet
PPT
ゴルフゲームでUnityの限界を突破する方法
PDF
GPU最適化入門
PDF
セガサターンマシン語プログラミングの紹介
PDF
【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計
PDF
Н. В. Морзе, 9 клас Підручник з інформатики
PDF
実行速度の最適化のあれこれ プラス おまけ
PDF
HCL Domino エージェントとトラブルシューティング
PPTX
UE4のためのより良いゲーム設計を理解しよう!
PPTX
MipMap(밉맵)
PDF
そう、UE4ならね。あなたのモバイルゲームをより快適にする沢山の冴えたやり方について Part 2 <Texture Streaming, メモリプロ...
PDF
UE4におけるエフェクトの基本戦略事例 後半
PDF
ARでVRアバターを表示するシステムを構築しよう
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
UE4におけるLoadingとGCのProfilingと最適化手法
徹底解説!UE4を使ったモバイルゲーム開発におけるコンテンツアップデートの極意!
UE4 Performance and Profiling | Unreal Dev Day Montreal 2017 (日本語訳)
新しくなったモノビットエンジンを使って10万人規模のサーバを構築するノウハウを公開!2017年10月27日モノビットエンジン勉強会
猫でも分かるUE4.22から入ったSubsystem
Comics masha and the internet
ゴルフゲームでUnityの限界を突破する方法
GPU最適化入門
セガサターンマシン語プログラミングの紹介
【Unite 2018 Tokyo】60fpsのその先へ!スマホの物量限界に挑んだSTG「アカとブルー」の開発設計
Н. В. Морзе, 9 клас Підручник з інформатики
実行速度の最適化のあれこれ プラス おまけ
HCL Domino エージェントとトラブルシューティング
UE4のためのより良いゲーム設計を理解しよう!
MipMap(밉맵)
そう、UE4ならね。あなたのモバイルゲームをより快適にする沢山の冴えたやり方について Part 2 <Texture Streaming, メモリプロ...
UE4におけるエフェクトの基本戦略事例 後半
ARでVRアバターを表示するシステムを構築しよう
【Unite Tokyo 2019】Understanding C# Struct All Things
Ad

Similar to Static Code Analysis for Projects, Built on Unreal Engine (20)

PDF
A Long-Awaited Check of Unreal Engine 4
PPTX
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
PDF
How the PVS-Studio analyzer began to find even more errors in Unity projects
PPTX
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
PDF
How the PVS-Studio Team Improved Unreal Engine's Code
PPTX
Game Engine Code Quality: Is Everything Really That Bad?
PDF
Long-Awaited Check of CryEngine V
PDF
Critical errors in CryEngine V code
PDF
Discussing Errors in Unity3D's Open-Source Components
PDF
Handling False Positives in PVS-Studio and CppCat
PDF
Static analysis as part of the development process in Unreal Engine
PDF
Searching for bugs in Mono: there are hundreds of them!
PDF
ChakraCore: analysis of JavaScript-engine for Microsoft Edge
PDF
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
PDF
Brief analysis of Media Portal 2 bugs
PDF
Analyzing the Blender project with PVS-Studio
PPTX
PVS-Studio in 2019
PDF
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
PDF
Sony C#/.NET component set analysis
PDF
How to Improve Visual C++ 2017 Libraries Using PVS-Studio
A Long-Awaited Check of Unreal Engine 4
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How the PVS-Studio analyzer began to find even more errors in Unity projects
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
How the PVS-Studio Team Improved Unreal Engine's Code
Game Engine Code Quality: Is Everything Really That Bad?
Long-Awaited Check of CryEngine V
Critical errors in CryEngine V code
Discussing Errors in Unity3D's Open-Source Components
Handling False Positives in PVS-Studio and CppCat
Static analysis as part of the development process in Unreal Engine
Searching for bugs in Mono: there are hundreds of them!
ChakraCore: analysis of JavaScript-engine for Microsoft Edge
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
Brief analysis of Media Portal 2 bugs
Analyzing the Blender project with PVS-Studio
PVS-Studio in 2019
Serious Sam shooter anniversary - finding bugs in the code of the Serious Eng...
Sony C#/.NET component set analysis
How to Improve Visual C++ 2017 Libraries Using PVS-Studio
Ad

More from Andrey Karpov (20)

PDF
60 антипаттернов для С++ программиста
PDF
60 terrible tips for a C++ developer
PPTX
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
PDF
PVS-Studio in 2021 - Error Examples
PDF
PVS-Studio in 2021 - Feature Overview
PDF
PVS-Studio в 2021 - Примеры ошибок
PDF
PVS-Studio в 2021
PPTX
Best Bugs from Games: Fellow Programmers' Mistakes
PPTX
Does static analysis need machine learning?
PPTX
Typical errors in code on the example of C++, C#, and Java
PPTX
C++ Code as Seen by a Hypercritical Reviewer
PPTX
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
PPTX
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
PPTX
The Great and Mighty C++
PPTX
Static code analysis: what? how? why?
PDF
Zero, one, two, Freddy's coming for you
PDF
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PDF
PVS-Studio Static Analyzer as a Tool for Protection against Zero-Day Vulnerab...
PDF
Analysis of commits and pull requests in Travis CI, Buddy and AppVeyor using ...
PDF
PVS-Studio in the Clouds: CircleCI
60 антипаттернов для С++ программиста
60 terrible tips for a C++ developer
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Feature Overview
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021
Best Bugs from Games: Fellow Programmers' Mistakes
Does static analysis need machine learning?
Typical errors in code on the example of C++, C#, and Java
C++ Code as Seen by a Hypercritical Reviewer
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
The Great and Mighty C++
Static code analysis: what? how? why?
Zero, one, two, Freddy's coming for you
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PVS-Studio Static Analyzer as a Tool for Protection against Zero-Day Vulnerab...
Analysis of commits and pull requests in Travis CI, Buddy and AppVeyor using ...
PVS-Studio in the Clouds: CircleCI

Recently uploaded (20)

PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
AI in Product Development-omnex systems
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
medical staffing services at VALiNTRY
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PPTX
L1 - Introduction to python Backend.pptx
PDF
Digital Strategies for Manufacturing Companies
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PPTX
Online Work Permit System for Fast Permit Processing
PPTX
Odoo POS Development Services by CandidRoot Solutions
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PPTX
ai tools demonstartion for schools and inter college
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
AI in Product Development-omnex systems
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
medical staffing services at VALiNTRY
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
L1 - Introduction to python Backend.pptx
Digital Strategies for Manufacturing Companies
Design an Analysis of Algorithms II-SECS-1021-03
VVF-Customer-Presentation2025-Ver1.9.pptx
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Upgrade and Innovation Strategies for SAP ERP Customers
Online Work Permit System for Fast Permit Processing
Odoo POS Development Services by CandidRoot Solutions
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
ai tools demonstartion for schools and inter college

Static Code Analysis for Projects, Built on Unreal Engine

  • 1. Static Code Analysis for Projects, Built on Unreal Engine Ilya Gainulin PVS-Studio gainulin@viva64.com
  • 2. I Am Looking for Errors in Your Code 2
  • 3. Results of Incorrect Type Casing in the ShareX Project 3
  • 4. Results of Incorrect Type Casing in the ShareX Project Incorrect code: float pixelWeight = color.Alpha / 255; Fixed code: float pixelWeight = (float)color.Alpha / 255; 4 type Byte
  • 6. What Is Static Analysis? Static analysis is a way to check a program’s code without executing the program. 6
  • 7. Why Do You Need Static Analysis? • Detect errors early in the program development process. • Get recommendations on code formatting. • Check your spelling. • Calculate various software metrics 7
  • 8. Cost to Fix a Bug Fix earlier, save money! 8
  • 9. Why Do You Need Static Analysis? • Detect errors early in the program development process. • Get recommendations on code formatting. • Check your spelling. • Calculate various software metrics 9
  • 10. Static Analysis Advantages? • Detecting potential problems in code early • Full code coverage • Easy to use 10
  • 13. Static Analysis Advantages 13 Mono V3012 The '?:' operator, regardless of its conditional expression, always returns one and the same value: Color.FromArgb (150, 179, 225). ProfessionalColorTable.cs 258
  • 14. Static Analysis Disadvantages • Unavoidable false positives • Static analysis is usually not as good at detecting memory leaks and parallel errors 14
  • 15. Static Analysis Disadvantages void OutstandingIssue(const char *strCount) { unsigned nCount; sscanf_s(strCount, "%u", &nCount); int array[10]; memset(array, 0, nCount * sizeof(int)); } 15
  • 16. Static Analyzers Are Not Isolated Tools and Rare Checks – They Are a Part of DevOps 16 Написание кода Компиляция Unit тесты Интеграционные тесты Развёртывание Планирование Commit кода
  • 17. Static Analyzers Are Not Isolated Tools and Rare Checks – They Are a Part of DevOps 17 Написание кода Компиляция Полный статический анализ на билд сервере Unit тесты Интеграционные тесты Развёртывание Планирование Commit кода
  • 18. Static Analyzers Are Not Isolated Tools and Rare Checks – They Are a Part of DevOps 18
  • 19. Static Analyzers Are Not Isolated Tools and Rare Checks – They Are a Part of DevOps Написание кода Компиляция Полный статический анализ на билд сервере Unit тесты Интеграционные тесты Развёртывание Планирование Инкрементальный статический анализ на машине разработчика Commit кода 19
  • 20. Incremental Analysis • A decrease in analysis time, because only fixed or new code is processed. • Works well for early error detection. 20
  • 21. Ways to Use Static Analysis in a UE Project • Tracking compiler runs. • Direct integration with the build system. 21
  • 22. 22 Invoking CL.exe compiler MSBuild Unreal Build Tool Building Unreal Engine projects Build finished Gathering information The Simplest Way to Check a UE Project: Catch All Compiler Calls
  • 23. Tracking Compiler Runs from a GUI Application 23
  • 24. Tracking Compiler Runs from a GUI Application 24
  • 25. Tracking Compiler Runs from a GUI Application 25
  • 26. Direct Integration into Build System and VS • Run analysis directly from the Visual Studio IDE. • Run the analysis automatically when building a UE project. • Run incremental analysis. 26
  • 27. Common assembly scenario of a C++ project in VS 27
  • 28. Common assembly scenario of a C++ project in VS 28
  • 29. Particularities of Building a UE Project • Instead of Visual Studio’s standard build system, the UnrealBuildTool (UBT) is used. • Project files have the .uproject extension. 29
  • 30. Particularities of Building a UE Project 30
  • 31. What’s the Problem? • The project file may not contain paths to source files that need to be checked. • Not all compilation options required for correct preprocessing are present. 31
  • 32. What’s the Solution? • Write your own toolchain for the build system, so as to embed the static analyzer launch into UBT. • Pass a parameter to the UBT build system. That parameter would demonstrate the need for analysis. 32
  • 34. Some of the Current toolchain’s Limitations • Only builds a project or only analyzes the project. • No .cpp file analysis, if an included .h file has been changed. 34
  • 35. The Project Analysis After Its Build • Modifying the Build.bat and Rebuild.bat scripts. 35
  • 36. The Project Analysis After Its Build 36
  • 37. The Project Analysis After Its Build 37
  • 38. The .cpp File Analysis in Scenarios with the Connected Modified .h File • Remove and restore the cache file UBT uses. 38
  • 39. The .cpp File Analysis in Scenarios with the Connected Modified .h File 39
  • 40. Errors in Unreal Engine Code static bool PositionIsInside(....) { return Position.X >= Control.Center.X - BoxSize.X * 0.5f && Position.X <= Control.Center.X + BoxSize.X * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f; } 40
  • 41. Errors in Unreal Engine Code static bool PositionIsInside(....) { return Position.X >= Control.Center.X - BoxSize.X * 0.5f && Position.X <= Control.Center.X + BoxSize.X * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f; } PVS-Studio warns: V501 There are identical sub-expressions 'Position.Y >= Control.Center.Y — BoxSize.Y * 0.5f' to the left and to the right of the '&&' operator. svirtualjoystick.cpp 97 41
  • 42. Errors in Unreal Engine Code static bool PositionIsInside(....) { return Position.X >= Control.Center.X - BoxSize.X * 0.5f && Position.X <= Control.Center.X + BoxSize.X * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f && Position.Y >= Control.Center.Y - BoxSize.Y * 0.5f; Position.Y <= Control.Center.Y + BoxSize.Y * 0.5f; } PVS-Studio warns: V501 There are identical sub-expressions 'Position.Y >= Control.Center.Y — BoxSize.Y * 0.5f' to the left and to the right of the '&&' operator. svirtualjoystick.cpp 97 42
  • 43. enum ECubeFace; ECubeFace CubeFace; friend FArchive& operator<<(FArchive& Ar, FResolveParams& ResolveParams) { .... if(Ar.IsLoading()) { ResolveParams.CubeFace = (ECubeFace)ResolveParams.CubeFace; } .... } 43
  • 44. enum ECubeFace; ECubeFace CubeFace; friend FArchive& operator<<(FArchive& Ar, FResolveParams& ResolveParams) { .... if(Ar.IsLoading()) { ResolveParams.CubeFace = (ECubeFace)ResolveParams.CubeFace; } .... } PVS-Studio warns: V570 The 'ResolveParams.CubeFace' variable is assigned to itself. rhi.h 1279 44
  • 45. bool VertInfluencedByActiveBone( FParticleEmitterInstance* Owner, USkeletalMeshComponent* InSkelMeshComponent, int32 InVertexIndex, int32* OutBoneIndex = NULL); void UParticleModuleLocationSkelVertSurface::Spawn(....) { int32 BoneIndex1, BoneIndex2, BoneIndex3; BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE; if(!VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[0], &BoneIndex1) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[1], &BoneIndex2) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[2]) &BoneIndex3) { .... } 45
  • 46. bool VertInfluencedByActiveBone( FParticleEmitterInstance* Owner, USkeletalMeshComponent* InSkelMeshComponent, int32 InVertexIndex, int32* OutBoneIndex = NULL); void UParticleModuleLocationSkelVertSurface::Spawn(....) { int32 BoneIndex1, BoneIndex2, BoneIndex3; BoneIndex1 = BoneIndex2 = BoneIndex3 = INDEX_NONE; if(!VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[0], &BoneIndex1) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[1], &BoneIndex2) && !VertInfluencedByActiveBone( Owner, SourceComponent, VertIndex[2]) &BoneIndex3) { .... } 46
  • 47. The Analyzer’s Warning About a Sneaky Error PVS-Studio warns: V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. particlemodules_location.cpp 2120 47
  • 48. void GetRenderData(....) { .... FT_Bitmap* Bitmap = nullptr; if( Slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { FT_Bitmap NewBitmap; .... Bitmap = &NewBitmap; } .... OutRenderData.RawPixels.AddUninitialized( Bitmap->rows * Bitmap->width ); .... } 48
  • 49. void GetRenderData(....) { .... FT_Bitmap* Bitmap = nullptr; if( Slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ) { FT_Bitmap NewBitmap; .... Bitmap = &NewBitmap; } .... OutRenderData.RawPixels.AddUninitialized( Bitmap->rows * Bitmap->width ); .... } 49 PVS-Studio: V506 Pointer to local variable 'NewBitmap' is stored outside the scope of this variable. Such a pointer will become invalid. fontcache.cpp 466
  • 50. void UGameplayStatics::DeactivateReverbEffect(....) { if (GEngine || !GEngine->UseSound()) { return; } UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....); .... } 50
  • 51. void UGameplayStatics::DeactivateReverbEffect(....) { if (GEngine || !GEngine->UseSound()) { return; } UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....); .... } PVS-Studio: V522 Dereferencing of the null pointer 'GEngine' might take place. Check the logical condition. gameplaystatics.cpp 988 51
  • 52. void UGameplayStatics::DeactivateReverbEffect(....) { if (GEngine || !GEngine->UseSound()) if (GEngine == nullptr || !GEngine->UseSound()) { return; } UWorld* ThisWorld = GEngine->GetWorldFromContextObject(....); .... } PVS-Studio: V522 Dereferencing of the null pointer 'GEngine' might take place. Check the logical condition. gameplaystatics.cpp 988 52
  • 53. template< typename DefinitionType > FORCENOINLINE void Set(....) { .... if ( DefinitionPtr == NULL ) { WidgetStyleValues.Add( PropertyName, MakeShareable( new DefinitionType( InStyleDefintion ) ) ); } else { WidgetStyleValues.Add( PropertyName, MakeShareable( new DefinitionType( InStyleDefintion ) ) ); } } 53
  • 54. template< typename DefinitionType > FORCENOINLINE void Set(....) { .... if ( DefinitionPtr == NULL ) { WidgetStyleValues.Add( PropertyName, MakeShareable( new DefinitionType( InStyleDefintion ) ) ); } else { WidgetStyleValues.Add( PropertyName, MakeShareable( new DefinitionType( InStyleDefintion ) ) ); } } 54 PVS-Studio: V523 The 'then' statement is equivalent to the 'else' statement. paths.cpp 703
  • 55. Conclusion • Static analysis of UE projects is not too complicated. • Combine static analysis with other testing methods. 55
  • 56. Thank You for Your Attention 56