メインコンテンツ

errno の不適切な使用

errno がエラー状態について正しくチェックされていない

説明

この欠陥は、errno をチェックしてもエラーがないことが保証されない状況で、errno でエラー状態をチェックした場合に発生します。場合によっては、errno をチェックすることによって誤検知につながる可能性があります。

たとえば、次の関数呼び出し後に errno をチェックします。

  • fopen: ISO® 規格に従う場合、この関数はエラーで errno を設定しない可能性があります。

  • atof: ISO 規格に従う場合、この関数は errno を設定しません。

  • signal: この関数が SIG_ERR エラー インジケーターを返す場合のみ、errno の値がエラーを示します。

リスク

ISO C 標準では、これらの関数は必ずしもエラーで errno を設定しません。関数が errno を設定するかどうかは、実装によって異なります。

エラーを検出するため errno のみをチェックする場合、このチェックの妥当性も実装によって異なります。

場合によっては、関数が特定のエラー インジケーターを返す場合のみ、errno の値がエラーを示します。関数の戻り値をチェックする前に errno をチェックする場合、誤検出が発生する可能性があります。

修正方法

エラーの検出方法の詳細は、その特定の関数のドキュメンテーションを参照してください。

通常、そのような関数はエラーを示すために帯域外エラー インジケーターを返します。次に例を示します。

  • fopen は、エラーが発生すると NULL ポインターを返します。

  • signal は、SIG_ERR エラー インジケーターを返し、errno に正の値を設定します。この関数の戻り値をチェックした後のみ errno をチェックします。

すべて展開する

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

#define fatal_error() abort()

const char *temp_filename = "/tmp/demo.txt";

FILE *func()
{
    FILE *fileptr;
    errno = 0;
    fileptr = fopen(temp_filename, "w+b");
    if (errno != 0) {
        if (fileptr != NULL) {
            (void)fclose(fileptr);
        }
        /* Handle error */
        fatal_error();
    }
    return fileptr;
}

この例では、errnofopen の呼び出し後にチェックされる最初の変数です。エラーが発生すると fopenerrno を非ゼロの値に変更すると想定しています。エラーで errno を設定しない fopen の実装を使ってこのコードを実行すると、エラー状態を見落とすことになります。この場合、fopen は検出をエスケープする NULL ポインターを返す可能性があります。

修正 — fopen 呼び出し後に戻り値をチェック

1 つの修正方法として、fopen の戻り値が NULL ポインターかどうかのみをチェックします。

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

#define fatal_error() abort()

const char *temp_filename = "/tmp/demo.txt";

FILE *func()
{
    FILE *fileptr;
    fileptr = fopen(temp_filename, "w+b");
    if (fileptr == NULL) { 
        fatal_error();
    }
    return fileptr;
}

結果情報

グループ: プログラミング
言語: C | C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: ERRNO_MISUSE
影響度: High

バージョン履歴

R2017a で導入