4

実行時エラーの可能性を探すために、いくつかのコードに対して cppcheck を実行しました。また、次の状況で null ポインター逆参照の可能性が報告されています。

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 - そうでない場合、4 行目で x が null かどうかを確認するのは冗長です

しかし、これがどのように可能かわかりません。

4

3 に答える 3

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;

面白いことに、これは以前の例と完全に同等ですが、明確な (「可能」ではない) null ポインターの逆参照が行われます。

int main() {
  Foo *p = 0;
  if ((*p).x == 0)
    return 1;

結論: cppcheck は本当にバグのあるツールです。

于 2010-12-18T11:29:45.807 に答える
1

次のようにします。

Foo* x = ptr_foo; //ptr_foo is defined earlier in the code.

しかしptr_foo、プログラムの別の場所、別のファイルに書き込まれた場合はどうなるでしょうか? たとえば、あなたが見つけたとしsomeotherfile.cましょう:

ptr_null = 0;

次に、 if dereferencesが呼び出されFoo* x = ptr_foo;たときに悪いモジョを引き起こす可能性は十分にあります。y(x)yx

私の経験から、静的分析ツールは、プログラムに関する状態情報を持っていないため、多数の誤検知を報告する傾向があります。

null ポインター参照に遭遇しないことを本当に確認したい場合は、次のようなことを試すことができます。

Foo* x = 0;
if(ptr_foo != 0){
    x = ptr_foo;
}else{
    x = //something else
}
于 2010-12-17T20:14:39.053 に答える
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
于 2015-06-19T06:58:13.903 に答える