web-dev-qa-db-ja.com

エラーを解決する一般的な方法:変数「x」の周りのスタックが破損しました

私はVS2010のエラーをデバッグするプログラムを持っています:

Error: Stack around the variable 'x' was corrupted

これにより、スタックオーバーフローが発生する可能性が高い機能が得られますが、問題がどこにあるかを視覚的に確認できません。

VS2010でこのエラーをデバッグする一般的な方法はありますか?不正なスタックメモリを上書きしている書き込み操作を特定することは可能ですか?ありがとう

20
lezebulon

VS2010でこのエラーをデバッグする一般的な方法はありますか?

いいえ、ありません。あなたがしたことは、どういうわけか未定義の動作を呼び出すことです。これらの動作が定義されていない理由は、一般的なケースの検出/診断が非常に難しいためです。場合によっては、そうすることが不可能であることが証明されます。

ただし、通常は問題の原因となるやや少数の問題があります。

  • メモリの不適切な処理:
    • 何かを2回削除すると、
    • 間違ったタイプの削除を使用する(freeで割り当てられたものに対してはnewなど)、
    • メモリが削除された後で何かにアクセスする。
  • ローカルへのポインタまたは参照を返します。
  • 配列の最後を超えて読み書きする。
12
David Hammen

これはいくつかの問題が原因で発生する可能性があり、一般的には確認が困難です。

  • 二重削除
  • deletenew[]またはdelete[]で割り当てられた変数newで割り当てられた変数
  • deletemallocで割り当てられたもの
  • delete自動ストレージ変数
  • 参照によりローカルを返す

すぐにわからない場合は、メモリーデバッガーを手に入れます(Rational Purify for Windowsが思い浮かびます)。

8
Luchian Grigore

実際に表示される情報は非常に有益です。このエラーの原因となる可能性のあるアクティビティがないか、x変数の近くの場所を確認してください。

以下は、このような例外を再現する方法です。

int main() {
    char buffer1[10];
    char buffer2[20];
    memset(buffer1, 0, sizeof(buffer1) + 1);
    return 0;
}

生成される(VS2010):

実行時チェックの失敗#2-変数「buffer1」の周りのスタックが破損していました。

明らかにmemsetは必要以上に1文字書き込んでいます。オプション\ GSを使用したVSでは、このようなバッファオーバーフロー(有効になっている)を検出できます。詳細については、こちらをご覧ください http://msdn.Microsoft.com/en-us/library/Aa290051

たとえば、デバッガーを使用してコードをステップ実行し、変数の内容を見るたびに、それらがどのように変化するかを監視できます。データブレークポイントで運を試すこともできます。メモリの場所が変更されたときにブレークポイントを設定し、その時点でデバッガーが停止します。おそらく問題のある場所にコールスタックが表示されます。しかし、これは実際には\ GSフラグでは機能しない可能性があります。

ヒープオーバーフローを検出するには、gflagsツールを使用できます。

3
marcinj

このメッセージは、配列の境界違反が原因である場合もあります。関数(および関数が呼び出すすべての関数、特にスタックベースのオブジェクトのメンバー関数)が、使用される可能性のある配列の境界に従っていることを確認してください。

3
Omaha

私はこのエラーに何時間も困惑しました。考えられる原因はわかっており、それらは以前の回答ですでに言及されていますが、メモリを割り当てず、配列要素にアクセスせず、ローカル変数へのポインターを返しません。 。

その後、最終的に問題の原因を発見しました:

*x++;

その意図は、指摘された値を増分することでした。ただし、優先順位が高いため、++が最初に来て、xポインタを前方に移動すると、*は何もせず、*xに書き込むと、パラメータが来るとスタックカナリアが破損します。スタックから、VSを不平を言う。

(*x)++に変更すると、問題が解決します。

お役に立てれば。

1
Calmarius

この状況で私が行うことは次のとおりです。

エラーが発生する前に、問題の変数の(正しい)値を確認できる場所にブレークポイントを設定します。スタックが破損している変数のメモリアドレスが必要です。デバッガーがアドレスを簡単に取得できるように、コード行を追加する必要がある場合があります(int * x =&y)

この時点で、メモリブレークポイントを設定できます(デバッグ->新しいブレークポイント->新しいデータブレークポイント)。

Playを押すと、メモリが書き込まれたときにデバッガが停止します。スタックを調べて(通常、一部のアセンブリコードで壊れます)、何が呼び出されているかを確認します。

0
Ben

私は通常、変数beforeに従いますが、これは通常、問題を解決するのに役立ちます。しかし、これはあなたが見たように手がかりがなく非常に複雑になることがあります。 [デバッグ]メニュー>> [例外]を有効にして、「Win32例外」にチェックマークを付けると、すべての例外をキャッチできます。これでもこの例外はキャッチされませんが、間接的に問題を指摘する何かをキャッチできます。

私の場合、それは私が使用していたライブラリが原因でした。プロジェクトに含めていたヘッダーファイルは、そのライブラリの実際のヘッダーファイルと(1行だけ)完全には一致しませんでした。

関連する別のエラーがあります:

0xC015000F:非アクティブ化されているアクティブ化コンテキストは、最後にアクティブ化されたものではありません。

デバッグ情報のないコンピューターで、スタックの破損した不思議なメッセージが表示されるのに飽きたとき、別のコンピューターでプロジェクトを試したところ、代わりに上記のメッセージが表示されました。新しい例外を除いて、私は自分の方法でうまくいくことができました。

0
zar

13項目のポインター配列を作成し、14番目の項目を設定しようとしたときに、この問題が発生しました。配列を14アイテムに変更すると、問題が解決しました。これが一部の人々に役立つことを願っています^ _ ^

0