问题
I ran cppcheck over some code to look for possible runtime errors. And it is reporting a possible null pointer dereference with the following situation:
Foo* x = ... //defined somewhere
...
Foo* y(x); //possible null pointer dereference.
Edit: Better example
for( int i = 0; i < N; i++ )
{
Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
if( !x ) // line 4
continue;
}
Error message from cppcheck:
[C:\file.cpp:3]: (error) Possible null pointer dereference: x - otherwise it is redundant to check if x is null at line 4
But I don't see how this is possible.
回答1:
I am really surprised that you got that warning. For me, it works exactly the opposite. Using cppcheck 1.46.1 compiled from sources in Linux. This is fine:
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;
}
}
Now, with this loop body it is also "fine" according to cppcheck although it segfaults if I actually try to run it, obviously:
Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
if (x->x == 0)
break;
if( !x ) // line 4
continue;
Even this is "fine":
int main() {
Foo *p = 0;
if (p->x == 0)
return 1;
And this finally generates "possible" null pointer dereference. Possible, right:
int main() {
Foo *p = 0;
p->x = 0;
The funny thing is that this, while being completely equivalent to an earlier example, gives definite (not "possible") null pointer dereference:
int main() {
Foo *p = 0;
if ((*p).x == 0)
return 1;
The conclusion: cppcheck is a really buggy tool.
回答2:
Take the following:
Foo* x = ptr_foo; //ptr_foo is defined earlier in the code.
But what if ptr_foo
was written to at another point in the program, in another file? For example, let's say that in someotherfile.c
you find:
ptr_null = 0;
Then it is entirely possible that Foo* x = ptr_foo;
could cause bad mojo, when y(x)
is called, if y
dereferences x
.
From my experience, static analysis tools tend to report a large number of false positives, because they do not have any state information about the program.
If you really want to make sure you won't run into a null pointer reference, you could try something like:
Foo* x = 0;
if(ptr_foo != 0){
x = ptr_foo;
}else{
x = //something else
}
回答3:
Just a wrap up to the post from Sergey Tachenov:
Foo* x( ArrayOfObjsContainingFooPtr[i].FooPtr ); // line 3
if (x->x == 0)
break;
if( !x ) // line 4
continue;
This one is now correctly detected by 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.
Also the next example is detected correctly:
int main() {
Foo *p = 0;
if (p->x == 0)
return 1;
}
Here is the output from cppcheck:
$ cppcheck --enable=all nullptrderef10.cpp
Checking nullptrderef10.cpp...
[nullptrderef10.cpp:19]: (error) Possible null pointer dereference: p
Even the next example demonstrates that Cppcheck works as expected:
int main()
{
Foo *p = 0;
if ((*p).x == 0)
return 1;
}
Here is the output:
$ cppcheck --enable=all nullptrderef11.cpp
Checking nullptrderef11.cpp...
[nullptrderef11.cpp:18]: (error) Possible null pointer dereference: p
[nullptrderef11.cpp:18]: (error) Null pointer dereference
来源:https://stackoverflow.com/questions/4474357/c-possible-null-pointer-dereference