2009-06-09 15 views
3

実行時に動的にdllとしてモジュールをロードする必要があります。これは、クラスインタフェースに準拠しているためです。私が気づいたのは、(メインスレッドのメインプログラムの)dllによってスローされた例外を捕まえた後、右のデストラクタが呼び出され、モジュールが破棄され、dllがアンロードされた後、catchブロックの最後に}プログラムをクラッシュする別の例外が発生するdll例外をキャッチした後のアクセス違反

xxxxx.exeの0x68ad2377(msvcr90d.dll)の最初の例外:0xC0000005:アクセス違反の場所0x02958f14を読み取るアクセス違反。

私は例外で破り有効にした場合、この第二の例外に破壊する

msvcr90d.dllとしての位置を示しています!__ DestructExceptionObject(EHExceptionRecord * pExcept = 0x0017ee4c、unsigned char型fThrowNotAllowed = 0)ライン1803 + 0xFのバイト

しかし、フレームスタックが破損している可能性があります。なぜこの例外がスローされるのか分かりません。次のように

私のコードの構造を簡略化したバージョンがある:プログラムの

非常に簡単な構造:

//shared header: 
class Module 
{ 
public: 
    virtual void Foo(void) = 0; 
}; 


//dll: 
class SomeSpecificModule : public Module 
{ 
public: 
    virtual void Foo(void); 
}; 

void SomeSpecificModule::Foo(void) 
{ 
    throw 1; 
} 

extern "C" __declspec(dllexport) Module* GetModule() 
{ 
    return new SomeSpecificModule; 
} 


//program: 
typedef ptrGetModule* (*GetModule)(); 

int main(void) 
{ 
    HANDLE hMod = LoadLibrary("SomeSpecificModule.dll"); 
    ptrGetModule GetModule = (ptrGetModule)GetProcAddress(hMod, "GetModule"); 
    try 
    { 
     Module *d = GetModule(); 
     d->Foo(); 
    } 
    catch (...) 
    { 
     cout << '!' << endl; 
    } 
    return 0; 
} 
+0

スタックトレース全体を投稿してください –

答えて

1

あなたはあなたの実際のコードに値で例外をcathingていますか?この場合、catchブロックの最後にコピーされた例外オブジェクトのデストラクタに例外が存在する可能性があります。

1

このコードでは、DLLがアンロードされた場所は表示されません(あなたが言うように)。関連コードを投稿してください。

DLLのアンロードは、オブジェクトの破壊、スタックの巻き戻しなどに必要なコードが含まれているため、DLLがアンロードされた時点で投稿された内容からは明らかではありません。

0

チェックpojectの設定、アプリケーションがマルチスレッド化されている場合、その後、あなたはマルチスレッドDLLに

4

をリンクする必要が覚えておくべき事は、Cランタイムライブラリの各コピーは独自の状態を持っているということです。 SomeSpecificModule.dllがCランタイムライブラリに静的にリンクしている場合、この種の問題が発生する可能性があります。その場合は、CランタイムライブラリのDLLバージョンとリンクしてみてください。また、SomeSpecificModule.dllがコンパイルされ、メインモジュールとまったく同じ方法でリンクされていることを確認する必要があります。

あなたは、DLLがアンロードされ、正しいデストラクタが呼び出されたと述べました。あなたの実際のプログラムは、あなたが投稿したサンプルよりもずっと多くなっているようです。 SomeSpecificModule.dllをtryブロックにアンロードした場合、SomeSpecificModule :: Foo()の例外レコードをアンロードしました。これはmでクラッシュした方法です。

しかし、一般にDLL境界が問題を求めています。あなたは非PODオブジェクトを投げている場合は、別のヒープ、異なるコンパイラ設定、STLのバージョンで別のCランタイムライブラリによって割り当てられたメモリで問題が発生する可能性があります。

DLLの境界を越えないようにコードを変更してください。ある日あなたのチームの誰かがコンパイラの設定を変更したり、サードパーティのヘッダ#defineが変更され、プログラムがクラッシュし始めると、根本原因を突き止めるのが非常に困難になります。

とにかく、実際のコードを見ることなく、私は何がうまくいかないかを推測しようとしています。それが役に立てば幸い。

0

これは暗闇の中のショットかもしれませんが、チェックアウトする価値があります。

エラーがmsvcr90d.dllに表示されるため、アプリケーションがDEBUGでコンパイルされているようです。 DEBUGでコンパイルされているDLLもありますか? msvcr90.dllでメモリを作成し、msvcr90d.dllで解放する、またはその逆を行うことは、dllを使用するときの一般的な問題です。

あなたの関数ポインタtypedefは少し疑わしいと思います。私は次のように書くでしょう:

typedef Module* (*moduleFnType)(); 

int main(void) 
{ 
    HANDLE hMod = LoadLibrary("SomeSpecificModule.dll"); 
    moduleFnType GetModule = (moduleFnType)GetProcAddress(hMod, "GetModule"); 
    try 
    { 
     Module *d = GetModule(); 
     d->Foo(); 
    } 
    catch (...) 
    { 
     cout << '!' << endl; 
    } 
    return 0; 
} 

あなたのtypedefは、関数GetModuleの戻り値の型については何も言いません。

0

Canopus:例外としてintをスローすると、同じことが起こります。

TK___:私はすべてのプロジェクトでマルチスレッドのDLLにリンクしています。

AssafとShing Yip:dllは実際にFreeLibrary()のラッパーのデストラクタでアンロードされます。ラッパーオブジェクトはtr1 :: shared_ptrのベクトルにプッシュされます(ラッパー自体はリソースホルダなので、STLベクタに入れることはできません)、try {}スコープ内にのみ存在します。それは正しいことのように思えたので、エラー状況が発生したときにDLLのアンロードを含むクリーンアップを行うことができ、RAIIスタイルのデザインを好む傾向があります。これが問題の原因であれば、どのようなデザインを使用すれば正しく動作し、依然としてソフトウェアエンジニアリングの観点から見えますか? しかし、これは問題ではないかもしれないと思うのですが、例外がスローされたときに発生するデストラクタ呼び出しをステップ実行すると、FreeLibrary()はエラーなしで実行され、閉じるまでステップを続けることができます}をキャッチ{}の中に入れます。

Magnus Skog:リリースモードでは、例外をキャッチして通常の実行を継続するのではなく、クラッシュすることもあります。 ダイナミックメモリは、1)演算子が新しい場合があります.2)tr1 :: shared_ptr、3)_mm_malloc/_mm_freeで整列が必要です。

+0

FYI。答えに答えるための好ましい方法は、答えにコメントを追加することです(あなたの担当者が十分に高くないためにまだできない)か、元の質問を編集することです。元の質問を拡大するためにここにある追加情報を実際に使用する必要があります。将来の質問者が類似の症状を抱えている場合、この質問を見つけるのに役立ちます。さらに、問題と解決策のより良い「物語」を作成するだけです。 –

+0

@Prune。私の編集された答えを見てください。 – ralphtheninja

3

DLLが例外をスローするときに呼び出される必要があるスタックアンワインディングコードの多くはDLLにあります。 DLLをアンロードすると、そのコードはどのように呼び出されますか?

動的にリンクされたモジュール境界に例外をスローしないでください。

関連する問題