メインコンテンツ

MISRA C++:2023 Rule 25.5.3

The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function

R2024b 以降

説明

ルール定義

The pointer returned by the C++ Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror must not be used following a subsequent call to the same function. 1

根拠

C 標準では、getenv などの再呼び出し不可能な関数が "静的" バッファーへのポインターを返すことを許可しています。バッファーが静的であるため、getenv の 2 回目の呼び出しでバッファーが変更されることがあります。最初の呼び出しで返されたポインターを 2 回目の呼び出しの後も使用し続けると、予期しない結果になる可能性があります。ポイントされるバッファーに、最初の呼び出しの値が含まれなくなる可能性があります。

このルールの対象となる他の再呼び出し不可能な関数についても、同じ理由が当てはまります。このルールの目的上、以下の関数のペアの呼び出しは、同じ関数の呼び出しとして扱われます。

  • setlocale および localeconv

  • asctime および ctime

  • gmtime および localtime

Polyspace 実装

Polyspace® は、次の事象がこの順番で起きた場合にこのルールの違反を報告します。

  1. getenvsetlocale など、再呼び出し不可能な標準関数から返されるバッファーをポイントします。

    user = getenv("USER");
  2. その再呼び出し不可能な標準関数またはそのペアとなる関数を、もう一度呼び出します。

    user2 = getenv("USER2");
  3. 最初のステップ以降バッファーが変更されずに残っていると想定して、最初のステップのポインターを使用またはデリファレンスします。しかし、バッファーは 2 番目のステップの呼び出しで変更されています。

    次に例を示します。

    var=*user;

場合によっては、getenv 関数を 2 回呼び出さなくても、ポインターを返すだけで違反が発生することがあります。以下に例を示します。

char* func() {
     user=getenv("USER");
     .
     .
     return user;
}

トラブルシューティング

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

すべて展開する

この例では、ポインター user_name_from_home はポインター home から派生しています。homegetenv の最初の呼び出しから返されるバッファーを指しています。そのため、user_name_from_home は同じバッファー内の場所を指します。

#include <cstdlib>
#include <cstring>

int func()
{
	int result = 0;

	char *home = getenv("HOME");   /* First call */
	if(home != NULL) {
		char *user = NULL;
		char *user_name_from_home = strrchr(home, '/');

		if(user_name_from_home != NULL) {
			user = getenv("USER");   /* Second call */
			if((user != NULL) &&
			        (strcmp(user, user_name_from_home) == 0)) // Noncompliant
			{
				result = 1;
			}
		}
	}
	return result;
}

このバッファーは、getenv を再度呼び出した後に変更されます。user_name_from_home を引き続き使用すると、予期しない結果が発生する可能性があります。

修正 — 2 回目の呼び出し前にバッファーのコピーを作成

getenv の最初の呼び出しからのバッファーを 2 回目の呼び出し以降も使用する場合は、最初の呼び出し後にバッファーをコピーします。1 つの修正方法として、関数 strdup を使用してコピーします。

#include <stdlib.h>
#include <string.h>

int func()
{
    int result = 0;

    char *home = getenv("HOME");    
    if (home != NULL) {
        char *user = NULL;
        char *user_name_from_home = strrchr(home, '/'); 
        if (user_name_from_home != NULL) {
            /* Make copy before second call */
            char *saved_user_name_from_home = strdup(user_name_from_home); 
            if (saved_user_name_from_home != NULL) {
                user = getenv("USER");  
                if ((user != NULL) &&
                    (strcmp(user, saved_user_name_from_home) == 0)) 
                {
                    result = 1;
                }
                free(saved_user_name_from_home);
            }
        }
    }
    return result;
}

チェック情報

グループ: ローカライズ ライブラリ
カテゴリ: Mandatory

バージョン履歴

R2024b で導入


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.