メインコンテンツ

有効期間が一時的なオブジェクトにアクセスしています

オブジェクトに対する読み取りまたは書き込み操作が未定義の動作

説明

この欠陥は、関数呼び出しから返された、有効期間が一時的なオブジェクトに対して読み取りまたは書き込みを試みると発生します。関数から返された、配列が含まれている構造体または共用体では、それらの配列メンバーは一時オブジェクトです。一時オブジェクトの有効期間が終了するのは、以下のとおりです。

  • C11 規格で定義されているように、その呼び出しを含む完全な式または完全な宣言子が終了したとき。

  • C90 および C99 規格で定義されているように、次のシーケンス ポイントの後。シーケンス ポイントとは、プログラムの実行において、すべての前の評価が完了し、以降の評価がまだ開始されていない時点のことです。

C++ コードでは、有効期間が一時的なオブジェクトに書き込みを行う場合のみ、[有効期間が一時的なオブジェクトにアクセスしています] によって欠陥が報告されます。

有効期間が一時的なオブジェクトがアドレスで返された場合、欠陥は報告されません。

リスク

有効期間が一時的なオブジェクトの変更は未定義の動作であり、プログラムの異常終了と移植性の問題の原因になる可能性があります。

修正方法

関数呼び出しから返されたオブジェクトをローカル変数に代入します。有効期間が一時的なオブジェクトの内容がこの変数にコピーされます。安全にこれを変更できるようになります。

すべて展開する

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

#define SIZE6 6

struct S_Array
{
    int t;
    int a[SIZE6];
};

struct S_Array func_temp(void);

/* func_temp() returns a struct value containing
* an array with a temporary lifetime.
*/
int func(void) {
 
/*Writing to temporary lifetime object is
 undefined behavior
 */
    return ++(func_temp().a[0]); 
}

void main(void) {
    (void)func();
}

この例では、func_temp() は配列メンバー a をもつ構造体を値で返します。このメンバーの有効期間は一時的です。これをインクリメントすることは未定義の動作です。

修正 — 書き込み前にローカル変数に戻り値を代入

1 つの修正方法として、func_temp() の呼び出しの戻り値をローカル変数に代入します。一時オブジェクト a の内容がこの変数にコピーされ、これを安全にインクリメントできます。

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

#define SIZE6 6

struct S_Array
{
    int t;
    int a[SIZE6];
};

struct S_Array func_temp(void);

int func(void) {

/* Assign object returned by function call to 
 *local variable
 */
    struct S_Array s = func_temp(); 

/* Local variable can safely be
 *incremented
 */
    ++(s.a[0]);                                           
    return s.a[0];
}

void main(void) {
    (void)func();
}

結果情報

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

バージョン履歴

R2018a で導入