2016-10-17 7 views
2

私はtry catchブロックを持つクリックハンドラの中に単純な関数を持っています。このtry catchブロック内で例外をスローすると、例外が正常にキャッチされます。UnmanagedFunctionPointerは.NET 4.0、3.5を使用しているときにstackoverflowを引き起こします

例外をスローする前にアンマネージDLLを呼び出すと、例外が処理されず、捕捉されません。

私のプログラムの例外処理を壊すかもしれないunamanged DLL呼び出しは何ですか?

プログラムをデバッグモードで実行すると、すべての例外に対して「例外時ブレーク」が発生しても例外がキャッチされます。アプリケーションがクラッシュせず、期待どおりに実行されます。

私はそれが私が次のエラー「スタッククッキー計測コードは、スタックベースのバッファオーバーランを検出し、」取得クラッシュしたときに「デバッグなしで開始」とデバッグを打つ

編集などのプログラムを実行する場合: それが表示されますスタックオーバーフローによって例外処理が中断される

クラッシュを生成する単純化されたプログラムを添付しました。

ISOConnection _comm; //This is instantiated at another time in the same thread 

//C# test function that crashes when run without a debugger attached 
bool DoMagic() 
{ 
    try 
    { 
     //if I uncomment this line the exception becomes unhandled and cannot be caught 
     //_comm.ConnectISO15765(); 

     throw new Exception(); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("Caught exception") 
    } 

//Within ISOConnection class 
public void ConnectISO15765(){ 
    ... 
    lock(syncLock){ 
     uint returnCode = J2534Interface.PassThruConnect((uint)DeviceId, (uint)ProtocolID.ISO15765, (uint)ConnectFlag.NONE, (uint)BaudRate.ISO15765, ref ChannelId); 


//C# UnmanagedFunctionPointer allocation code 
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId); 
public PassThruConnect Connect; 

[DllImport("kernel32.dll")] 
public static extern IntPtr LoadLibrary(string dllToLoad); 

m_pDll = NativeMethods.LoadLibrary(path); 
... 
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "PassThruConnect"); 
if (pAddressOfFunctionToCall != IntPtr.Zero) 
    Connect = (PassThruConnect)Marshal.GetDelegateForFunctionPointer(
     pAddressOfFunctionToCall, 
     typeof(PassThruConnect)); 

//C++ function declaration 
long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long Baudrate, unsigned long *pChannelID); 

UPDATE

私はクラッシュの後

[DllImport("op20pt32.dll", EntryPoint = "PassThruConnect", CallingConvention = CallingConvention.Cdecl)] 
public static extern uint PassThruConnect2(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId); 

を発生しないとUnmanagedFunctionPointer PassThurConnectへの呼び出しを交換した場合、私は行っておりませんまたは私は間違って行っておりますものはありUnmanagedFunctionPointerを割り当てると、デバッガが不足してスタックオーバーフロークラッシュが発生することがありますか?

このコードが数週間前に動作するように見えるのは、他人とは何か。主な変更点は、try catchが別のスレッドにあってロック(syncLock)を使用していないことです。すべてが1つのスレッドにありますが、BackgroundWorkerでも同じクラッシュが発生しました。

UPDATE#2 PROBLEM SEMI-解決しよう

[OK]を、それが働いてまで、私は戻って私のコミットを1つずつ圧延。 .NET 3.5から.NET 4.0への変更点

デバッガの取り付けに関係なく、.NET 3.5はクラッシュしません。デバッガが接続されていないと、.NET 4.0がクラッシュします。私のコードのバグを排除するために、私のログ用のConcurrentQueue(私が使用していた唯一の4.0の機能)を削除し、現在のコードベースを3.5に戻しました。

4.0で問題があることを100%確信させるために、コードベースを3.5から4.0に戻し、ConcurrentQueueをそのまま残しました(文字通りビルドオプションを変更して再構築しました)、StackOverflowクラッシュが戻ってきました。

私はこの問題をデバッグするにはどのようなアイデア4.0を使用することを好むでしょうか?

編集:.NET 4.6。1も3 http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html

はどうやら基本的に問題がまだ存在するので、それだけで自分のアプリケーションをクラッシュしない、.NET 3.5をpinvokestackimbalanceで無視され

のUPDATE位にクラッシュします。

App.Configに次のコードを追加すると、マネージコードに移行するときに.NETがスタックを修復します。小さなパフォーマンスヒットが問題を解決します。

これは問題を解決しますが、最初に問題を引き起こすUnmanagedFunctionPointerの問題点を知りたいと思います。

<configuration> 
    <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/> 

編集:このスレッドが重複し、他の1が削除されていません...

+0

を.Netコードスタックの破損によって捕まえられないいくつかの致命的な例外があります。私はそれらのうちの1つを信じています。おそらくあなたはinteropラッパーを間違えてしまい、スタックの位置がずれる...またはネイティブコードだけが悪いです。 –

+0

これで、マネージコールの直前にDebugger.Launch()を追加し、StackOverflow例外をスローしました。これは疑いの余地なく、例外処理を中断します。デバッガを最初から接続していると、これはなぜ起こりませんか? – rolls

+0

私は同じ関数プロトタイプでdllimportを使用する場合、私はstackoverflowを取得しません。アンマネージ関数ポインタを使うときに何か必要なことはありますか? – rolls

答えて

2

[OK]を問題は呼び出し規約がないCDECL

これは、理にかなってSTDCALLあるべきであるので、ジェネリックJ2534 APIドキュメントでは、次のヘッダを指定しています。私が供給されたヘッダファイルはこの仕様をしていませんが。

extern "C" long WINAPI PassThruConnect 
(
unsigned long ProtocolID; 
unsigned long Flags 
unsigned long *pChannelID 
) 

ここでWINAPIはStdCallではなく、通常C/C++ライブラリのようにCdeclとして知られています。

.NET 3.5は誤った呼び出し規約を許可し、スタックを「修正」します。 4.0では、これはもはやケースではなく、PinvokeStackImbalance例外が発生します。

あなたはまた、次のコードでスタックを修正するために4.0を強制することができ、あなたのapp.config

<configuration> 
    <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/> 

に追加それとも、単にSTDCALLにCDECLを変更することによって、あなたの呼び出し規約を修正することができます:

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID); 
関連する問題