WindowsServer2012R2での初期化していないC++ローカル変数の初期値について

新田浩喜 0 評価のポイント
2024-03-12T10:31:27.0066667+00:00

VisualStudio2015でツールセット2012を指定してビルドしたexeを使用しています。

当該プログラムには、初期化していないローカル変数が存在していましたが、WindowsServer2012R2で使用していた時には特に不具合が発生していませんでした。(バグが顕在化しませんでした。)

ところが、同exeをWindowsServer2019に移行したところ同ローカル変数の初期値不良による障害が発生してしまいました。

プログラムに当該ローカル変数の値を出力するログを仕込んで繰り返して実行する調査をしたところ、初期値としては何種類かの値が不規則な順序でセットされていました。

そこで質問です。

① 初期化していないローカル変数にセットされる値が何種類かしかありませんが、同一環境、同一起動条件でこのプログラムを使用している場合には、これらの値しかセットされないと考えて問題ないでしょうか?

② ①がNOの場合、ユーザープログラムの動作が変わらない場合、値が変わる要因としてはどのようなことが考えられるでしょうか?

③ 同プログラムをVisualStudio2019+ツールセット2019でビルドしなおすと、初期化していないローカル変数には必ずゼロがセットされるようになりましたが、VisualStudioまたはC++ランタイムのどこかのバージョンから、初期化していないローカル変数が自動的に初期化されるような仕様変更が行われたでしょうか?

以上、拙い質問で申し訳ありませんが、よろしくお願いいたします。

Visual Studio
Visual Studio
Windows、Web、モバイル デバイス用のアプリケーションを構築するための統合開発ツールの Microsoft スイートのファミリ。
35 件の質問
Windows Server
Windows Server
エンタープライズ レベルの管理、データ ストレージ、アプリケーション、通信をサポートする Microsoft サーバー オペレーティング システムのファミリ。
20 件の質問
C++
C++
C プログラミング言語の拡張機能として作成された高レベルの汎用プログラミング言語。低レベルのメモリ操作機能に加えて、オブジェクト指向、汎用、関数型の機能を備えています。
11 件の質問
0 件のコメント コメントはありません
{count} 件の投票

2 件の回答

並べ替え方法: 最も役に立つ
  1. gekka 6,846 評価のポイント MVP
    2024-03-12T17:20:04.4333333+00:00

    >①
    C/C++の規格としては初期化されていないメモリはどのような値になっているかは決められていません。
    ただし、VisualC++の場合はメモリリークやバッファーオーバラン検出などのために割り当てメモリの前後に特定のパターンの値で埋めていることもあります。

    旧MSDNフォーラムが消滅したのでバックアップから引用

    gekka wrote;

    バッファーオーバーランによる書き換えを検出するための特定パターンを埋め込んでおくための領域では? 後ろに付加されるのはリリースビルドでは発生しない現象だったりしませんか?領域の前方にも同じようなパターンがありませんか?

    デバッグビルドではデバッグ用のmallocで領域確保するようですよ。 CRT デバッグ ヒープ

    Atomu Hidakaさんwrote;

    どこかでパターンによって意味があると見たことがあります。調べてみました。

    これのことでしょうか?

    ポインタ先の変数のダンプが、0xFDFDFDFD ならば、ポインタ計算の誤りです。 ポインタ先の変数のダンプが、0xDDDDDDDD ならば、メモリ開放して無効になった変数へのアクセスです。 変数のダンプが、0xCDCDCDCD または 0xCCCCCCCC ならば、変数の初期化忘れです。 https://qiita.com/hkuno/items/ed32c0597233e401dc3c

    >②③
    検索してみつけたstackoverflowのリンクを見ると、コンパイラの隠しオプション-initallや、MicrosoftのBlogなどが見つかります。

    ブログのInitAll - Automatic Initializationには、コンパイラのバージョンに言及はしていませんが、現在はコンパイル時にスタック領域を初期化していると書かれてます。
    ほかにもWin101903以降はOSレベルで対応しているようなことも書かれていますね。

    再利用されたメモリに前のデータが残っているとセキュリティの問題もあったりするので、この記事以外でもゼロに初期化されてるようになっていることもあるかもしれません。


  2. 新田浩喜 0 評価のポイント
    2024-03-13T01:11:40.29+00:00

    gekka様、早速ご回答いただき、ありがとうございます。

    ①に関しては、上記に記載されているようなパターンではなく、4つのbool変数に下記のような値がセットされ、実行するたびにランダムに切り替わります。

    初期値パターン1:

    bMergeRec[0]

    bCordRec1[0]

    bCordRec2[0]

    bRec2Save[0]

    初期値パターン2:

    bMergeRec[138]

    bCordRec1[0]

    bCordRec2[0]

    bRec2Save[118]

    実行結果の例:

    1回目~4回目:初期値パターン1

    5回目    :初期値パターン2

    6回目~10回目:初期値パターン1

    11回目    :初期値パターン2

    12回目    :初期値パターン1

    13回目    :初期値パターン2

    ...

    これは、前の処理で使用されたスタック領域を使用しているようなのですが、各回のユーザープログラムは同一の設定、入力ファイルで起動しているので、上記の現象が起きる関数が実行されるまでの流れはすべて同一であると考えております。

    従いまして、この関数に入る前にスタック領域を使用しているのは、ユーザープログラムに制御が渡される前またはライブラリ関数の中ではないかと想定しております。

    また、30000回以上の実行を繰り返しても初期値の設定パターンは上記2種類しか出てこないのですが、今後の実行においてこれら以外の値が設定される可能性はあるでしょうか?

    ②③の回答については、ご提供いただいたサイトを参考に調査を進めたいと思っております。ご提供ありがとうございました。