SlideShare a Scribd company logo
1 of 56
Статический анализ кода проектов, построенных на
движке Unreal Engine
Илья Гайнулин
PVS-Studio
gainulin@viva64.com
Ищу ошибки в твоём коде
2
Результат неправильного приведения
типов в проекте ShareX
3
Результат неправильного приведения
типов в проекте ShareX
Как было:
float pixelWeight = color.Alpha / 255;
Как поправили:
float pixelWeight = (float)color.Alpha / 255;
4
тип Byte
Сотрудничество с Epic Games
5
Что такое статический анализ?
Это анализ программного обеспечения, производимый без
реального выполнения исследуемых программ.
6
Для чего нужен статический анализ?
• Обнаружение ошибок в коде на ранних этапах разработки
программного обеспечения
• Получение рекомендаций по оформлению кода,
проверка правописания
• Подсчёт различных метрик программного
обеспечения
7
Стоимость исправления дефекта
Исправь раньше,
сократи затраты!
8
Для чего нужен статический анализ?
• Обнаружение ошибок в коде на ранних этапах разработки
программного обеспечения
• Получение рекомендаций по оформлению кода,
проверка правописания
• Подсчёт различных метрик программного
обеспечения
9
Преимущества статического анализа?
• Раннее обнаружение потенциальных проблем в коде
• Полное покрытие кода
• Простота использования
10
Преимущества статического анализа?
11
Преимущества статического анализа?
12
Преимущества статического анализа?
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
Недостатки статического анализа
void OutstandingIssue(const char *strCount)
{
unsigned nCount;
sscanf_s(strCount, "%u", &nCount);
int array[10];
memset(array, 0, nCount * sizeof(int));
}
15
Статические анализаторы — это не изолированные
инструменты и редкие проверки, а часть DevOps
16
Написание кода Компиляция Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Commit кода
Статические анализаторы — это не изолированные
инструменты и редкие проверки, а часть DevOps
17
Написание кода Компиляция
Полный статический
анализ на билд
сервере
Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Commit кода
Статические анализаторы — это не изолированные
инструменты и редкие проверки, а часть DevOps
18
Статические анализаторы — это не изолированные
инструменты и редкие проверки, а часть DevOps
Написание кода Компиляция
Полный статический
анализ на билд
сервере
Unit тесты
Интеграционные
тесты
Развёртывание
Планирование
Инкрементальный
статический анализ
на машине
разработчика
Commit кода
19
Инкрементальный анализ
• Сокращение времени анализа, так как анализируется только
исправленный или новый код
• Хорошо подходит для раннего обнаружения ошибок
20
Способы проведения статического анализа
UE проекта
• Отслеживания запусков компилятора
• Прямая интеграция с системой сборки
21
22
Invoking CL.exe
compiler
MSBuild
Unreal Build
Tool
Building Unreal Engine
projects
Build finished
Gathering
information
Самый простой способ проверить UE проект – это отловить все
вызовы компилятора
Отслеживание запусков компилятора из GUI приложения
23
Отслеживание запусков компилятора из GUI приложения
24
Отслеживание запусков компилятора из GUI приложения
25
Прямая интеграция в сборочную систему и
VS
• Возможность проводить анализ напрямую из IDE Visual Studio
• Автоматический запуск анализа при осуществлении сборки UE
проекта
• Возможность осуществлять инкрементальный анализ
26
Обычный сценарий сборки C++ проекта в VS
27
Обычный сценарий сборки C++ проекта в VS
28
Особенность сборки UE проекта
• Использование не стандартной сборочной системы для Visual
Studio - MSBuild, а собственной – UnrealBuildTool (UBT)
• Использование проектных файлов с расширением .uproject
29
Особенность сборки UE проекта
30
В чём проблема?
• В проектном файле могут отсутствовать пути до исходных
файлов, которые необходимо проверять
• Присутствуют не все параметры компиляции, необходимые для
правильного препроцессирования
31
Какое решение?
• Встроить в UBT запуск статического анализатора, то есть
написать свой toolchain для сборочной системы
• Передавать какой-нибудь параметр сборочной системе UBT при
запуске, указывающий о необходимости проведения анализа
32
Какое решение?
33
Несколько ограничений существующего
toolchain’а
• Только сборка или только анализ проекта
• Нет анализа .cpp файла, если был изменён подключённый .h файл
34
Анализ проекта после его сборки
• Модификация скриптов Build.bat и Rebuild.bat
35
Анализ проекта после его сборки
36
Анализ проекта после его сборки
37
Анализ .cpp файла при модификации
подключённого .h
• Удаление и восстановление кэш файла, используемого UBT
38
Анализ .cpp файла при модификации
подключённого .h
39
Примеры ошибок в коде движка Unreal Engine
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
Примеры ошибок в коде движка Unreal Engine
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: 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
Примеры ошибок в коде движка Unreal Engine
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: 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: 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
Сообщение анализатора к хитрой ошибке
Предупреждение PVS-Studio: 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
Заключение
• Статический анализ UE проектов это не так сложно
• Статический анализ должен сочетаться с другими методами
тестирования
55
Спасибо за внимание
56

More Related Content

What's hot

Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?
Nikita Lipsky
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
Alex Tumanoff
 
Async clinic by by Sergey Teplyakov
Async clinic by by Sergey TeplyakovAsync clinic by by Sergey Teplyakov
Async clinic by by Sergey Teplyakov
Alex Tumanoff
 

What's hot (20)

Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
Александр Тарасенко, Использование python для автоматизации отладки С/C++ код...
 
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
Как мы уменьшили количество ошибок в Unreal Engine с помощью статического ана...
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
AOT для Java: Мифы и Challenges
AOT для Java: Мифы и ChallengesAOT для Java: Мифы и Challenges
AOT для Java: Мифы и Challenges
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Жилье комфорт-класса для акторов и хендлеров. Максим Хижинский. CoreHard Spri...
Жилье комфорт-класса для акторов и хендлеров. Максим Хижинский. CoreHard Spri...Жилье комфорт-класса для акторов и хендлеров. Максим Хижинский. CoreHard Spri...
Жилье комфорт-класса для акторов и хендлеров. Максим Хижинский. CoreHard Spri...
 
Unit tests final
Unit tests finalUnit tests final
Unit tests final
 
Улучшение качества открытого программного обеспечения с помощью инструментов ...
Улучшение качества открытого программного обеспечения с помощью инструментов ...Улучшение качества открытого программного обеспечения с помощью инструментов ...
Улучшение качества открытого программного обеспечения с помощью инструментов ...
 
DI в C++ тонкости и нюансы
DI в C++ тонкости и нюансыDI в C++ тонкости и нюансы
DI в C++ тонкости и нюансы
 
Превышаем скоросные лимиты с Angular 2
Превышаем скоросные лимиты с Angular 2Превышаем скоросные лимиты с Angular 2
Превышаем скоросные лимиты с Angular 2
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
Григорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммыГригорий Демченко — Асинхронное программирование и сопрограммы
Григорий Демченко — Асинхронное программирование и сопрограммы
 
Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2Превышаем скоростные лимиты с Angular 2
Превышаем скоростные лимиты с Angular 2
 
Опыт тестирования API САПР платформы
Опыт тестирования API САПР платформыОпыт тестирования API САПР платформы
Опыт тестирования API САПР платформы
 
Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
 
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестовЮлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестов
 
Async clinic by by Sergey Teplyakov
Async clinic by by Sergey TeplyakovAsync clinic by by Sergey Teplyakov
Async clinic by by Sergey Teplyakov
 

Similar to Статический анализ кода проектов, построенных на движке Unreal Engine

Комплексное использование анализаторов для повышения качества кода
Комплексное использование анализаторов для повышения качества кодаКомплексное использование анализаторов для повышения качества кода
Комплексное использование анализаторов для повышения качества кода
Andrey Karpov
 
Continuous integration
Continuous integrationContinuous integration
Continuous integration
MageCloud
 

Similar to Статический анализ кода проектов, построенных на движке Unreal Engine (20)

Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализатор
 
Нужно ли статическому анализу машинное обучение?
Нужно ли статическому анализу машинное обучение?Нужно ли статическому анализу машинное обучение?
Нужно ли статическому анализу машинное обучение?
 
Как команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы TizenКак команда PVS-Studio может улучшить код операционной системы Tizen
Как команда PVS-Studio может улучшить код операционной системы Tizen
 
Качество кода игровых движков: неужели всё так плохо?
Качество кода игровых движков: неужели всё так плохо?Качество кода игровых движков: неужели всё так плохо?
Качество кода игровых движков: неужели всё так плохо?
 
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опытОблегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
 
Комплексное использование анализаторов для повышения качества кода
Комплексное использование анализаторов для повышения качества кодаКомплексное использование анализаторов для повышения качества кода
Комплексное использование анализаторов для повышения качества кода
 
Паттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играхПаттерны 64-битных ошибок в играх
Паттерны 64-битных ошибок в играх
 
Поговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложений
 
Статические анализаторы кода как DevSecOps решение
Статические анализаторы кода как DevSecOps решениеСтатические анализаторы кода как DevSecOps решение
Статические анализаторы кода как DevSecOps решение
 
Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?Статический анализ кода: Что? Как? Зачем?
Статический анализ кода: Что? Как? Зачем?
 
Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"
 
Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»
 
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
Статический анализ и написание качественного кода на C/C++ для встраиваемых с...
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Formal verification of C code
Formal verification of C codeFormal verification of C code
Formal verification of C code
 
Формальная верификация кода на языке Си
Формальная верификация кода на языке СиФормальная верификация кода на языке Си
Формальная верификация кода на языке Си
 
Tbb лр1
Tbb   лр1Tbb   лр1
Tbb лр1
 
Continuous integration
Continuous integrationContinuous integration
Continuous integration
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй это
 
Aspect Oriented Approach
Aspect Oriented ApproachAspect Oriented Approach
Aspect Oriented Approach
 

More from Andrey Karpov

More from Andrey Karpov (20)

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

Статический анализ кода проектов, построенных на движке Unreal Engine

  • 1. Статический анализ кода проектов, построенных на движке Unreal Engine Илья Гайнулин PVS-Studio gainulin@viva64.com
  • 2. Ищу ошибки в твоём коде 2
  • 4. Результат неправильного приведения типов в проекте ShareX Как было: float pixelWeight = color.Alpha / 255; Как поправили: float pixelWeight = (float)color.Alpha / 255; 4 тип Byte
  • 6. Что такое статический анализ? Это анализ программного обеспечения, производимый без реального выполнения исследуемых программ. 6
  • 7. Для чего нужен статический анализ? • Обнаружение ошибок в коде на ранних этапах разработки программного обеспечения • Получение рекомендаций по оформлению кода, проверка правописания • Подсчёт различных метрик программного обеспечения 7
  • 8. Стоимость исправления дефекта Исправь раньше, сократи затраты! 8
  • 9. Для чего нужен статический анализ? • Обнаружение ошибок в коде на ранних этапах разработки программного обеспечения • Получение рекомендаций по оформлению кода, проверка правописания • Подсчёт различных метрик программного обеспечения 9
  • 10. Преимущества статического анализа? • Раннее обнаружение потенциальных проблем в коде • Полное покрытие кода • Простота использования 10
  • 13. Преимущества статического анализа? 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. Недостатки статического анализа • Неизбежное появление ложно-позитивных срабатываний • Статический анализ, как правило, слаб в диагностике утечек памяти и параллельных ошибок 14
  • 15. Недостатки статического анализа void OutstandingIssue(const char *strCount) { unsigned nCount; sscanf_s(strCount, "%u", &nCount); int array[10]; memset(array, 0, nCount * sizeof(int)); } 15
  • 16. Статические анализаторы — это не изолированные инструменты и редкие проверки, а часть DevOps 16 Написание кода Компиляция Unit тесты Интеграционные тесты Развёртывание Планирование Commit кода
  • 17. Статические анализаторы — это не изолированные инструменты и редкие проверки, а часть DevOps 17 Написание кода Компиляция Полный статический анализ на билд сервере Unit тесты Интеграционные тесты Развёртывание Планирование Commit кода
  • 18. Статические анализаторы — это не изолированные инструменты и редкие проверки, а часть DevOps 18
  • 19. Статические анализаторы — это не изолированные инструменты и редкие проверки, а часть DevOps Написание кода Компиляция Полный статический анализ на билд сервере Unit тесты Интеграционные тесты Развёртывание Планирование Инкрементальный статический анализ на машине разработчика Commit кода 19
  • 20. Инкрементальный анализ • Сокращение времени анализа, так как анализируется только исправленный или новый код • Хорошо подходит для раннего обнаружения ошибок 20
  • 21. Способы проведения статического анализа UE проекта • Отслеживания запусков компилятора • Прямая интеграция с системой сборки 21
  • 22. 22 Invoking CL.exe compiler MSBuild Unreal Build Tool Building Unreal Engine projects Build finished Gathering information Самый простой способ проверить UE проект – это отловить все вызовы компилятора
  • 26. Прямая интеграция в сборочную систему и VS • Возможность проводить анализ напрямую из IDE Visual Studio • Автоматический запуск анализа при осуществлении сборки UE проекта • Возможность осуществлять инкрементальный анализ 26
  • 27. Обычный сценарий сборки C++ проекта в VS 27
  • 28. Обычный сценарий сборки C++ проекта в VS 28
  • 29. Особенность сборки UE проекта • Использование не стандартной сборочной системы для Visual Studio - MSBuild, а собственной – UnrealBuildTool (UBT) • Использование проектных файлов с расширением .uproject 29
  • 31. В чём проблема? • В проектном файле могут отсутствовать пути до исходных файлов, которые необходимо проверять • Присутствуют не все параметры компиляции, необходимые для правильного препроцессирования 31
  • 32. Какое решение? • Встроить в UBT запуск статического анализатора, то есть написать свой toolchain для сборочной системы • Передавать какой-нибудь параметр сборочной системе UBT при запуске, указывающий о необходимости проведения анализа 32
  • 34. Несколько ограничений существующего toolchain’а • Только сборка или только анализ проекта • Нет анализа .cpp файла, если был изменён подключённый .h файл 34
  • 35. Анализ проекта после его сборки • Модификация скриптов Build.bat и Rebuild.bat 35
  • 36. Анализ проекта после его сборки 36
  • 37. Анализ проекта после его сборки 37
  • 38. Анализ .cpp файла при модификации подключённого .h • Удаление и восстановление кэш файла, используемого UBT 38
  • 39. Анализ .cpp файла при модификации подключённого .h 39
  • 40. Примеры ошибок в коде движка Unreal Engine 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. Примеры ошибок в коде движка Unreal Engine 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: 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. Примеры ошибок в коде движка Unreal Engine 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: 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: 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. Сообщение анализатора к хитрой ошибке Предупреждение PVS-Studio: 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. Заключение • Статический анализ UE проектов это не так сложно • Статический анализ должен сочетаться с другими методами тестирования 55