10

別のDLLファイルを使用しているDLLファイルを使用したEXEファイルがあります。この状況が発生しました:

DLLファイル1:

class abc
{
    static bool FindSubFolders(const std::string & sFolderToCheck, 
                               std::vector< std::string > & vecSubFoldersFound);
}

DLLファイル2:

void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}

リリースモードでは、すべてが正常に機能します。しかし、デバッグモードではstd::strings、フォルダーベクトル内のいずれかのデストラクタでアサーションエラーが発生します(フォルダーがaFunctionの最後でスコープ外になる場合)。

dbgheap.c : line 1274

/*
 * If this ASSERT fails, a bad pointer has been passed in. It may be
 * totally bogus, or it may have been allocated from another heap.
 * The pointer MUST come from the 'local' heap.
 */
_ASSERTE(_CrtIsValidHeapPointer(pUserData));

これは、メモリがDLLファイル1のヒープに割り当てられているが、DLLファイル2で解放されているためだと思います。

のコメントdbgheap.cは、これが問題であるとかなり主張しているようです。

無視すればうまくいくように見えるのに、なぜこれがこのような問題なのですか?これを行うためのアサーションに失敗しない方法はありますか?

4

4 に答える 4

14

ショーンがすでに言ったように、リリースビルドは単にその削除ステートメントを無視するので、期待できる最善の方法はメモリリークです。

両方のDLLファイルのコンパイル方法を制御できる場合は、ランタイムライブラリにマルチスレッドデバッグDLL(/ MDd)またはマルチスレッドDLL(/ MD)設定を使用してください。そうすれば、両方のDLLファイルが同じランタイムシステムを使用し、同じヒープを共有します。

欠点は、アプリケーションと一緒にランタイムシステムをインストールする必要があることです(Microsoftはそのためのインストーラーを提供しています)。Visual Studioはそのランタイムシステムもインストールするため、開発マシンでは正常に機能しますが、新しくインストールされたマシンでは、不足しているDLLファイルが報告されます。

于 2009-10-28T02:20:47.683 に答える
8

ほとんどの場合、リリースビルドにも同じ問題がありますが、リリースビルドはアサートしません。彼らはただ問題を無視します。問題が発生することはありません。または、データが破損している可能性があります。または、クラッシュが発生する可能性があります。たぶん、あなたのユーザーだけがあなたが単に再現することができないバグを経験するでしょう。

CRTアサーションを無視しないでください。

常に適切なデアロケータ(最初に使用されたアロケータと一致するもの)を使用する必要があります。DLLファイルで静的CRTライブラリを使用している場合、DLLファイルは異なるヒープを使用しています。ヒープ間でメモリの割り当てを解除することはできません。同じヒープを使用して、メモリのブロックを割り当ておよび割り当て解除します。

DLLファイルで共有CRTライブラリを使用している場合、それらは同じヒープを使用している必要があり、1つのDLLファイルで割り当て、別のファイルで割り当てを解除できます。

于 2009-10-28T02:08:07.387 に答える
7

他の人が言うように、この問題は、CRTが2つのモジュール間で共有されていることを確認することで解決できます。ただし、この契約を実施するのが難しい一般的なシナリオがあります。

その理由は、EXEとDLLが同じCRTバージョン(6.0、7.0、8.0など)に対してリンクされていない場合、共有CRTに対してリンクすることは機能しないためです。たとえば、VC6.0でビルドされたDLLを取得し、それをVS2010のEXEビルドで使用しようとすると、以前と同じ問題が発生します。2つのバージョンのCRTがプロセスにロードされ、EXEとDLLが「共有」CRTを使用するかどうかに関係なく、それぞれが独自のヒープを割り当てに使用します。これらは同じではありません。

APIのより良い方法は、一方の側に割り当てられたオブジェクトも同じ側で破棄されるようにすることです。私はこれが醜いように聞こえることを知っていますが、DLLがバイナリ互換性を維持することを保証する唯一の方法です。

于 2012-11-27T15:22:47.460 に答える
5

これは、アプリケーションまたは1つ(または複数)のDLLファイルが静的バージョンの標準ライブラリに対してリンクされている場合にのみ問題になります。これは、MSが標準ライブラリの共有ライブラリバージョンをリリースすることにより、約10年前に解決されました。これは、標準ライブラリの各バージョンが独自の内部ヒープを構築するため、複数のヒープがある場合は、メモリを正しいヒープに解放する必要があるためです。標準ライブラリの共有バージョンを使用することにより、それらはすべて同じヒープを使用します。

現在のアプリケーションでは標準的な方法であり、すべてのDLLファイルはダイナミックバージョンの標準ライブラリを使用するようにビルドする必要があります。

上記の唯一の注意点は、独自のヒープを作成し、このヒープからメモリを割り当てる場合です。しかし、これはまれな状況でのみ行われる非常に特殊な手順です(そして、それを使用するのに十分理解している場合は、この質問をする状況にはなりません)。

于 2009-10-28T04:45:29.123 に答える