2010-12-17 51 views
4

我在某些代码上运行了cppcheck以查找可能的运行时错误。而且它报告与下面的情况可能的空指针引用:从cppcheck更好的例子C++可能的空指针解引用

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

错误消息:

[C:\ file.cpp

Foo* x = ... //defined somewhere 

... 

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

编辑:3] :(错误)可能的空 指针解除引用:x - 否则它 冗余以检查x是否为空 第4行

但我不明白这是可能的。

+3

你可以发布一个更完整的例子吗?我怀疑存在导致这种情况的代码路径。请注意,静态代码分析工具并不完美,这可能是误报。 – 2010-12-17 20:08:45

+0

更新的原始问题 – Glaeken 2010-12-17 20:27:25

+0

这些例子都没有解引用x。 – 2010-12-17 22:17:48

回答

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 
} 
+0

替代(恕我直言更清洁)版本的代码示例:'Foo * x = ptr_foo? ptr_foo:/ *别的东西* /;' – 2010-12-17 20:18:55

+0

不,从来没有任何可能性,“Foo * x = ptr_foo;可能是不好的mojo”。这是一个指针副本,而不是取消引用。 – 2010-12-17 20:21:49

+0

这就是我在想安德鲁 – Glaeken 2010-12-17 20:26:33

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虽然它出现segfaults如果我真的尝试运行它,很明显:

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是一个非常有用的工具。

+0

+1:用于演示此工具中与该问题高度相关的许多错误,显然不是很难找到。 – rubenvb 2010-12-18 12:08:36

+0

更不用说慢... – 2010-12-18 12:49:12

0

只是一次总结,从谢尔盖Tachenov帖子:

$ 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. 

也是正确检测到下一个例子:

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

这一个是现在正确地cppcheck检测

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