メインコンテンツ

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

前の操作によって無効になった環境ポインター

setenv または putenv ファミリ関数の呼び出しによってポインターの参照先の環境が変更されている

説明

この欠陥は、ホスト環境で操作による環境の変更後に、main() の第 3 引数を使用して環境にアクセスした場合に発生します。ホストされている環境では、多くの C 実装で非標準の構文がサポートされます。

main (int argc, char *argv[], char *envp[])
setenv または putenv ファミリ関数の呼び出しにより、*envp の参照先の環境に変更が加えられます。

リスク

setenv または putenv ファミリ関数の呼び出しによって環境が変更されると、環境のメモリが再割り当てされる可能性があります。そのホストされている環境のポインターが更新されず、正しくない場所を指す場合があります。このポインターを呼び出すと、予期しない結果が返されたり、プログラムの異常終了が発生したりすることがあります。

修正方法

ホストされている環境のポインターを使用しないようにします。代わりに、グローバル外部変数を使用します。Linux® では environ、Windows® では _environ_wenviron、またはこれらと同等のグローバル外部変数を使用します。環境を変更すると、これらの変数が更新されます。

すべて展開する

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

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

/* envp is from main function */
int func(char **envp) 
{
    /* Call to setenv may cause environment
     *memory to be reallocated 
     */
    if (setenv(("MY_NEW_VAR"),("new_value"),1) != 0) 
    {
        /* Handle error */
        return -1;
    }
    /* envp not updated after call to setenv, and may
     *point to incorrect location.
     **/
    if (envp != ((void *)0)) { 
        use_envp(envp);
/* No defect on second access to
*envp because defect already raised */
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func(envp);
    }
}

この例では、環境のメモリが再割り当てされる可能性のある setenv の呼び出しの後に、func() 内で envp にアクセスしています。envp は、setenv によって環境が変更された後には更新されないため、正しくない場所を指す可能性があります。前のコード行で既に欠陥が報告されているため、use_envp() が呼び出されたときには欠陥が報告されません。

修正 — グローバル外部変数 environ を使用

1 つの修正方法として、setenv の呼び出し後に必ず更新される変数を使用して環境にアクセスします。たとえば、次のコードでは、ポインター envpmain() からも使用可能ですが、環境へのアクセスは func() 内でグローバル外部変数 environ を通じて行います。

#include <stdio.h>
#include <stdlib.h>
extern char **environ;

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

int func(void)
{
    if (setenv(("MY_NEW_VAR"), ("new_value"),1) != 0) {
        /* Handle error */
        return -1;
    }
  /* Use global external variable environ
   *which is always updated after a call to setenv */
    
    if (environ != NULL) { 
        use_envp(environ);
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func();
    }
} 

結果情報

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

バージョン履歴

R2018a で導入