Анализатор обнаружил потенциальную ошибку, которая может привести к разыменовыванию нулевого указателя.
Анализатор заметил в коде следующую ситуацию. В начале, указатель используется. А уже затем этот указатель проверяется на значение NULL. Это может означать одно из двух:
1) Возникнет ошибка, если указатель будет равен NULL.
2) Программа всегда работает корректно, так как указатель всегда не равен NULL. Проверка является лишней.
Рассмотрим первый вариант. Ошибка есть.
buf = Foo();
pos = buf->pos;
if (!buf) return -1;
Если указатель 'buf' окажется равен NULL, то выражение 'buf->pos ' приведёт к ошибке. Анализатор выдаст предупреждение на этот код, указав 2 строки. Первая строка - это то место, где используется указатель. Вторая строка - это то место, где указатель сравнивается со значением NULL.
Исправленный вариант кода:
buf = Foo();
if (!buf) return -1;
pos = buf->pos;
Рассмотрим второй вариант. Ошибки нет.
void F(MyClass *p)
{
if (!IsOkPtr(p))
return;
printf("%s", p->Foo());
if (p) p->Clear();
}
Этот код всегда работает корректно. Указатель всегда не равен NULL. Однако анализатор не разобрался в этой ситуации и выдал предупреждение. Чтобы оно исчезло, следует удалить проверку "if (p)". Она не имеет практического смысла и только может запутать программиста, читающего код.
Исправленный вариант:
void F(MyClass *p)
{
if (!IsOkPtr(p))
return;
printf("%s", p->Foo());
p->Clear();
}
В случае если анализатор PVS-Studio ошибается, то кроме изменения кода, можно использовать комментарий для подавления предупреждений. Пример: "p->Foo(); //-V595".
Примечание.
Некоторые пользователи сообщают, что анализатор выдает предупреждение V595 на корректный код, Пример:
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);
Да, здесь PVS-Studio выдает ложное срабатывание. Код корректен и указатель 'src' не может быть равен NULL в тот момент, когда выполняется присваивание "*dst = *src". Возможно, в дальнейшем мы реализуем исключение для подобных случаев, но пока не спешим это делать. Хотя здесь нет ошибки, анализатор выявил избыточность кода. Функцию можно сократить. При этом пропадет предупреждение V595, а код станет проще.
Улучшенный вариант:
int Foo(int *dst, int *src)
{
assert(dst && src);
*dst = *src;
return Foo(dst, src);
}