メインコンテンツ

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

スタック変数へのポインターまたは参照が範囲外

ローカル変数を指すポインターが変数スコープを逸脱している

説明

この欠陥は、ローカル変数へのポインターまたは参照が変数のスコープを逸脱している場合に発生します。次に例を示します。

  • 関数が、ローカル変数を指すポインターを返す。

  • 関数が代入 globPtr = &locVar を実行する。globPtr はグローバル ポインター変数、locVar はローカル変数です。

  • 関数が代入 *paramPtr = &locVar を実行する。paramPtr は関数パラメーター (つまり int** ポインターなど)、locVar はローカルの int 変数です。

  • C++ メソッドが代入 memPtr = &locVar を実行する。memPtr はメソッドが属するクラスのポインター データ メンバー、locVar はメソッドから見てローカルな変数です。

  • (C++11 以降) 関数が、参照によって関数のローカル変数を取得するラムダ式オブジェクトを返す。

欠陥は、関数 alloca を使用して割り当てたメモリにも適用されます。この欠陥は静的なローカル変数には適用されません。Polyspace® は、関数定義に含まれるローカル オブジェクトは同じスコープ内にあると仮定します。

リスク

ローカル変数にはスタック上のアドレスが割り当てられます。ローカル変数のスコープがいったん終了すると、このアドレスは再利用可能になります。このアドレスを使用して変数のスコープ外にあるローカル変数値にアクセスすると、予期しない動作を引き起こす可能性があります。

ローカル変数を指すポインターが変数のスコープを逸脱していると、Polyspace Bug Finder™ によってその欠陥が強調表示されます。この欠陥は、ポインターに格納されているアドレスが使用されていない場合でも発生します。コードを保守可能なものにするため、ポインターが変数のスコープを逸脱しないようにすることをお勧めします。ポインター内のアドレスが現在使用されていない場合でも、関数の他の使用者がそのアドレスを使用することで動作が未定義となる可能性があります。

修正方法

ローカル変数へのポインターまたは参照が変数スコープを逸脱しないようにします。

すべて展開する

void func2(int *ptr) {
    *ptr = 0;
}

int* func1(void) {
    int ret = 0;
    return &ret ;
}
void main(void) {
    int* ptr = func1() ;
    func2(ptr) ;
}

この例では、func1 はローカル変数 ret を指すポインターを返します。

main では、ptr はローカル変数のアドレスを指します。ret のスコープは func1 に制限されているため、func2 内で ptr がアクセスされると、そのアクセスは無効になります。

auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [&] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

この例では、関数 createAdder で、参照によってローカル変数 addThis を取得するラムダ式 adder を定義しています。addThis のスコープは関数 createAdder に制限されます。createAdder によって返されたオブジェクトが呼び出されると、変数 addThis に対する参照がスコープ外からアクセスされます。この方法でアクセスが行われると、addThis の値は未定義となります。

修正 – 参照ではなくラムダ式でのコピーによってローカル変数を取得

関数がラムダ式オブジェクトを返す場合は、ラムダ式でローカル変数を参照によって取得しないようにします。代わりにコピーによって変数を取得します。

コピーによって取得された変数の有効期間はラムダ オブジェクトと同じです。しかし、参照によって取得された変数の有効期間は、多くの場合、ラムダ オブジェクト自体よりも短くなります。ラムダ オブジェクトを使用すると、スコープ外からアクセスされるこれらの変数は値が未定義となります。

auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [=] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

結果情報

グループ: 静的メモリ
言語: C | C++
既定値: 手書きコードはオン、生成コードはオフ
コマンド ライン構文: LOCAL_ADDR_ESCAPE
影響度: High

バージョン履歴

R2015b で導入

すべて展開する