c++ Possible null pointer dereference
Asked Answered
A

3

4

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.

Anaemia answered 17/12, 2010 at 20:5 Comment(3)
Can you post a more complete example? I suspect there is a code path that leads to this situation. Note that static code analysis tools are not perfect and this might be a false positive.Overside
Neither of those examples dereference x.Challah
your examples are still not complete. Can you post minimal compilable code? The code above CAN cause null pointer dereferencing.Ster
C
3

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.

Chiromancy answered 18/12, 2010 at 11:29 Comment(1)
+1: for demonstrating the numerous faults in this tool that are highly relevant to the question and apparently not very hard to find.Downtime
A
1

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
}
Arda answered 17/12, 2010 at 20:14 Comment(4)
Alternate (IMHO cleaner) version of your code sample: Foo* x = ptr_foo ? ptr_foo : /* something else */;Telangiectasis
No, there is never any possibility that "Foo* x = ptr_foo; could be bad mojo". It's a pointer copy, not a dereference.Alver
This is what I was thinking AndrewAnaemia
@Andrew: if "Foo* x = ptr_foo; //where ptr_foo = 0", then calling "y(x) //assuming y dereferences x" will definitely be bad mojo. I see that I did not communicate that in my answer, so I updated my answer.Arda
C
0

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
Christie answered 19/6, 2015 at 6:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.