C ++ Возможное разыменование нулевого указателя - PullRequest
4 голосов
/ 17 декабря 2010

Я запустил cppcheck над некоторым кодом, чтобы найти возможные ошибки во время выполнения. И он сообщает о возможном разыменовании нулевого указателя в следующей ситуации:

Foo* x = ... //defined somewhere

...

Foo* y(x); //possible null pointer dereference.

Редактировать: лучший пример

for( int i = 0; i < N; i++ )
{
    Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
    if( !x )                                         // line 4
        continue;
}

Сообщение об ошибке от cppcheck:

[C: \ file.cpp: 3]: (ошибка) Возможно, ноль разыменование указателя: x - иначе избыточно, чтобы проверить, является ли х нулевым в строка 4

Но я не понимаю, как это возможно.

Ответы [ 3 ]

3 голосов
/ 18 декабря 2010

Я очень удивлен, что вы получили это предупреждение.Для меня это работает с точностью до наоборот.Использование cppcheck 1.46.1, скомпилированного из исходников Linux.Это нормально:

struct Foo {
  int x;
};

struct Obj {
  Foo *FooPtr;
};

#define N 10

static Obj ArrayOfObjsContainingFooPtr[N];

int main() {
  for( int i = 0; i < N; i++ ) {
    Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
    if( !x )                                         // line 4
      continue;
  }
}

Теперь, с этим телом цикла, оно также "нормально" в соответствии с cppcheck, хотя оно и вызывает ошибку, если я на самом деле пытаюсь его запустить, очевидно:

Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
if (x->x == 0)
  break;
if( !x )                                         // line 4
  continue;

Даже это "отлично":

int main() {
  Foo *p = 0;
  if (p->x == 0)
    return 1;

И, наконец, генерируется "возможный" разыменование нулевого указателя.Возможно, верно:

int main() {
  Foo *p = 0;
  p->x = 0;

Самое смешное, что это, будучи полностью эквивалентным более раннему примеру, дает определенный (не «возможный») разыменование нулевого указателя:

int main() {
  Foo *p = 0;
  if ((*p).x == 0)
    return 1;

Вывод: cppcheck - действительно глючный инструмент.

1 голос
/ 17 декабря 2010

Возьмите следующее:

Foo* x = ptr_foo; //ptr_foo is defined earlier in the code.

Но что, если ptr_foo было записано в другой точке программы, в другом файле? Например, скажем, что в someotherfile.c вы найдете:

ptr_null = 0;

Тогда вполне возможно, что Foo* x = ptr_foo; может вызвать плохое mojo, когда вызывается y(x), если y разыменовывает x.

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

Если вы действительно хотите убедиться, что вы не столкнетесь с нулевой ссылкой, вы можете попробовать что-то вроде:

Foo* x = 0;
if(ptr_foo != 0){
    x = ptr_foo;
}else{
    x = //something else
}
0 голосов
/ 19 июня 2015

Просто завершение к посту Сергея Таченова:

 Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
if (x->x == 0)
 break;
if( !x )                                         // line 4
 continue;

Теперь этот файл корректно обнаруживается cppcheck:

 $ cppcheck --enable=all nullptrderef9.cpp 
 Checking nullptrderef9.cpp...
 [nullptrderef9.cpp:20] -> [nullptrderef9.cpp:22]: (warning) Possible null pointer dereference: x - otherwise it is redundant to check it against null.

Также корректно обнаруживается следующий пример:

int main() {
  Foo *p = 0;
  if (p->x == 0)
  return 1;
}

Вот вывод из cppcheck:

 $ cppcheck --enable=all nullptrderef10.cpp 
 Checking nullptrderef10.cpp...
 [nullptrderef10.cpp:19]: (error) Possible null pointer dereference: p

Даже следующий пример демонстрирует, что Cppcheck работает должным образом:

 int main()
 {
    Foo *p = 0;
    if ((*p).x == 0)
       return 1;
 }

Вот вывод:

$ cppcheck --enable=all nullptrderef11.cpp
  Checking nullptrderef11.cpp...
  [nullptrderef11.cpp:18]: (error) Possible null pointer dereference: p
  [nullptrderef11.cpp:18]: (error) Null pointer dereference
...