Windows.Forms Application.Run()中的不可跟踪异常 [英] Untraceable Exceptions in Windows.Forms Application.Run()

查看:331
本文介绍了Windows.Forms Application.Run()中的不可跟踪异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个正在尝试调试的旧Windows.Forms应用程序。

I have an old Windows.Forms Application that I am trying to debug.

有时运行几分钟后,将产生ArithmeticException或OverflowException。源必须在代码库中的某个位置,但是stacktrace始终指向 Application.Run(mainForm);

Sometimes after running a few minutes it will produce an ArithmeticException or an OverflowException. The source must be somewhere in the codebase, but the stacktrace always points to the line Application.Run(mainForm);

StackTrace是无用的,因为它仅显示Windows.Forms本机调用:

The StackTrace is useless as it only shows Windows.Forms native calls:

 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.

要查找异常的来源,我向
Sys添加了一个异常处理程序。 tem.Windows.Forms.Application.ThreadException System.AppDomain.CurrentDomain.UnhandledException

To find the source of the exception I have added an exception handler to System.Windows.Forms.Application.ThreadException and to System.AppDomain.CurrentDomain.UnhandledException.

我尝试使用
System.Windows.Forms.Application.SetUnhandledExceptionMode();

永远不会调用ThreadException事件处理程序。 UnhandledException事件处理程序只报告我在Visual Studio中看到的相同异常。

The ThreadException event handler is never called. The UnhandledException event handler just reports the same exception I see in Visual Studio.

在Visual Studio中,我启用了抛出异常时中断执行的功能:

这没有任何作用。

In Visual Studio I have enabled breaking execution when an exception is thrown: This had no effect whatsoever.

如何查找有问题的代码行?

What can I do to find the offending line of code?

编辑:完整的异常详细信息:

edit: the full exception details:

如果我在未附加任何调试器的情况下启动该进程,并在附加调试器之前等待其崩溃,则会出现以下异常:

If I start the process without any debugger attached, and wait for it to crash before attaching a debugger, I get the following exception:

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

调试然后导致这种反汇编

Debugging then leads to this piece of disassembly

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

我无法解析,但是我怀疑这仅仅是DispatchMessageW函数

I cannot parse this, but I suspect this is merely the DispatchMessageW function

推荐答案

此处的诊断是,根据您发布的调用堆栈判断,您的流程中存在遗留的非托管代码。

The diagnostic here is that you have legacy unmanaged code in your process, judging from the call stack you posted that's likely to be an old ActiveX control.

这些异常是浮点处理器FPU生成的硬件异常。可以将其置于操作模式中,通过引发异常来报告问题,例如您所看到的STATUS_FLOAT_OVERFLOW和STATUS_FLOAT_INVALID_OPERATION异常。 NaN或非正规化而不是产生无限大。 FMUL指令可以很容易地产生这样的异常。

These exceptions are hardware exceptions generated by the FPU, the floating point processor. Which can be put in an operation mode where it reports problems by raising exceptions, like the STATUS_FLOAT_OVERFLOW and STATUS_FLOAT_INVALID_OPERATION exceptions that you are seeing. Instead of generating infinity, NaN or denormals. The FMUL instruction can easily generate such an exception.

更改FPU操作模式的软件从根本上来说与托管代码不兼容。这要求始终屏蔽FPU异常。掩盖这些异常是完全正常的,并且所有现代软件都可以完成这些操作。但是,早在上个世纪,这些例外就被认为是诊断浮点计算的资产。尤其是,旧的Borland运行时库会掩盖这些异常。

Software that changes the FPU operation mode is pretty fundamentally incompatible with managed code. Which requires that FPU exceptions are always masked. Masking these exceptions is entirely normal and what is done with all modern software. Back in the previous century these exceptions were however considered an asset to diagnose floating point calculations going haywire. In particular, old Borland runtime libraries unmasked these exceptions.

好吧,如果您还没有收到该消息,那将是一个非常糟糕的消息。首先看的是试图诊断为什么此代码引发了浮点异常。坏数据往往是最常见的原因。其次,您真的必须对FPU控制寄存器进行更改,这很容易导致托管代码也失败。特别是WPF代码中的问题,它喜欢使用NaN。

Well, this is all rather bad news in case you didn't get that message yet. First place to look is to try to diagnose why this code is throwing floating point exceptions. Bad data tends to be the most common reason. Secondly, you really have to do something about the FPU control register being changed, this can easily cause managed code to fail as well. Particularly a problem in WPF code, it likes using NaN.

使用调试器查找此类代码非常容易。使用调试+ Windows +注册调试器窗口。右键单击窗口,然后勾选浮点选项。 CTRL寄存器的值至关重要,在托管程序中,该值应为 027F 。首先粗略地浏览程序,当寄存器更改时,您发现了麻烦的产生者。如果它是64位程序,则还要勾选 SSE,MXCSR寄存器应为 00001F80

Finding such code is pretty easy with the debugger. Use the Debug + Windows + Registers debugger window. Right-click the window and tick the "Floating point" option. The value of the CTRL register is crucial, it should be 027F in a managed program. Step through the program, coarse at first, you found the trouble-maker when the register changes. If it is 64-bit program then also tick "SSE", the MXCSR register should be 00001F80.

您无法使用托管代码直接重置FPU控制寄存器,但是可以使用技巧。每当处理异常时,CLR都会将其重置。因此,可能修复方法是在导致控制寄存器值更改的语句之后有意引发并捕获异常:

You cannot directly reset the FPU control register with managed code but you can use a trick. The CLR resets it whenever it handles an exception. So a possible fix is to intentionally throw and catch an exception, after the statement that caused the control register value to change:

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

在msvcrt.dll中调用_controlfp()函数的功能更多直接的方式。但是,当然,由于两者的副作用,因为该库正在以一种非设计的方式运行,所以它当然不会遇到Nan和Infinity值。从长远来看,您确实需要考虑淘汰该旧组件或库。

Pinvoking the _controlfp() function in msvcrt.dll is a more direct way. But of course with the side-effect of both that now that library is operating in a mode that it wasn't designed for, it of course won't expect to encounter Nan and Infinity values. Long term, you really need to consider retiring that old component or library.

这篇关于Windows.Forms Application.Run()中的不可跟踪异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆