メインコンテンツ

要注意の関数の戻り値がチェックされていません

予期しない戻り値およびエラーのチェックなしで呼び出される要注意の関数

説明

この欠陥は、エラー発生の可能性に関する情報を返す要注意の標準関数を呼び出し、以下のいずれかを行った場合に発生します。

  • 戻り値を無視。

    戻り値を変数に単純に代入することも、戻り値を明示的に void にキャストすることもしていない。

  • エラーの戻り値をテストすることなく関数の出力 (戻り値または引数の参照渡し) を使用。

以下のような理由で関数呼び出しで障害を発生する可能性が高い場合、チェッカーはその関数を要注意と見なします。

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

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

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

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

チェッカーは、関数がエラーなしで終了したかどうかを "戻り値" が示す関数のみを考慮します。

このような関数の一部では、以下のような重要なタスクを実行する可能性があります。

  • 権限の設定 (setuid など)

  • jail の作成 (chroot など)

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

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

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

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

リスク

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

修正方法

プログラムを続行する前に、"重要で要注意" の関数の戻り値をテストします。

要注意の関数ではない場合は、その関数を void にキャストすることによって戻り値を明示的に無視することができます。Polyspace® は、要注意の関数が void にキャストされている場合はこの欠陥を発生させません。"重要で要注意の関数" の場合、さらに脆弱なタスクが実行されるため、この解決策は許容されません。

すべて展開する

#include <pthread.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>

void initialize() {
    pthread_attr_t attr;

    pthread_attr_init(&attr);//Noncompliant 
}
int read_file(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r");   
  return 0; //Noncompliant

}

この例は、要注意の POSIX 関数 pthread_attr_init および fmemopen の呼び出しを示しています。それらの戻り値が無視され、欠陥の原因になっています。

修正 - 関数を (void) にキャスト

考えられる 1 つの修正方法として、関数を void にキャストします。この修正では Polyspace およびレビュー担当者に、要注意の関数の戻り値を明示的に無視していることを伝えます。

#include <pthread.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>

void initialize() {
    pthread_attr_t attr;

    (void)pthread_attr_init(&attr);//Compliant 
}
int read_file(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  (void)fmemopen (argv[1], strlen (argv[1]), "r"); //Compliant
  
  return 0; 
}
修正 — 戻り値をテスト

1 つの修正方法として、pthread_attr_initfmemopen の戻り値をテストして、エラーをチェックします。

#include <pthread.h>
#include <string.h>
#include <stddef.h>
#include <stdio.h>

void initialize() {
    pthread_attr_t attr;

    int result = pthread_attr_init(&attr);//Compliant 
	if(result != 0){
		//Handle fatal error
	} 
}
int read_file(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r"); 
  if (in==NULL){
	  // Handle error
  }
  return 0;//Compliant 
}
#include <pthread.h>
extern void *start_routine(void *);

void returnnotchecked() {
    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));
    pthread_join(thread_id,  &res); 
}

この例では、2 つの重要な関数 pthread_create および pthread_join を呼び出しています。pthread_create の戻り値は void にキャストすることで無視されますが、pthread_create は (要注意の関数であるだけでなく) 重要な関数であるため、Polyspace ではこの "要注意の関数の戻り値がチェックされていません" という欠陥が無視されません。他の重要な関数 pthread_join は暗黙的に無視される値を返します。pthread_join は、pthread_create の戻り値を使用しますが、この戻り値はチェックされていません。

修正 - 重要な関数の戻り値をテスト

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

#include <pthread.h>
#include <stdlib.h>
#define fatal_error() abort()

extern void *start_routine(void *);

void returnnotchecked() {
    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);
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

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

結果情報

グループ: セキュリティ
言語: C | C++
既定値: オフ
コマンド ライン構文: RETURN_NOT_CHECKED
影響度: High

バージョン履歴

R2016b で導入

すべて展開する