SlideShare a Scribd company logo
Статический анализ кода проектов, построенных на
движке 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

PDF
Сенцов Сергей "Приемы оптимизаций Desktop приложений"
PPTX
Основы и применение статического анализа кода при разработке лекция 1
PDF
Цена ошибки
PPTX
Асинхронность и сопрограммы
PDF
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
PPTX
Что могут статические анализаторы, чего не могут программисты и тестировщики
PDF
Шишки, набитые за 15 лет использования акторов в C++
PPTX
Современный статический анализ кода: что умеет он, чего не умели линтеры
Сенцов Сергей "Приемы оптимизаций Desktop приложений"
Основы и применение статического анализа кода при разработке лекция 1
Цена ошибки
Асинхронность и сопрограммы
Исключения C++ через призму компиляторных оптимизаций. Роман Русяев ➠ CoreHa...
Что могут статические анализаторы, чего не могут программисты и тестировщики
Шишки, набитые за 15 лет использования акторов в C++
Современный статический анализ кода: что умеет он, чего не умели линтеры

What's hot (20)

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

Similar to Static code analysis of the projects built on Unreal Engine (20)

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

More from DevGAMM Conference (20)

PPTX
The art of small steps, or how to make sound for games in conditions of war /...
PPTX
Breaking up with FMOD - Why we ended things and embraced Metasounds / Daniel ...
PPTX
How Audio Objects Improve Spatial Accuracy / Mads Maretty Sønderup (Audiokine...
PPTX
Why indie developers should consider hyper-casual right now / Igor Gurenyov (...
PPTX
AI / ML for Indies / Tyler Coleman (Retora Games)
PDF
Agility is the Key: Power Up Your GameDev Project Management with Agile Pract...
PPTX
New PR Tech and AI Tools for 2023: A Game Changer for Outreach / Kirill Perev...
PDF
Playable Ads - Revolutionizing mobile games advertising / Jakub Kukuryk (Popc...
PDF
Creative Collaboration: Managing an Art Team / Nastassia Radzivonava (Glera G...
PDF
From Local to Global: Unleashing the Power of Payments / Jan Kuhlmannn (Xsolla)
PDF
Strategies and case studies to grow LTV in 2023 / Julia Iljuk (Balancy)
PDF
Why is ASO not working in 2023 and how to change it? / Olena Vedmedenko (Keya...
PDF
How to increase wishlists & game sales from China? Growth marketing tactics &...
PDF
Turkish Gaming Industry and HR Insights / Mustafa Mert EFE (Zindhu)
PDF
Building an Awesome Creative Team from Scratch, Capable of Scaling Up / Sasha...
PPTX
Seven Reasons Why Your LiveOps Is Not Performing / Alexander Devyaterikov (Be...
PDF
The Power of Game and Music Collaborations: Reaching and Engaging the Masses ...
PPTX
Branded Content: How to overcome players' immunity to advertising / Alex Brod...
PPTX
Resurrecting Chasm: The Rift - A Source-less Remastering Journey / Gennadii P...
PPTX
How NOT to do showcase events: Behind the scenes of Midnight Show / Andrew Ko...
The art of small steps, or how to make sound for games in conditions of war /...
Breaking up with FMOD - Why we ended things and embraced Metasounds / Daniel ...
How Audio Objects Improve Spatial Accuracy / Mads Maretty Sønderup (Audiokine...
Why indie developers should consider hyper-casual right now / Igor Gurenyov (...
AI / ML for Indies / Tyler Coleman (Retora Games)
Agility is the Key: Power Up Your GameDev Project Management with Agile Pract...
New PR Tech and AI Tools for 2023: A Game Changer for Outreach / Kirill Perev...
Playable Ads - Revolutionizing mobile games advertising / Jakub Kukuryk (Popc...
Creative Collaboration: Managing an Art Team / Nastassia Radzivonava (Glera G...
From Local to Global: Unleashing the Power of Payments / Jan Kuhlmannn (Xsolla)
Strategies and case studies to grow LTV in 2023 / Julia Iljuk (Balancy)
Why is ASO not working in 2023 and how to change it? / Olena Vedmedenko (Keya...
How to increase wishlists & game sales from China? Growth marketing tactics &...
Turkish Gaming Industry and HR Insights / Mustafa Mert EFE (Zindhu)
Building an Awesome Creative Team from Scratch, Capable of Scaling Up / Sasha...
Seven Reasons Why Your LiveOps Is Not Performing / Alexander Devyaterikov (Be...
The Power of Game and Music Collaborations: Reaching and Engaging the Masses ...
Branded Content: How to overcome players' immunity to advertising / Alex Brod...
Resurrecting Chasm: The Rift - A Source-less Remastering Journey / Gennadii P...
How NOT to do showcase events: Behind the scenes of Midnight Show / Andrew Ko...

Static code analysis of the projects built on 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