2011-02-08 10 views
5

私はプログラムのデプロイメントを進めており、コードベースはC++/CLIとC#が混在しています。 C++/CLIには、ネイティブ、混合(/clr)、安全(/clr:safe)のすべての味があります。私の開発環境では、すべてのC++/CLIコードのDLLを作成し、C#コード(EXE)からそのDLLを参照します。この方法は完璧に機能します。混在モードのC++/CLIクラッシュ:atexitのヒープ破損(静的デストラクタ登録)

私のリリースでは、1つの実行可能ファイルをリリースしたいと考えています(単に「DLLとEXEを別々にするのはなぜですか」とは言えません)。

これまでのところ、すべての異なるソースでEXEをコンパイルすることに成功しました。しかし、私がそれを実行すると、 "XXXXが動作を停止しました"というダイアログが表示され、オンラインチェック、クローズ、デバッグのオプションが表示されます。次のような問題の詳細は以下のとおりです。

Problem Event Name:  APPCRASH 
Fault Module Name:  StackHash_8d25 
Fault Module Version:  6.1.7600.16559 
Fault Module Timestamp: 4ba9b29c 
Exception Code:   c0000374 
Exception Offset:   000cdc9b 
OS Version:    6.1.7600.2.0.0.256.48 
Locale ID:    1033 
Additional Information 1: 8d25 
Additional Information 2: 8d25552d834e8c143c43cf1d7f83abb8 
Additional Information 3: 7450 
Additional Information 4: 74509ce510cd821216ce477edd86119c 

私はデバッグおよびVisual Studioに送信した場合、それは報告します!

Unhandled exception at 0x77d2dc9b in XXX.exe: A heap has been corrupted 

はntdll.dllので停止、その中にブレーク結果の選択がないと77d2dc9b()追加情報。 Visual Studioに続行するように指示すれば、プログラムは正常に起動し、おそらくデバッガがアタッチされているので、問題なく動作するようです。

あなたは何をしていますか?このヒープの破損を避けるにはどうすればよいですか?プログラムはこれ以外は正常に動作しているようです。次のように

私の要約コンパイルスクリプトは、(私は簡潔にするためのチェック私の誤りを省略している)である:

@set TARGET=x86 
@set TARGETX=x86 
@set OUT=%TARGETX% 
@call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" %TARGET% 

@set WIMGAPI=C:\Program Files\Windows AIK\SDKs\WIMGAPI\%TARGET% 

set CL=/Zi /nologo /W4 /O2 /GS /EHa /MD /MP /D NDEBUG /D _UNICODE /D UNICODE /D INTEGRATED /Fd%OUT%\ /Fo%OUT%\ 
set INCLUDE=%WIMGAPI%;%INCLUDE% 
set LINK=/nologo /LTCG /CLRIMAGETYPE:IJW /MANIFEST:NO /MACHINE:%TARGETX% /SUBSYSTEM:WINDOWS,6.0 /OPT:REF /OPT:ICF /DEFAULTLIB:msvcmrt.lib 
set LIB=%WIMGAPI%;%LIB% 
set CSC=/nologo /w:4 /d:INTEGRATED /o+ /target:module 

:: Compiling resources omitted 

@set CL_NATIVE=/c /FI"stdafx-native.h" 
@set CL_MIXED=/c /clr /LN /FI"stdafx-mixed.h" 
@set CL_PURE=/c /clr:safe /LN /GL /FI"stdafx-pure.h" 

@set NATIVE=... 
@set MIXED=... 
@set PURE=... 

cl %CL_NATIVE% %NATIVE% 
cl %CL_MIXED% %MIXED% 
cl %CL_PURE% %PURE% 
link /LTCG /NOASSEMBLY /DLL /OUT:%OUT%\core.netmodule %OUT%\*.obj 

csc %CSC% /addmodule:%OUT%\core.netmodule /out:%OUT%\GUI.netmodule /recurse:*.cs 

link /FIXED /ENTRY:GUI.Program.Main /OUT:%OUT%\XXX.exe^
/ASSEMBLYRESOURCE:%OUT%\core.resources,XXX.resources,PRIVATE /ASSEMBLYRESOURCE:%OUT%\GUI.resources,GUI.resources,PRIVATE^
/ASSEMBLYMODULE:%OUT%\core.netmodule %OUT%\gui.res %OUT%\*.obj %OUT%\GUI.netmodule 

アップデート1

デバッグシンボルでこれをコンパイルし、再試行すると、私は実際にはより多くの情報を得る。コールスタックは、次のとおり

msvcr90d.dll!_msize_dbg(void * pUserData, int nBlockUse) Line 1511 + 0x30 bytes 
msvcr90d.dll!_dllonexit_nolock(int (void)* func, void (void)* * * pbegin, void (void)* * * pend) Line 295 + 0xd bytes 
msvcr90d.dll!__dllonexit(int (void)* func, void (void)* * * pbegin, void (void)* * * pend) Line 273 + 0x11 bytes 
XXX.exe!_onexit(int (void)* func) Line 110 + 0x1b bytes 
XXX.exe!atexit(void (void)* func) Line 127 + 0x9 bytes 
XXX.exe!`dynamic initializer for 'Bytes::Null''() Line 7 + 0xa bytes 
mscorwks.dll!6cbd1b5c() 
[Frames below may be incorrect and/or missing, no symbols loaded for mscorwks.dll] 
... 

この(Bytes::Nullための動的初期化子)を '引き起こす' という私のコードの行である:

class Bytes { public: static Bytes Null; } 
:として宣言されるヘッダで

Bytes Bytes::Null; 

私はまた次のようにヘッダ内のグローバルexternを実行しようとしました:

extern Bytes Null; // header 
Bytes Null; // cpp file 

同じ方法で失敗しました。

CRT atexit関数は、静的初期化子のために誤って必要とされているようです。


ベンフォークトは、(ネイティブ静的イニシャライザを含む)任意のCRT関数の使用を指摘したように

を修正(mainCRTStartupWinMainCRTStartup、又は_DllMainCRTStartupで起こる)CRTの適切な初期化を必要とします。私はC++ mainまたはWinMainを持っている混合C++/CLIファイル追加しました:これを実行した後

using namespace System; 
[STAThread] // required if using an STA COM objects (such as drag-n-drop or file dialogs) 
int main() { // or "int __stdcall WinMain(void*, void*, wchar_t**, int)" for GUI applications 
    array<String^> ^args_orig = Environment::GetCommandLineArgs(); 
    int l = args_orig->Length - 1; // required to remove first argument (program name) 
    array<String^> ^args = gcnew array<String^>(l); 
    if (l > 0) Array::Copy(args_orig, 1, args, 0, l); 
    return XXX::CUI::Program::Main(args); // return XXX::GUI::Program::Main(args); 
} 

を、プログラムは現在、さらに少し取得しますが、まだ(他の場所で対処されることになります)の問題があります。

  • プログラムはC#でのみである場合には、それはそれだけで、C++/CLIのメソッドを呼び出すC++/CLIのプロパティを取得し、作成、管理C++/CLIはCにC#と追加
  • イベントオブジェクト++れるたびに伴い、正常に動作します/ CLIコードは決して発射されません(たとえそうであっても)
  • もう一つの奇妙なエラーは例外が発生したということであるヒープ破損が固定されているのでXにXからキャストすることはできませんと言ってInvalidCastExceptionが(Xは、Xと同じです...)

である(でCRTを初期化する)、質問が行われます。

+0

@Foleタイトルを修正していただきありがとうございます。 – coderforlife

答えて

5

EDIT:今後誰かを助ける場合に備えて、推奨されるデバッグ手順を残して問題を発見しました。

問題は、エントリポイントを変更したことです。 onexitリストのような内部リソースを設定するC++/CLI標準ライブラリ提供のエントリポイントを使用する必要があります。

/ENTRYスイッチを削除し、希望のスタートアップルーチンを呼び出す簡単なmain関数を作成します。


別のEXEやDLLを使用すると、最終製品のために許容可能ではないかもしれないが、このシンプルな設定をテストするためには良いだろうとあなたは同じ問題を取得するかどうかを確認します。

別の.DLLでヒープの破損を再現できる場合は、ネイティブのC++コードのどこかにあり、C#を同じファイルに混在させずにデバッグする方がはるかに簡単です。

別のDLLとEXEで問題を再現できない場合は、統合プロセスに関連している可能性があります(リンクされる内容によってレイアウトが変わるため、あまり明らかにならない場合があります)。

ヒープの破損のバグが見つかった場合は、その1つの.EXEに戻ってください。

もう1つの方法は、クラッシュしたときにより良いスタックトレースを得るために、デバッグデータベースを構築することです。リリースビルド(または特にリリースビルド)でも、デバッグ情報を使用してビルドする必要があります。

+0

私はDLL/EXEシステム(Visual Studio内)ですべてをテストしていました。私はCコードのPDBでコンパイルしていましたが、リンクステップではPDBを含めませんでした。上記の完全なデバッグ情報を使用して結果を掲載しました。あなたの考えは? – coderforlife

+0

@thaimin:私は問題があると思う。 'atexit'を含む標準のライブラリ関数を使用する予定がある場合は、CRTのエントリーポイント関数を置き換えることはno-noです。 –

+0

私は意図的にatexitを使用しませんでした! (ただし、後で使用される他のCRT機能があります)。この修正により、新しい問題が発生します。編集した質問を参照してください。 – coderforlife

関連する問題