8

次のようなプロトタイプを持つ関数があります。

void function(std::string str);

この関数は、その dll をロードして使用する別のプログラムのメイン関数で呼び出されます。

function("some string value here");

この関数から戻ると、ヒープ破損エラーが発生します。

Windows は、program.exe でブレークポイントをトリガーしました。

これは、ヒープの破損が原因である可能性があります。これは、program.exe またはそれがロードした DLL のバグを示しています。

これは、ユーザーが program.exe にフォーカスがあるときに F12 キーを押したことが原因である可能性もあります。

出力ウィンドウには、より多くの診断情報が表示される場合があります。

コードをいじってみると、いくつかの奇妙な観察結果に気付きました
。 1. 渡された文字列の長さが 11 文字未満の場合、エラーは発生しませんが、さらに文字を追加するとすぐにエラーが表示されます。
2. パラメータの型を からstd::stringに変更するとstd::string&、エラーが消えます。参照を渡すというアイデアはhereから生まれました。
3. 関数の本体をコメントアウトしました。そこの操作は、生成された例外とは関係ありません。
4. パラメータ タイプを からstd::stringに変更char*すると、問題も解決します。
このエラーの原因は何ですか? どうすれば解決できますか?

4

3 に答える 3

9

ほとんどの場合、Windows では DLL が独自のプライベート ヒープを持っているため、クラッシュが発生しています。

関数をコンパイルすると、コンパイラはstd::stringのデストラクタのコードを生成して、その引数をクリーンアップします。このコードは、DLL ヒープに割り当てられたメモリを解放します。ただし、アプリケーション EXE は、 のコンストラクター用に独自のコードも生成std::stringし、プログラム ヒープにコードを割り当てます。1 つのヒープに割り当て、もう 1 つのヒープで解放すると、未定義の動作が発生し、クラッシュします。

小さな文字列がバグを引き起こさない理由については、多くのstd::string実装では小さな文字列を構造体自体にインライン化して、ヒープのオーバーヘッドを回避しています。文字列が収まるほど小さい場合、メモリ割り当てを行う必要がないため、たまたま動作しているように見えます... EXE と DLL の両方に同じ STL バージョンを使用し、インライン化のしきい値が変更されない限り。

この問題を回避するには、値によってオブジェクトを DLL に渡さないでください (それらがPOD オブジェクトでない限り)。また、オブジェクトが作成されたときとは異なる DLL または EXE でオブジェクトを解放しないでください。STL または C++ ライブラリ オブジェクトをそれらの実装は、C++ コンパイラの異なるバージョン間で異なる可能性があるためです。代わりにPOD オブジェクトまたは C プリミティブ型を渡しますconst char *

于 2012-12-03T08:02:42.567 に答える
7

DLL 関数をエクスポートするときは、整数データ型、つまり int またはポインター (float と double については不明) のみを受け入れるのが最善です。

文字列を渡す必要がある場合は、 として渡しconst char *ます。DLL 関数が文字列を返す必要がある場合は、char *DLL が文字列を書き込む事前に割り当てられたバッファーへのポインターを DLL に渡します。

DLL 自体の関数の外部で DLL によって割り当てられたメモリを使用したり、独自のコンストラクター/デストラクターを持つ値構造体を渡したりしないでください。

于 2012-12-03T07:59:24.027 に答える
5

おそらく、静的バージョンの C ランタイムとリンクしている可能性があります。静的バージョンの C ランタイムとリンクする DLL を作成することは決して良い考えではありません。これにより、多くの問題が発生する可能性があります。たとえば、プログラムでは、EXE がリンクされている静的 C ランタイムのプライベート ヒープからメモリを割り当て、次に DLL でそのヒープを削除して新しいヒープを作成します (追加したいため)。一部のデータを入力文字列に追加し、バッファを拡大する必要がある)、エラーが発生します。これに対する最も簡単なアプローチは、プログラムのすべての部分 (EXE および DLL) を C ランタイムの DLL バージョンとリンクすることです。これにより、それらはすべて MSVCRTXX.dll から同じヒープを共有します。

于 2012-12-03T08:05:58.607 に答える