# V3125. The object was used after it was verified against null. Check lines: N1, N2.

Анализатор обнаружил потенциальную ошибку, которая может привести к доступу по нулевой ссылке.

Анализатор заметил в коде следующую ситуацию. Сначала объект проверяется на null, а потом используется уже без проверки на null. Это может означать одно из двух:

1) Возникнет исключение, если объект будет равен null.

2) Программа всегда работает корректно, так как объект всегда не равен null. Проверка является лишней.

Рассмотрим первый вариант. Здесь может возникнуть исключение.

    obj = Foo();
    if (obj != null)
      obj.Func1();
    obj.Func2();

Если объект 'obj' окажется равен null, то выражение 'obj.Func2()' приведёт к ошибке. Анализатор выдаст предупреждение на этот код, указав 2 строки. Первая строка - это то место, где используется объект. Вторая строка - это то место, где объект сравнивается со значением null.

Исправленный вариант кода:

    obj = Foo();
    if (obj != null) {
      obj.Func1();
      obj.Func2();
    }

Рассмотрим второй вариант. Проход по списку безопасный, проверка лишняя

    List<string> list = CreateNotEmptyList();
    if (list == null || list.Count == 0) { .... }
    foreach (string item in list) { .... }

Этот код всегда работает корректно. Список list всегда не пуст. Однако анализатор не разобрался в этой ситуации и выдал предупреждение. Чтобы оно исчезло, следует удалить проверку "if (list == null || list.Count == 0)". Она не имеет практического смысла и может только запутать программиста, читающего код.

Исправленный вариант:

    List<string> list = CreateNotEmptyList();
    foreach (string item in list) { .... }

Ещё один вариант сообщения анализатора - когда проверка и использование расположены в разных ветках if\else или switch выражений. Например:

    if (lines.Count == 1)
    {
        if (obj != null)
            obj.Func1();
    }
    else
    {
        lines.Clear();
        obj.Func2();
    }

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

Исправленный вариант:

    if (lines.Count == 1)
    {
        if (obj != null)
            obj.Func1();
    }
    else
    {
        lines.Clear();
        if (obj != null)
            obj.Func2();
    }

В случае если анализатор ошибается, то кроме изменения кода, можно использовать комментарий для подавления предупреждений. Пример: "obj.Foo(); //-V3125".

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

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

CWE-476

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