3

私は現在、非常に大きな (そして古いため息をつく) コード ベースに取り組んでおり、最近 VS2005 (SP1) にアップグレードされました。私と私のチームは、このコードのモジュールを変更/更新/置換していますが、vtables が壊れているように見える問題に時々遭遇しています。私は vtables の専門家ではありませんが、これらは確かに壊れているようです。エラーは、次のエラーで明らかになります。

実行時チェックの失敗 #0 - ESP の値が関数呼び出しで適切に保存されませんでした。これは通常、ある呼び出し規約で宣言された関数を、別の呼び出し規約で宣言された関数ポインターで呼び出した結果です。

もちろん、このエラーには他にも多くの理由が考えられますが、デバッグ (デバッグ ビルド) 時に、操作したいオブジェクトの vtables が奇妙に見えることを実際に確認できます。

各 vtable を参照するスタックとヒープは正常に見え、vtable へのポインターはマップ ファイルと完全に一致します。これは、vtables が格納されている場所ではなく、スタックとヒープに影響するため、これがメモリ上書きバグなどではないことを示しています。(読み取り専用領域に保存されていますよね?) とにかく、今のところ問題ないようです。しかし、vtable のメモリを見ると、すべての値をポインターとして解釈すると、同じ範囲 (例: 0x00f203db 0x00f0f9be 0x00ecdda7 0x00f171e1) にあるにもかかわらず、マップ ファイルのどのエントリとも一致せず、それらの多くが一致することがわかります。 4 バイトにアラインされていません。VS2005 がどのように vtable を構築するかについての詳細はわかりませんが、これは私には間違っているように見えます。これが正しい動作である場合、おそらく誰かが私にこれを説明できますか?

私の質問は、この動作の原因は何ですか? たとえば、クラス階層が複雑すぎる場合、リンカに既知のバグはありますか? 誰かが以前に似たようなものを見たことがありますか? 現在、関数を影響を受けるクラスからインラインに移動することでクラッシュを回避できますが (恐ろしいことです!)、明らかにこれは実行可能な長期的な解決策ではありません。

洞察をありがとう!

更新: プロジェクトの詳細について尋ねられました。もちろん、これを提供します。ただし、最初に、質問は ESP 値が保存されていないというエラーに完全に関連しているわけではありません。私が最も興味を持っているのは、vtable に奇妙な値が表示される理由です。とはいえ、ここにいくつかの追加情報があります。ソリューションはいくつかの外部および内部プロジェクトに依存していますが、これらは長い間変更されておらず、すべて同じ呼び出し規則を使用しています。壊れているように見えるコードはすべて、ソリューションの 1 つのかなり標準的な C++「メイン」プロジェクト内にあります。すべてのコードは同じコンパイラでビルドされます。このソリューションでは、DLL も使用しませんが、多くの静的ライブラリにリンクしています。

SHFolder.lib、python25.lib、dxguid.lib、d3d9.lib、d3dx9.lib、dinput8.lib、ddraw.lib、dxerr9.lib、ws2_32.lib、mss32.lib、Winmm.lib、vtuneapi.lib、vttriggers。 lib、DbgHelp.lib、kernel32.lib、user32.lib、gdi32.lib、winspool.lib、comdlg32.lib、advapi32.lib、shell32.lib、ole32.lib、oleaut32.lib、uuid.lib、odbc32.lib、 odbccp32.lib

4

6 に答える 6

2

問題が見つかりました。本当にばかげていますが、問題を引き起こしたクラス階層には、同じ名前のウィンドウ #define と競合する GetObject という仮想関数がありました。ヘッダー ファイルには、これらの Windows ヘッダー ファイルが異なる順序で含まれていたため、リンカーが混乱していました。実際、問題は破損した vtables でしたが、これが理由になるとは思っていませんでした! ええと、あなたは毎日何かを学びます...

しかし、答えてくれたすべての人に感謝します!

于 2009-02-26T06:04:42.080 に答える
1

ここでの大きなヒントは、「これは通常、ある呼び出し規約で宣言された関数を、別の呼び出し規約で宣言された関数ポインターで呼び出した結果です」というエラーの部分にあると思います。呼び出し元の API と呼び出しを処理しているライブラリとの間に不一致があるようです。

また、異なるコンパイラでビルドされたコードが混在している場合もあります。このプロジェクトの性質について、他に何を教えていただけますか? 呼び出している関数は外部ライブラリにありますか? または、コール スタック全体をデバッグできますか?

編集:プロジェクトはDLLを使用していないと言いました。静的ライブラリはどうですか?

于 2009-02-24T09:01:57.490 に答える
0

私はまったく同じ問題を抱えていました-オブジェクトでオーバーロードされた仮想関数を呼び出すと、「ESPが適切に保存されませんでした」エラーが発生しましたが、デバッグにより、コンパイラがこの呼び出しのvtableに誤ったオフセットを生成したことが示されたため、パラメータが呼び出されていました。呼び出された関数は、呼び出し元がスタックにさらに多くのパラメーターをプッシュしたかのようにESPを更新しました。その結果、戻り時に無効なESP値が発生しました。

障害のあるクラスを含むヘッダーファイルをソースファイルの先頭に配置すると、問題は解消されました。これを正確に引き起こした原因についてはこれ以上調査していませんが、同じ状況であったと思います。仮想メンバーの宣言をいじることを定義するものもあります。

同じ問題に遭遇する他の人を助けることを願っています。

于 2009-08-24T09:00:14.687 に答える
0

私がこのようなメッセージを受け取ったときはいつでも、答えはコードの一部または全部を再コンパイルすることでした。最初のステップとして、完全な再構築を試みます。外部ライブラリに関する Sqook の提案ももっともらしく聞こえますが、可能であれば、メイン コードと同じ呼び出し規約でそのライブラリを再コンパイルする必要があります。

Build コマンドが再コンパイルが必要なファイルを見逃す可能性があり、それがあなたのメッセージにつながる可能性があることに時々気づきました。繰り返しますが、完全に再構築すると問題が解決します。

于 2009-02-24T09:22:05.023 に答える
0

以前にこのエラーが発生したのは、常に COM が関与している場合です。ほとんどの場合、特に再入可能性に関連しています。COM を使用していますか? STA、メッセージ フィルターを使用していますか?

于 2009-02-24T14:17:17.593 に答える