2010-12-17 81 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