Oracle® Solaris Studio 12.4: コードアナライザユーザーズガイド

印刷ビューの終了

更新: 2014 年 10 月
 
 

コードアナライザで分析されるエラー

コンパイラ、discover、および uncover は、コード内の静的コードの問題、動的メモリーアクセスの問題、およびカバレージの問題を検出します。この付録では、これらのツールで検出され、コードアナライザで分析される特有のエラーの種類について説明します。

コードカバレージの問題

コードカバレージ検査では、カバーされていない関数が特定されます。結果では、見つかったコードカバレージの問題に「カバーされていない関数」というラベルが付けられ、潜在的なカバレージの割合が示されます。この割合は、該当する関数をカバーするテストを追加した場合にアプリケーションの合計カバレージが何パーセント増加するかを示しています。

考えられる原因: 関数を実行するテストが行われなかったか、デッドコードまたは古いコードを削除していません。

静的コードの問題

静的コード検査では、次の種類のエラーが検出されます。

  • ABR: 配列境界を越える読み取り (beyond array bounds read)

  • ABW: 配列境界を越える書き込み (beyond array bounds write)

  • DFM: メモリーの二重解放 (double freeing memory)

  • ECV: 明示的型キャスト違反 (explicit type cast violation)

  • FMR: 解放済みメモリーの読み取り (freed memory read)

  • FMW: 解放済みメモリーの書き込み (freed memory write)

  • INF: 空の無限ループ (infinite empty loop)

  • MLK: メモリーリーク (memory leak)

  • MFR: 関数の復帰なし (missing function return)

  • MRC: malloc 戻り値の検査なし (missing malloc return value check)

  • NFR: 初期化されていない関数の復帰 (uninitialized function return)

  • NUL: NULL ポインタ間接参照、リークの可能性があるポインタの検査

  • RFM: 解放済みメモリーを返す (return freed memory)

  • UMR: 初期化されていないメモリーの読み取り、初期化されていないメモリーの読み取りビット操作 (uninitialized memory read, uninitialized memory read bit operation)

  • URV: 使用されていない戻り値 (unused return value)

  • VES: スコープ外での局所変数の使用 (out-of-scope local variable usage)

このセクションでは、エラーの考えられる原因と、エラーが発生する可能性があるコードの例を説明します。

配列境界を越える読み取り (ABR)

考えられる原因: 配列境界を越えてメモリーを読み取ろうとしました。

例:

    int a[5];
    . . .
    printf("a[5] = %d\n",a[5]);  // Reading memory beyond array bounds

配列境界を越える書き込み (ABW)

考えられる原因: 配列境界を越えてメモリーに書き込もうとしました。

例:

    int a [5];
     . . .
     a[5] = 5; // Writing to memory beyond array bounds

メモリーの二重解放 (DFM)

考えられる原因: 同じポインタを使用して free()() を複数回呼び出しました。C++ では、同じポインタに対して delete 演算子を 2 回以上使用しています。

例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .       // p was not signed a new value between the free statements
     free(p); // Double freeing memory

解放済みメモリーの読み取り (FMR)

例:

    int *p = (int*) malloc(sizeof(int));
    free(p);
    . . .  // Nothing assigned to p in between
    printf("p = 0x%h\n",p); // Reading from freed memory 

解放済みメモリーの書き込み (FMW)

例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .        // Nothing assigned to p in between
     *p = 1; // Writing to freed memory 

空の無限ループ (INF)

例:

    int x=0;
    int i=0;
    while (i200) {
      x++; } // Infinite loop 

メモリーリーク

考えられる原因: メモリーが割り当てられるが、関数の終了またはエスケープの前に解放されていません。

例:

    int foo()
    {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
      }  
    }                                      // The 2nd malloc leaked here

関数の復帰なし (MFR)

考えられる原因: 終了するパスの一部に戻り値がありません。

例:

    #include <stdio.h>
    int foo (int a, int b) 
    {
      if (a) 
        { 
           return b; 
        }
    }            // If foo returns here, the return is uninitialized
    int main ( )
    {
        printf("%d\n", foo(0,30));
    }

malloc 戻り値の検査なし (MRC)

考えられる原因: Cの malloc または C++ の new 演算子からの戻り値に null 検査なしでアクセスします。

例:

    #include <stdlib.h>
    int main()
    {
     int *p3 = (int*) malloc(sizeof(int)); // Missing null-pointer check after malloc.
     *p3 = 0;
    }  

リークの可能性があるポインタの検査: NULL ポインタ間接参照 (NUL)

考えられる原因: null に等しくなる可能性のあるポインタにアクセスしているか、null になることのないポインタに冗長な null 検査を行なっています。

例:

    #include <stdio.h>
    #include <stdlib.h>
    int gp, ctl;
    int main()
    {
     int *p = gp;
     if (ctl)
      p = 0;
     printf ("%c\n", *p); // May be null pointer dereference
     if (!p)
      *p = 0; // Surely null pointer dereference

    int *p2 = gp;
    *p2 = 0; // Access before checking against NULL. 
    assert (p2!=0);

    int *p3 = gp;
    if (p3) {
      printf ("p3 is not zero.\n");
    }
    *p3 = 0; // Access is not protected by previous check against NULL. 
    }

解放済みメモリーを返す (RFM)

例:

    #include <stdlib.h>
    int *foo ()
    {
     int *p = (int*) malloc(sizeof(int));
     free(p);
     return p; // Return freed memory is dangerous
    }
    int main()
    {
     int *p = foo();
     *p = 0;
    }

初期化されていないメモリーの読み取り (UMR)

考えられる原因: 初期化されていないローカルデータまたはヒープデータの読み取り。

例:

    #include <stdio.h>
    #include <stdlib.h>
     struct ttt {
        int a: 1;
        int b: 1;
     };

     int main()
     {
       int *p = (int*) malloc(sizeof(int));
       printf("*p = %d\n",*p); // Accessing uninitialized data 

       struct ttt t;
       extern void foo (struct ttt *);

       t.a = 1;
       foo (&t); // Access uninitialized bitfield data "t.b"
     }

使用されていない戻り値 (URV)

考えられる原因: 初期化されていないローカルデータまたはヒープデータの読み取り。

例:

    int foo();
   int main()
   {
      foo(); // Return value is not used.
   }

スコープ外での局所変数の使用 (VES)

考えられる原因: 初期化されていないローカルデータまたはヒープデータの読み取り。

例:

    int main() 
   {
      int *p = (int *)0;
      void bar (int *);
      {
        int a[10];
        p = a;
      } // local variable 'a' leaked out
      bar(p);
    }

動的メモリーアクセスエラー

動的メモリーアクセス検査では、次の種類のエラーが検出されます。

  • ABR: 配列境界を越える読み取り (beyond array bounds read)

  • ABW: 配列境界を越える書き込み (beyond array bounds write)

  • BFM: 不正な空きメモリー (bad free memory)

  • BRP: 不正な realloc アドレスパラメータ (bad realloc address parameter)

  • CGB: 破損したガードブロック (corrupted guard block)

  • DFM: メモリーの二重解放 (double freeing memory)

  • FMR: 解放済みメモリーの読み取り (freed memory read)

  • FMW: 解放済みメモリーの書き込み (freed memory write)

  • FRP: 解放済み realloc パラメータ (freed realloc parameter)

  • IMR: 無効なメモリーの読み取り (invalid memory read)

  • IMW: 無効なメモリーの書き込み (invalid memory write)

  • MLK: メモリーリーク (memory leak)

  • OLP: 送り側と受け側の重複 (overlapping source and destination)

  • PIR: 部分的に初期化された読み取り (partially initialized read)

  • SBR: スタック境界を越える読み取り (beyond stack bounds read)

  • SBW: スタック境界を越える書き込み (beyond stack bounds write)

  • UAR: 割り当てられていないメモリーの読み取り (unallocated memory read)

  • UAW: 割り当てられていないメモリーの書き込み (unallocated memory write)

  • UMR: 初期化されていないメモリーの読み取り (uninitialized memory read)

このセクションでは、エラーの考えられる原因と、エラーが発生する可能性があるコードの例を説明します。

配列境界を越える読み取り (ABR)

考えられる原因: 配列境界を越えてメモリーを読み取ろうとしました。

例:

    int a[5];
    . . .
    printf("a[5] = %d\n",a[5]);  // Reading memory beyond array bounds

配列境界を越える書き込み (ABW)

考えられる原因: 配列境界を越えてメモリーに書き込もうとしました。

例:

    int a [5];
     . . .
     a[5] = 5; // Writing to memory beyond array bounds

不正な空きメモリー (BFM)

考えられる原因: free()() または realloc()() にヒープデータ以外のポインタを渡しました。

例:

    #include <stdlib.h>
    int main()
    {
     int *p = (int*) malloc(sizeof(int));
     free(p+1); // Freeing wrong memory block
    }

不正な Realloc アドレスパラメータ (BRP)

例:

    #include <stdlib.h>
    int main()
    {
     int *p = (int*) realloc(0,sizeof(int));
     int *q = (int*) realloc(p+20,sizeof(int[2])); // Bad address parameter for realloc 
    }

破損したガードブロック (CGB)

考えられる原因: 動的に割り当てられた配列の末尾を越えて「レッドゾーン」に書き込んでいます。

例:

    #include <stdio.h>
    #include <stdlib.h>

    int main() {
     int *p = (int *) malloc(sizeof(int)*4);
     *(p+5) = 10; //  Corrupted array guard block detected (only when the code is not annotated)
     free(p);

     return 0;
    }

メモリーの二重解放 (DFM)

考えられる原因: 同じポインタを使用して free()() を複数回呼び出しました。C++ では、同じポインタに対して delete 演算子を 2 回以上使用しています。

例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .       // p was not assigned a new value between the free statements
     free(p); // Double freeing memory

解放済みメモリーの読み取り (FMR)

例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .  // Nothing assigned to p in between
     printf("p = 0x%h\n",p); // Reading from freed memory

解放済みメモリーの書き込み (FMW)

例:

    int *p = (int*) malloc(sizeof(int));
     free(p);
     . . .        // Nothing assigned to p in between
     *p = 1; // Writing to freed memory 

解放済み Realloc パラメータ (FRP)

例:

   #include <stdlib.h>

   int main() {
     int *p = (int *) malloc(sizeof(int));
     free(0);
     int *q = (int*) realloc(p,sizeof(it[2])); //Freed pointer passed to realloc
   }

無効なメモリーの読み取り (IMR)

考えられる原因: ハーフワード境界、ワード境界、またはダブルワード境界に整列していないアドレスから、それぞれ 2、4、または 8 バイトを読み取っています。

例:

    #include <stdlib.h>
    int main()
    {  
      int *p = 0;
      int i = *p;   // Read from invalid memory address 
    }

無効なメモリーの書き込み (IMW)

考えられる原因: ハーフワード境界、ワード境界、またはダブルワード境界に整列していないアドレスに、それぞれ 2、4、または 8 バイトを書き込んでいます。テキストアドレスに書き込んでいるか、読み取り専用データセクション (.rodata) に書き込んでいるか、mmap によって読み取り専用にされているページに書き込んでいます。

例:

     int main()
   {
     int *p = 0;
     *p = 1;  // Write to invalid memory address 
   }

メモリーリーク

考えられる原因: メモリーが割り当てられるが、関数の終了またはエスケープの前に解放されていません。

例:

       int foo()
   {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
     }  
   }                                      // The 2nd malloc leaked here

送り側と受け側の重複 (OLP)

考えられる原因: 正しくないソース、宛先、または長さが指定されました。ソースと宛先が重複している場合、プログラムの動作は不定になります。

例:

    #include <stlib.h>
    #include <string.h>
    int main() {
      char *s=(char *) malloc(15);
      memset(s, 'x', 15);
      memcpy(s, s+5, 10);
      return 0;
    }

部分的に初期化された読み取り (PIR)

例:

    #include <stdio.h>
   #include <stdlib.h>
    int main()
   { 
     int *p = (int*) malloc(sizeof(int));
     *((char*)p) = 'c';
     printf("*(p = %d\n",*(p+1)); // Accessing partially initialized data 
   }

スタック境界を越える読み取り (SBR)

考えられる原因: ローカル配列の末尾よりあと、または先頭より前を読み取っています。

例:

    #include <stdio.h>

   int main() {
     int a[2] = {0, 1};
     printf("a[-10]=%d\n",a[-10]); //  Read is beyond stack frame bounds

     return 0;
   }

スタック境界を越える書き込み (SBW)

考えられる原因: ローカル配列の末尾よりあと、または先頭より前に書き込んでいます。

例:

    #include <stdio.h>

    int main() {
     int a[2] = {0, 1};
     a[-10] = 2; //  Write is beyond stack frame bounds

     return 0;
   }

割り当てられていないメモリーの読み取り (UAR)

考えられる原因: ストレイポインタ (不正な値を持つポインタ)、ヒープブロック境界のオーバーフロー、すでに解放されたヒープブロックへのアクセス。

例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
     int *p = (int*) malloc(sizeof(int));
     printf("*(p+1) = %d\n",*(p+1)); // Reading from unallocated memory
   }

割り当てられていないメモリーの書き込み (UAW)

考えられる原因: ストレイポインタ (不正な値を持つポインタ)、ヒープブロック境界のオーバーフロー、すでに解放されたヒープブロックへのアクセス。

例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
    int *p = (int*) malloc(sizeof(int)); 
     *(p+1) = 1; // Writing to unallocated memory 
  }

初期化されていないメモリーの読み取り (UMR)

考えられる原因: 初期化されていないローカルデータまたはヒープデータの読み取り。

例:

    #include <stdio.h>
    #include <stdlib>
   int main()
   {
    int *p = (int*) malloc(sizeof(int));
    printf("*p = %d\n",*p); // Accessing uninitialized data
  }

動的メモリーアクセスの警告

動的メモリーアクセス検査では、次の種類の警告が検出されます。

  • AZS: 0 サイズの割り当て (allocating zero size)

  • メモリーリーク

  • SMR: 投機的な非初期化メモリーからの読み取り (speculative uninitialized memory read)

このセクションでは、警告の考えられる原因と、警告が発生する可能性があるコードの例を説明します。

サイズ 0 の割り当て (AZS)

例:

    #include <stdlib>
    int main()
    {
      int *p = malloc(); // Allocating zero size memory block
    }

メモリーリーク (MLK)

考えられる原因: メモリーが割り当てられるが、関数の終了またはエスケープの前に解放されていません。

例:

    int foo()
    {
     int *p = (int*) malloc(sizeof(int));
     if (x) {
      p = (int *) malloc(5*sizeof(int));  // will cause a leak of the 1st malloc
     }  
    }                                     // The 2nd malloc leaked here

投機的なメモリーの読み取り (SMR)

例:

    int i;
    if (foo(&i) != 0)  /* foo returns nonzero if it has initialized i */
    printf("5d\n", i);

コンパイラは、前述のソースに対して次の同等のコードを生成する可能性があります。

    int i;
    int t1, t2'
    t1 = foo(&i);
    t2 = i; /* value in i is loaded. So even if t1 is 0, we have uninitialized read due to speculative load */
    if (t1 != 0) 
    printf("%d\n", t2);