CXX.ERRNO.NOT_SET

ライブラリ関数を呼び出す前に、errno はゼロにリセットされていない

CXX.ERRNO.NOT_SET チェッカーは、ライブラリ関数を呼び出す前に、errno の値がゼロにリセットされていないケースにフラグを立てます。

脆弱性とリスク

errno の値は、ライブラリ関数の以前の呼び出しによって間違って設定される可能性があります。コードがライブラリ関数を最初にリセットせずに呼び出した後に errno の値をチェックする場合、コードは間違って実行される可能性があります。

軽減と防止

errno の値を設定するライブラリ関数を呼び出す前に、errno の値を常にゼロにリセットします。

脆弱コード例 1

コピー
  #include <errno.h>
  #include <limits.h>
  #include <stdlib.h>
    
  void func(const char *c_str) {
    unsigned long number;
    char *endptr;
     
    number = strtoul(c_str, &endptr, 0);
   if (errno == ERANGE) {
     /* Handle error */
   } else {
     /* Computation succeeded */
   }
 }

この準拠していない例では、コードは strtoul() を呼び出す前に、errno の値をゼロに設定することに失敗します。エラーが発生した場合、strtoul() は有効な値 (ULONG_MAX) を返すため、strtoul() が正常に実行されたかどうかを判断する唯一の手段は errno になります。

修正コード例 1

コピー
  #include <errno.h>
  #include <limits.h>
  #include <stdlib.h>
    
  void func(const char *c_str) {
    unsigned long number;
    char *endptr;
    
    errno = 0;
   number = strtoul(c_str, &endptr, 0);
   if (errno == ERANGE) {
     /* Handle error */
   } else {
     /* Computation succeeded */
   }
 }

この修正された例では、コードは strtoul() を呼び出す前に errno の値をゼロに設定し、呼び出した後に errno の値を検査します。

脆弱コード例 2

コピー
  #include <errno.h>
  #include <stdio.h>
    
  void func(const char *filename) {
    FILE *fileptr;
   
    errno = 0;
    fileptr = fopen(filename, "rb");
    if (errno != 0) {
     /* Handle error */
   }
 }

この準拠していない例では、エラーが発生しても fopen() は errno の値を設定しない場合があるため、コードはエラーを診断することに失敗する可能性があります。

修正コード例 2

コピー
  #include <stdio.h>
    
  void func(const char *filename) {
    FILE *fileptr = fopen(filename, "rb");
    if (fileptr == NULL)  {
      /* An error occurred in fopen() */
    }

C 標準では、fopen() を説明するときに errno については何も言及していません。この準拠している例では、コードは fopen() を呼び出した結果を使用して失敗を判断しており、errno の値をチェックしません。

拡張機能

このチェッカーは、Klocwork ナレッジベース (KB) を利用して拡張できます。詳細については、C/C++ 解析のチューニングを参照してください。