PVS-Studio 7.24: Unity, продвинутые механизмы подавления и многое другое
Вышел новый релиз PVS-Studio — 7.24. В нём мы улучшили анализ проектов на Unity, добавили новые возможности работы с файлами подавления (*.suppress), реализовали ряд диагностик и сделали многое другое. Подробности в этой заметке.
Улучшения анализа проектов на Unity
Для многих классов игрового движка Unity оператор '==' перегружен особым образом. Наиболее интересной особенностью перегрузки является тот факт, что сравнение с null может вернуть true, даже если сравниваемая ссылка не является нулевой. Пример:
void Start()
{
GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
Instantiate(obj);
if (obj == null)
Debug.Log("obj == null before destroy");
DestroyImmediate(obj);
if (obj == null)
Debug.Log("obj == null after destroy");
if (ReferenceEquals(obj, null))
Debug.Log("obj is really null");
if (obj is null)
Debug.Log("obj is really null 2");
}
Если вы работаете с Unity, то наверняка сможете сказать, что на экран консоли будет выведена единственная надпись: «obj == null after destroy». Всё потому, что оператор '==' при сравнении с null возвращает true, если сравниваемый объект уничтожен.
Новая версия анализатора лучше понимает такие особенности. В первую очередь это позволяет убрать ложные срабатывания о разыменовании нулевых ссылок. Также теперь PVS-Studio отслеживает обращения к методам и свойствам потенциально уничтоженных объектов. Такие обращения могут приводить к выбрасыванию исключений, и для их поиска мы добавили отдельное правило V3188.
Мы планируем и дальше улучшать возможности анализа проектов, использующих Unity, дорабатывая имеющиеся механизмы и реализуя новые диагностики. Обязательно пишите нам если у вас есть идеи по поводу того, какие ошибки анализатору стоит находить в таких проектах.
Продвинутые механизмы работы с файлами подавления в Visual Studio
В плагине для Visual Studio был расширен интерфейс для работы с файлами подавления (*.suppress). Раньше предполагалось, что в проекте может быть только один suppress-файл. Теперь же к каждому проекту может относиться несколько файлов подавления.
Ниже перечислены несколько нововведений.
1) Можно добавлять предупреждения в конкретные suppress-файлы:
2) Можно выбирать suppress-файлы, предупреждения из которых будут отображены в таблице:
3) Подавленные предупреждения можно также перемещать между suppress-файлами:
Эти возможности позволяют реализовывать новые сценарии работы с файлами подавления. К примеру, можно использовать один suppress-файл для предупреждений, оставленных «на потом», и ещё один — для ложных срабатываний.
Подробнее с этими и другими возможностями вы можете ознакомиться в документации.
Новые возможности подавления предупреждений из командной строки
В утилитах PVS-Studio_Cmd.exe и pvs-studio-dotnet появился новый режим — suppression. С помощью него можно производить различные операции с файлами подавления (*.suppress).
К примеру, можно создать для каждого проекта из решения новый suppress-файл:
PVS-Studio_Cmd.exe suppression -m CreateEmptySuppressFiles ^
-t JulietTestSuite.sln ^
-P myPrefix%projName%myPostfix.suppress
В результате выполнения такой команды в каждый проект решения будет добавлен пустой suppress-файл, имя которого генерируется на основе имени соответствующего проекта.
Ещё одной интересной возможностью является подавление предупреждений, соответствующих определённым критериям:
PVS-Studio_Cmd.exe suppression -m Suppress ^
-t JulietTestSuite.sln ^
-P myPrefix%projName%myPostfix.suppress ^
-R JulietTestSuite.plog ^
--groups "GA:3|OWASP"
Указанная команда подавит предупреждения из отчёта JulietTestSuite.plog в suppress-файлы, соответствующие паттерну, переданному через параметр '-P'. При этом подавлены будут только предупреждения 3 уровня группы General Analysis и все предупреждения группы OWASP.
Таким же образом можно и «снять подавление» с определённых предупреждений — для этого в качестве значения параметра '-m' необходимо передать 'UnSuppress'.
Эти и другие возможности нового режима подробно описаны в документации.
Учёт оператора null-forgiving ('!') в C#
В C# 9 в язык добавили возможность условного разделения ссылочных типов на допускающие и не допускающие null. Подробности — в официальной документации.
Когда ссылочная переменная может иметь значение null, к имени его типа добавляется '?'. Если же в конкретной ситуации такое выражение точно не возвращает нулевую ссылку, разработчики могут использовать оператор null-forgiving ('!'). Пример:
bool _returnText = false;
void Foo()
{
_returnText = true;
string value = GetText()!;
_ = value.Length;
}
// may return null
private string? GetText()
{
return _returnText ? "some text" : null;
}
Метод GetText в некоторых обстоятельствах действительно может возвращать null, однако результат его вызова внутри Foo точно является строкой «some text». Пометив вызов с помощью постфиксного '!', разработчик сообщает компилятору, что выражение не равно null.
Мы долго обдумывали необходимость учёта оператора null-forgiving при анализе. С одной стороны, он не даёт гарантий того, что выражение действительно не будет равно null. С другой — он является способом подавления ложных предупреждений компилятора о небезопасном разыменовании. Стоит ли ругаться там, где похожее предупреждение компилятора уже было подавлено?
В итоге анализатор всё же начал учитывать оператор null-forgiving при выдаче предупреждений. Теперь PVS-Studio не будет выдавать предупреждения о разыменовании потенциально нулевой ссылки, если выражение размечено с помощью '!'. Однако предупреждение всё же будет показано, если null является единственным возможным значением выражения.
Новые диагностики
C, C++
V1095. Usage of potential invalid handle. The value should be non-negative.
V1096. Variable with static storage duration is declared inside the inline function with external linkage. This may lead to ODR violation.
V1097. Line splice results in a character sequence that matches the syntax of a universal-character-name. Using this sequence lead to undefined behavior.
C#
V3187. Parts of an SQL query are not delimited by any separators or whitespaces. Executing this query may lead to an error.
V3188. The value of an expression is a potentially destroyed Unity object or null. Member invocation on this value may lead to an exception.
V3189. The assignment to a member of the readonly field will have no effect when the field is of a value type. Consider restricting the type parameter to reference types.
Личный кабинет пользователя
Недавно мы добавили на сайт возможность создавать свой аккаунт и заходить в свой личный кабинет. Кнопки регистрации/авторизации можно найти в шапке сайта, наведя курсор на иконку:
Личный кабинет позволяет:
просматривать список своих триальных ключей;
подписываться на комментарии к статьям;
получать оповещения об ответах на ваши комментарии;
настраивать подписки на рассылки о новых статьях и релизах.
В общем, приглашаю всех регистрироваться :).
Подробнее о личном кабинете можете прочитать в заметке.
Статьи
Для тех, кто пишет на C++:
Для тех, кто пишет на C#:
Разное:
**
Загрузить актуальную версию PVS-Studio можно здесь.
Если хотите получать пресс-релизы по почте, подписывайтесь на рассылку.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Nikita Lipilin. PVS-Studio 7.24: Unity, advanced warning suppression and much more.