我在某些代码上运行了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行
但我不知道这是怎么可能的。
答案 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