c ++可能的空指针取消引用

时间:2010-12-17 20:05:07

标签: c++ pointers dereference cppcheck

我在某些代码上运行了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] :(错误)可能为null   指针取消引用:x - 否则它   检查x是否为空是多余的   第4行

但我不知道这是怎么可能的。

3 个答案:

答案 0 :(得分:3)

我很惊讶你得到了那个警告。对我来说,它恰恰相反。使用从Linux中的源代码编译的cppcheck 1.46.1。这很好:

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 :(得分:1)

采取以下措施:

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

但是,如果ptr_foo被写入程序中的另一个点,在另一个文件中呢?例如,假设您在someotherfile.c找到:

ptr_null = 0;

如果Foo* x = ptr_foo;取消引用y(x),那么y完全有可能在调用x时导致错误的魔力。

根据我的经验,静态分析工具往往会报告大量误报,因为他们没有关于该程序的任何状态信息。

如果你真的想要确保你不会遇到空指针引用,你可以尝试这样的事情:

Foo* x = 0;
if(ptr_foo != 0){
    x = ptr_foo;
}else{
    x = //something else
}

答案 2 :(得分:0)

刚刚接受Sergey Tachenov发表的帖子:

 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