Статический анализатор PVS-Studio постоянно совершенствуется для повышения эффективности анализа кода. В этой статье мы расскажем о последних обновлениях анализатора, которые существенно улучшают анализ проектов на основе Unreal Engine.
История началась с обращения Epic Games (разработчиков Unreal Engine) о большом количестве ложных срабатываний при использовании встроенных макросов:
struct AAA
{
virtual int aaa() { return 1; }
virtual void bbb() {}
};
static void ccc(AAA* ptr)
{
check(ptr);
int ddd = ptr->aaa();
if (ptr) // <= V595 The 'ptr' pointer was utilized before
// it was verified agains nullptr.
{
ptr->bbb();
}
}
Ожидается, что если поток управления перейдёт на следующую инструкцию после передачи указателя в макрос check, то указатель ptr будет ненулевым. Анализатор считал иначе и выдавал при этом ложное срабатывание. Также Epic Games уточнили, что эта проблема возникает только при использовании конфигурации Shipping.
Конфигурация Shipping обычно предназначена для релизной сборки, но разработчики часто используют её в процессе разработки, чтобы:
При более подробном изучении проблемы мы выяснили, что ложное срабатывание возникает из-за макроса CA_ASSUME, который находится внутри макроса check:
#define CA_ASSUME( Expr ) __analysis_assume( !!( Expr ) )
Выше мы уже упоминали, что Shipping сборки близки к Release, а потому после препроцессирования он разворачивается в noop-операцию (т.е. не выполняющую никаких действий). Примерно так:
{
....
do
{
__noop(!!(ptr));
}
while ((0, 0) __pragma(warning(pop)));
};
Интересный факт: Epic Games сообщили нам, что Clang Static Analyzer не выдаёт ложных срабатываний на таком паттерне. Это натолкнуло нас на мысль посмотреть имплементацию макроса CA_ASSUME для Clang Static Analyzer:
__declspec(dllimport, noreturn) void CA_AssumeNoReturn();
#define CA_ASSUME( Expr ) ( __builtin_expect(!bool(Expr), 0) \
? CA_AssumeNoReturn() \
: (void)0 )
Макрос разворачивается в вызов noreturn-функции, если переданное выражение вычисляется как false. Именно это и помогает Clang Static Analyzer понять, что указатель после вызова макроса ненулевой.
После обсуждения с Epic Games было принято решение сделать отдельную имплементацию проверочных макросов, что обеспечит корректную работу анализатора PVS-Studio. Функционал начнёт работать, начиная с релизов PVS-Studio 7.33 и Unreal Engine 5.5.
Совместно с разработчиками Unreal Engine мы изменили промежуточный формат вывода предупреждений. Ядро C и C++ анализатора уже достаточно давно генерирует предупреждения в новом формате, главная фишка которого для пользователя — поддержка многофайловой навигации по коду. К сожалению, если вы проверяли свои проекты, основанные на Unreal Engine, при помощи интеграции с UnrealBuildTool, то этот функционал был недоступен до релиза PVS-Studio 7.30.
К счастью, теперь без проблем можно узнать, место разыменования нулевого указателя и путь, по которому он к нему пришёл.
SN-DBS — это распределённая система сборки, разработанная для значительного повышения производительности компиляции. Достигается это за счёт распределения задач сборки между несколькими узлами, что особенно полезно для крупномасштабных проектов.
Ранее при попытке анализа проекта, собираемого через SN-DBS, с помощью PVS-Studio происходила проблема: анализ проходил только на той части файлов, которые обрабатывались на мастер-ноде. В логах сборки при этом появлялось сообщение об ошибке.
Исправление этой проблемы уже готово и планируется к добавлению в предстоящий релиз Unreal Engine 5.5.
Вы можете интегрировать PVS-Studio в процесс сборки, модифицировав target-файл. Этот подход особенно полезен, когда вам нужно часто регенерировать файлы проекта.
Для интеграции вам нужно добавить параметр 'StaticAnalyzer' со значением ' PVSStudio':
Для версии 5.0 и ниже:
WindowsPlatform.StaticAnalyzer = WindowsStaticAnalyzer.PVSStudio;
Для версии 5.1 и выше:
StaticAnalyzer = StaticAnalyzer.PVSStudio;
Кроме параметра 'StaticAnalyzer', вы можете добавить другие настройки, о которых расскажем ниже.
Начиная с Unreal Engine 5.4, анализ автогенерируемых файлов (с расширением *.gen.cpp) отключён по умолчанию. Сделано это в целях снижения времени анализа крупных проектов. При желании можно вернуть старое поведение с помощью специального флага:
-StaticAnalyzerIncludeGenerated
В Unreal Engine 5.4 была добавлена настройка, которая задаёт уровень предупреждений, выдаваемых UnrealBuildTool при анализе. Она не влияет на работу PVS-Studio, но может привести к замедлению при получении отчёта. Это происходит из-за включённой по умолчанию настройки. Следовательно, UnrealBuildTool будет выводить больше предупреждений, чем необходимо, что приводит к увеличению времени генерации и обработки отчёта.
Чтобы отключить её и избежать вышеуказанной проблемы, добавьте следующий флаг в строку запуска UnrealBuildTool:
-StaticAnalyzerPVSPrintLevel = 0
Альтернативно, можно задать эту настройку в файле *.Target.cs:
StaticAnalyzerPVSPrintLevel = 0;
Начиная с Unreal Engine 5.4 стала доступна настройка, позволяющая запускать анализатор только на файлах проекта (пропуская анализ модуля Unreal Engine). Использование этой настройки позволяет значительно ускорить процесс анализа, особенно если в исходный код Unreal Engine не вносились никакие изменения.
Чтобы включить эту настройку, добавьте следующий флаг в строку запуска UnrealBuildTool:
-StaticAnalyzerProjectOnly
Альтернативно, можно задать эту настройку в файле *.Target.cs:
bStaticAnalyzerProjectOnly = true;
При анализе проектов, основанных на Unreal Engine, пользователи могут столкнуться с повышенным потреблением памяти. Существует две основные причины этого:
Мы значительно оптимизировали производительность анализатора (как время анализа, так потребляемую память), достигнув значительного прогресса в этом направлении. Тем не менее мы всё ещё рекомендуем отключать анализ unity pack'ов при работе с большими проектами. Как это сделать можно узнать здесь.
В PVS-Studio доступны диагностические правила для выявления багов, специфичных для проектов на основе Unreal Engine:
Мы уже получили обратную связь от некоторых пользователей по ложным срабатываниям и исправили определённое количество из них. Сейчас мы находимся в процессе исправления оставшихся проблем.
Мы будем признательны за любые предложения по новым правилам. Более подробно об этом можно почитать здесь.
Пользователи Unreal Engine столкнулись с большим количеством ложных срабатываний от диагностических правил общего назначения. В связи с этим мы приступили к работе по их устранению. На данный момент мы исправили диагностические правила, которые вызывали наибольшее количество ложных срабатываний на коде Unreal Engine:
Мы не останавливаемся на достигнутом! Сейчас работаем над улучшением следующего пакета диагностических правил.
Надеемся, что описанные в статье улучшения помогут как разработчикам Epic Games, так и пользователям Unreal Engine.
Если у вас есть идеи для диагностических правил Unreal Engine проектов или улучшения анализатора, пожалуйста, поделитесь ими с нами. Мы всегда открыты для новых предложений.
Оставайтесь с нами, чтобы быть в курсе всех последних обновлений :)