3

デバッグしようとしている古い Windows.Forms アプリケーションがあります。

数分実行すると、ArithmeticException または OverflowException が生成されることがあります。ソースはコードベースのどこかにある必要がありますが、スタックトレースは常に次の行を指していますApplication.Run(mainForm);

StackTrace は、Windows.Forms のネイティブ コールのみを表示するため、役に立ちません。

 bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   bei System.Windows.Forms.Application.Run(Form mainForm)
   bei Program.Main() in C:\xy\Program.cs:Zeile 102.

System.Windows.Forms.Application.ThreadException例外の原因を見つけるために、と に例外ハンドラを追加しました System.AppDomain.CurrentDomain.UnhandledException

例外のキャッチを有効または無効にしようとしました System.Windows.Forms.Application.SetUnhandledExceptionMode();

ThreadException イベント ハンドラが呼び出されることはありません。UnhandledException イベント ハンドラーは、Visual Studio で見られるのと同じ例外を報告するだけです。

Visual Studio では、例外がスローされたときに実行の中断を有効にしました。 ここに画像の説明を入力 これはまったく効果がありませんでした。

問題のあるコード行を見つけるにはどうすればよいですか?


編集:完全な例外の詳細:

ここに画像の説明を入力


デバッガーをアタッチせずにプロセスを開始し、クラッシュするのを待ってからデバッガーをアタッチすると、次の例外が発生します。

Unbehandelte Ausnahme bei 0x0c9f9e1b in program.exe: 0xC0000090: Floating-point invalid operation.

デバッグは、この逆アセンブルにつながります

0C9F9E12  add         esi,10h 
0C9F9E15  push        0CA1FD48h 
0C9F9E1A  push        eax  
0C9F9E1B  fmul        qword ptr ds:[0CA202E0h] 
0C9F9E21  fstp        dword ptr [esp+18h] 

これを解析することはできませんが、これは単に DispatchMessageW 関数であると思われます

4

1 に答える 1

8

ここでの診断は、古い ActiveX コントロールである可能性が高い投稿されたコール スタックから判断して、プロセスにレガシ アンマネージ コードがあることです。

これらの例外は、浮動小数点プロセッサである FPU によって生成されるハードウェア例外です。表示されている STATUS_FLOAT_OVERFLOW や STATUS_FLOAT_INVALID_OPERATION 例外など、例外を発生させて問題を報告する操作モードにすることができます。無限大、NaN、またはデノーマルを生成する代わりに。FMUL 命令は、このような例外を簡単に生成できます。

FPU の動作モードを変更するソフトウェアは、基本的にマネージ コードと互換性がありません。これには、FPU 例外を常にマスクする必要があります。これらの例外をマスクすることは完全に正常であり、最新のすべてのソフトウェアで行われています。ただし、前世紀には、これらの例外は、浮動小数点計算がうまくいかないことを診断するための資産と見なされていました。特に、古い Borland ランタイム ライブラリは、これらの例外のマスクを解除しました。

ええと、まだそのメッセージを受け取っていない場合、これはかなり悪いニュースです。最初に確認することは、このコードが浮動小数点例外をスローしている理由を診断することです。不良データが最も一般的な理由です。第 2 に、FPU 制御レジスタの変更について何かを行う必要があります。これにより、マネージ コードも簡単に失敗する可能性があります。特に WPF コードの問題で、NaN を好んで使用します。

デバッガーを使用すると、そのようなコードを簡単に見つけることができます。Debug + Windows + Registers デバッガー ウィンドウを使用します。ウィンドウを右クリックし、「浮動小数点」オプションにチェックマークを付けます。027FCTRL レジスタの値は非常に重要です。マネージド プログラム内にある必要があります。プログラムをステップ実行します。最初は粗いですが、レジスタが変更されたときにトラブルメーカーを見つけました。64 ビット プログラムの場合は、"SSE" にもチェックを入れます。MXCSR レジスタは00001F80.

マネージ コードを使用して FPU 制御レジスタを直接リセットすることはできませんが、トリックを使用できます。CLR は、例外を処理するたびにそれをリセットします。したがって、可能な修正は、制御レジスタ値を変更するステートメントの後で、意図的に例外をスローしてキャッチすることです。

        try {  throw new Exception("Resetting FPU control register, please ignore"); }
        catch { }

msvcrt.dll で _controlfp() 関数を呼び出すのが、より直接的な方法です。しかしもちろん、そのライブラリが設計されていないモードで動作しているという両方の副作用があるため、Nan と Infinity の値に遭遇することはもちろん期待できません。長期的には、その古いコンポーネントまたはライブラリを廃止することを検討する必要があります。

于 2013-01-22T19:00:34.587 に答える