CERT.STDLIB.SIGNAL

SIGFPE、SIGBUS、SIGSEGV、SIGILL、SIGEMT、または SIGTRAP に関する計算例外シグナルハンドラーから戻ると、未定義の動作を引き起こします。

CERT.STDLIB.SIGNAL チェッカーは、SIGFPE、SIGBUS、SIGSEGV、SIGILL、SIGEMT、および SIGTRAP に関する計算例外シグナルハンドラーから戻るとフラグを立てます。このチェッカーは、指定されたいずれかのシグナルタイプである場合に、signal() のすべての呼び出しに欠陥としてフラグを立てます。このため、この欠陥は、必ずしも欠陥であるとは限りませんが、コードの行をレビューする必要があることを意味しているものとして解釈する必要があります。

脆弱性とリスク

プログラムが計算例外シグナルハンドラーから戻る場合の動作は未定義です。

軽減と防止

シグナルが SIGFPE、SIGBUS、SIGSEGV、SIGILL、SIGEMT、または SIGTRAP などの計算エラーの結果である場合は、シグナルハンドラーから戻らないでください。

脆弱コード例

コピー
     #include <errno.h>
     #include <limits.h>
     #include <signal.h>
     #include <stdlib.h>

     volatile sig_atomic_t denom;

     void sighandle(int s)
     {
        if (denom == 0) {
            denom = 1;
        }
    }

    int main(int argc, char *argv[])
    {
        if (argc < 2) {
            return 0;
        }

        char *end = NULL;
        long temp = strtol(argv[1], &end, 10);

        if (end == argv[1] || 0 != *end ||
            ((LONG_MIN == temp || LONG_MAX == temp) && errno == ERANGE)) {
            /* Handle error */
        }

        denom = (sig_atomic_t)temp;

        signal(SIGFPE, sighandle);  

        long result = 100 / (long)denom;
        return 0;
    }

この非準拠の例では、プログラムが計算シグナルハンドラーから戻っており、動作は未定義であるため、Klocwork は 31 行目で CERT.STDLIB.SIGNAL の欠陥を報告します。この非準拠のコード例は、入力 0 が与えられ、上記のプログラムがエラー状態を修正するためにシグナルハンドラー (シグナル SIGFPE による) を使用した後でもが期待どおりに動作しない場合、無限にループします。

修正コード例

コピー
     #include <errno.h>
     #include <limits.h>
     #include <signal.h>
     #include <stdlib.h>

     int main(int argc, char *argv[]) {
       if (argc < 2) {
         return 0;
       }

      char *end = NULL;
      long denom = strtol(argv[1], &end, 10);

      if (end == argv[1] || 0 != *end ||
          ((LONG_MIN == denom || LONG_MAX == denom) && errno == ERANGE)) {
        /* Handle error */
      }

      long result = 100 / denom;
      return 0;
    }

上記のコードは、プログラムが SIGFPE ハンドラーから戻っておらず、代わりに abort()、quick_exit()、または Exit 関数を呼び出しているため、準拠しています。

関連チェッカー

  • MISRA.STDLIB.SIGNAL

外部参考資料