メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

MISRA C++:2008 Rule 0-3-2

If a function generates error information, then that error information shall be tested

説明

ルール定義

If a function generates error information, then that error information shall be tested. 1

根拠

戻り値でエラー情報を示す関数の戻り値をチェックしない場合、プログラムが予期しない動作をする可能性があります。これらの関数のエラーはプログラム全体に伝播し、不適切な出力、セキュリティの脆弱性およびシステム障害の原因となる可能性があります。

errno を設定する関数でエラーなしで関数呼び出しが完了したかどうかを確認するには、errno のエラー値をチェックします。このような errno を設定する関数の戻り値はエラーを示しません。戻り値は、以下のいずれかになります。

  • void

  • エラーが発生しても、戻り値は正常に行われた呼び出しと同じ値になる可能性があります。このような戻り値をインバンド エラー インジケーターと呼びます。たとえば、strtol は文字列を long 型整数に変換して、その整数を返します。変換結果がオーバーフローする場合、この関数は LONG_MAX を返し、errnoERANGE を設定します。ただし、この関数は正常に変換が行われても LONG_MAX を返すことがあります。errno をチェックすることでのみ、エラーと正常な変換を区別することができます。

errno を設定する関数でエラーが発生したかどうかは、errno をチェックすることでのみ判断できます。

Polyspace 実装

チェッカーは以下の場合に違反を報告します。

  • エラー発生の可能性に関する情報を返す、要注意の関数を呼び出した後、戻り値を無視するか、戻り値をテストせずに関数の出力を使用する。

    チェッカーは標準ライブラリに含まれる関数と、POSIX ライブラリや WinAPI ライブラリなどの他の有名なライブラリに含まれる関数に対応します。以下のような理由で関数の呼び出しでエラーが発生しやすい場合、Polyspace® はその関数を要注意と見なします。

    • システム リソースが使い尽くされた状態 (リソースを割り当てるときなど)。

    • 権限またはアクセス許可が変更された状態。

    • 外部ソースからのデータを読み取り、書き込みまたは変換する際にソースが汚染された状態。

    • 既存の API があってもサポートされない機能。

    Polyspace は、以下のような重要なタスクを実行する関数を、重要で要注意の関数と見なします。

    • 権限の設定 (setuid など)

    • jail の作成 (chroot など)

    • プロセスの作成 (fork など)

    • スレッドの作成 (pthread_create など)

    • ミューテックスのロックまたはロック解除 (pthread_mutex_lock など)

    • メモリ セグメントのロックまたはロック解除 (mlock など)

    重要ではない関数の場合、関数の戻り値を void にキャストすることによって明示的に戻り値を無視していれば、チェッカーはその関数にフラグを設定しません。重要で要注意の関数の場合、その戻り値を明示的に無視すると、Polyspace によってフラグが設定されます。

  • エラー状態を示すために errno を設定する関数を呼び出しても、その呼び出し後に errno をチェックしていない。このような関数の場合、エラーが発生したかどうかを判断するための唯一信頼できる方法は errno をチェックすることです。

    エラーで errno を設定する関数には次のものがあります。

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

#include <pthread.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <cstdlib>
#define fatal_error() abort()

void initialize_1() {
    pthread_attr_t attr;
    pthread_attr_init(&attr); //Noncompliant
}

void initialize_2() {
    pthread_attr_t attr;
   (void)pthread_attr_init(&attr); //Compliant
}

void initialize_3() {
    pthread_attr_t attr;
    int result;
    result = pthread_attr_init(&attr); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

int read_file_1(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r");   
  return 0; //Noncompliant
 
}
int read_file_2(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r"); //Compliant
  if (in==NULL){
	  // Handle error
  }
  return 0; 
}

この例は、要注意の関数 pthread_attr_init および fmemopen の呼び出しを示しています。Polyspace は、次の場合にフラグを設定します。

  • 要注意の関数の戻り値を暗黙的に無視している。要注意の関数の出力を明示的に無視している場合、フラグは設定されません。

  • 要注意の関数の戻り値を取得しているが、関連するスコープを抜ける前に戻り値をテストしていない。終了ステートメントに対して違反が報告されます。

準拠するには、関数の戻り値を void に明示的にキャストするか、戻り値をテストしてエラーがないかチェックします。

#include <pthread.h>
#include <cstdlib>
#define fatal_error() abort()
extern void *start_routine(void *);

void returnnotchecked_1() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;

    (void)pthread_attr_init(&attr);
    (void)pthread_create(&thread_id, &attr, &start_routine, ((void *)0)); //Noncompliant
    pthread_join(thread_id,  &res); //Noncompliant
}

void returnnotchecked_2() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;
    int result;

    (void)pthread_attr_init(&attr);
    result = pthread_create(&thread_id, &attr, &start_routine, NULL); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

    result = pthread_join(thread_id,  &res); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

この例では、2 つの重要な関数 pthread_create および pthread_join を呼び出しています。pthread_create の戻り値は void にキャストすることで無視されますが、pthread_create は (要注意の関数であるだけでなく) 重要な関数であるため、ルール チェッカーはやはり違反を報告します。他の重要な関数 pthread_join は暗黙的に無視される値を返します。

準拠するには、これらの重要な関数の戻り値をチェックして、関数が想定どおりに実行されることを検証します。

#include<cstdlib>
#include<cerrno>
#include<climits>
#include<iostream>

int main(int argc, char *argv[]) {
    char *str, *endptr;
    int base;
    
    str = argv[1];
    base = 10;
    
    long val = strtol(str, &endptr, base); //Noncompliant
    std::cout<<"Return value of strtol() = %ld\n" << val;
    
    errno = 0;
    long val2 = strtol(str, &endptr, base); //Compliant
    if((val2 == LONG_MIN || val2 == LONG_MAX) && errno == ERANGE) {
         std::cout<<"strtol error";
         exit(EXIT_FAILURE);
    }        
    std::cout<<"Return value of strtol() = %ld\n" << val2;
}

非準拠の例では、errno をチェックせずに strtol の戻り値を使用しています。

準拠するには、strtol を呼び出す前に、errno にゼロを設定します。strtol 呼び出し後、戻り値については LONG_MIN または LONG_MAX をチェックし、errno については ERANGE をチェックします。

チェック情報

グループ: Language Independent Issues
カテゴリ: 必要

バージョン履歴

R2020b で導入

すべて展開する


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.