Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
menu mobile close menu
Проверка проектов
Дополнительная информация
toggle menu Оглавление

V3080. Possible null dereference.

29 Мар 2016

Анализатор обнаружил фрагмент кода, который может привести к доступу по нулевой ссылке.

Рассмотрим несколько примеров, для которых анализатор выдает диагностическое сообщение V3080:

if (obj != null || obj.Func()) { ... }
if (obj == null && obj.Func()) { ... }
if (list == null && list[3].Func()) { ... }

Во всех условиях допущена логическая ошибка, которая приведет к доступу по нулевой ссылке. Ошибка может быть допущена при рефакторинге кода или из-за случайно опечатки.

Корректные варианты:

if (obj == null || obj.Func()) { .... }
if (obj != null && obj.Func()) { .... }
if (list != null && list[3].Func()) { .... }

Конечно, это очень простые ситуации. На практике проверка объекта на null и его использование может находиться в разных местах. Если анализатор выдал предупреждение V3080, изучите код расположенный выше и попробуйте понять, почему ссылка может быть нулевой.

Пример кода, где проверка и использование объекта находятся в разных строках

if (player == null) {
  ....
  var identity = CreateNewIdentity(player.DisplayName);
  ....
}

Анализатор предупредит, об опасности в строке внутри блока 'if'. Здесь или некорректно написано условие, или вместо 'player' должна использоваться другая переменная.

Программисты иногда забывают о том, что при проверке двух объектов на null один из них может оказаться нулевым, а второй нет, в результате чего будет вычислено всё условие и произойдёт доступ по нулевой ссылке. Например,

if ((text == null && newText == null) || text.Equals(newText)) {
  ....
}

Это условие можно переписать, например, так

if ((text == null && newText == null) ||
    (text != null && newText != null && text.Equals(newText))) {
  ....
}

Ещё один способ допустить ошибку заключается в использовании оператора логического AND (&) вместо условного AND (&&). Нужно помнить о том что, во-первых, при использовании логического AND всегда вычисляются обе части выражения, а во-вторых приоритет у логического AND выше чем у условного AND.

Пример:

public static bool HasCookies {
  get {
    var context = HttpContext;
    return context != null
      && context.Request != null & context.Request.Cookies != null
      && context.Response != null && context.Response.Cookies != null;
  }
}

В этом примере обращение к context.Request.Cookies будет выполнено даже если context.Request равен null.

Также опасной является ситуация с разыменованием параметра, для которого значением по умолчанию является 'null'. Пример:

public NamedBucket(string name, List<object> items = null)
{
  _name = name;

  foreach (var item in items)
  {
    ....
  }
}

Конструктор принимает коллекцию 'items' в качестве необязательного параметра. Однако если при вызове значение для 'items' не будет передано, то при попытке обхода коллекции в 'foreach' будет выброшено исключение типа 'NullReferenceException'.

В зависимости от ситуации решение этой проблемы может отличаться. Например, можно производить обход коллекции только в случае, если она не равна 'null'.

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки разыменования нулевого указателя/нулевой ссылки [* см. примечание касательно языков C#, Java].

Данная диагностика классифицируется как:

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V3080.