﻿# V595\. Pointer was used before its check for nullptr\. Check lines: N1, N2\.

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

Анализатор заметил в коде следующую ситуацию\. В начале, указатель используется\. А уже затем этот указатель проверяется на значение NULL\. Это может означать одно из двух:

1\) Возникнет ошибка, если указатель будет равен NULL\.

2\) Программа всегда работает корректно, так как указатель всегда не равен NULL\. Проверка является лишней\.

Рассмотрим первый вариант\. Ошибка есть\.

```cpp
buf = Foo();
pos = buf->pos;
if (!buf) return -1;
```

Если указатель 'buf' окажется равен NULL, то выражение 'buf\-\>pos ' приведёт к ошибке\. Анализатор выдаст предупреждение на этот код, указав 2 строки\. Первая строка \- это то место, где используется указатель\. Вторая строка \- это то место, где указатель сравнивается со значением NULL\.

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

```cpp
buf = Foo();
if (!buf) return -1;
pos = buf->pos;
```

Рассмотрим второй вариант\. Ошибки нет\.

```cpp
void F(MyClass *p)
{
  if (!IsOkPtr(p))
    return;
  printf("%s", p->Foo());
  if (p) p->Clear();
}
```

Этот код всегда работает корректно\. Указатель всегда не равен NULL\. Однако анализатор не разобрался в этой ситуации и выдал предупреждение\. Чтобы оно исчезло, следует удалить проверку "if \(p\)"\. Она не имеет практического смысла и только может запутать программиста, читающего код\.

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

```cpp
void F(MyClass *p)
{
  if (!IsOkPtr(p))
    return;
  printf("%s", p->Foo());
  p->Clear();
}
```

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

**Примечание N1\.**

Некоторые пользователи сообщают, что анализатор выдает предупреждение V595 на корректный код, Пример:

```cpp
static int Foo(int *dst, int *src)
{
  *dst = *src; // V595 !
  if (src == 0)
    return 0;
  return Foo(dst, src);
}
...
int a = 1, b = 2;
int c = Foo(&a, &b);
```

Да, здесь анализатор выдает ложное срабатывание\. Код корректен и указатель 'src' не может быть равен NULL в тот момент, когда выполняется присваивание "\*dst \= \*src"\. Возможно, в дальнейшем мы реализуем исключение для подобных случаев, но пока не спешим это делать\. Хотя здесь нет ошибки, анализатор выявил избыточность кода\. Функцию можно сократить\. При этом пропадет предупреждение V595, а код станет проще\.

Улучшенный вариант:

```cpp
int Foo(int *dst, int *src)
{
  assert(dst && src);
  *dst = *src;
  return Foo(dst, src);
}
```

**Примечание N2\.**

Иногда в программах можно встретить код следующего вида:

```cpp
int *x=&p->m_x;   //V595
if (p==NULL) return(OV_EINVAL);
```

Вычисляется указатель на член класса\. Этот указатель не разыменовывается и кажется, что анализатор зря выдаёт диагностическое сообщение V595\. Однако, этот код приводит к неопределённому поведению\. Если программа работает, это везение и не более того\. Нельзя вычислять выражение, если "&p\-\>m\_x", если указатель 'p' равен нулю\.

С аналогичной ситуацией программист может встретиться, желая отсортировать массив:

```cpp
int array[10];
std::sort(&array[0], &array[10]); // Undefined behavior
```

Использование &array\[10\] приводит к неопределенному поведению, так как элемент array\[10\] уже лежит за границами массива\. Но использование арифметики указателей вполне допустимо\. Можно обратиться к указателю, который адресует конечный элемент массива\. Поэтому, необходимо написать следующий корректный код:

```cpp
int array[10];
std::sort(array, array+10); //ok
```

## Дополнительные материалы

1. Андрей Карпов\. [Пояснение про диагностику V595](https://pvs-studio.ru/ru/blog/posts/cpp/0353/)\.