>
>
PVS-Studio 7.24: Unity, продвинутые мех…

Никита Липилин
Статей: 32

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 можно здесь.

Если хотите получать пресс‑релизы по почте, подписывайтесь на рассылку.