Untracked Exceptions in Windows.Forms Application.Run ()

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

Sometimes it throws an ArithmeticException or OverflowException after running for a few minutes. The source should be somewhere in the code base, but the stacktrace always points to the lineApplication.Run(mainForm);

StackTrace is useless as it only displays normal Windows.Forms 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.

      

To find the source of the exception, I added an exception handler for System.Windows.Forms.Application.ThreadException

and System.AppDomain.CurrentDomain.UnhandledException

.

I tried to enable and disable exceptions for catching System.Windows.Forms.Application.SetUnhandledExceptionMode();

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

In Visual Studio, I enabled termination on an exception: enter image description here This had no effect.

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


edit: full details of the details:

enter image description here


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

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

      

Debugging then leads to this disassembly part

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

      

I cannot make out this, but I suspect it is just the DispatchMessageW function

+3


source to share


1 answer


The diagnosis here is that you have legacy unmanaged code in your process, judging by the call stack you posted, which may be an old ActiveX control.

These exceptions are hardware exceptions thrown by FPU, floating point processor. Which can be put into run mode where it reports problems by throwing exceptions like the STATUS_FLOAT_OVERFLOW and STATUS_FLOAT_INVALID_OPERATION exceptions you see. Instead of generating infinity, NaN or denormals. The FMUL statement can easily throw such an exception.

Software that changes the FPU's behavior is fundamentally incompatible with managed code. This requires FPU exceptions to always be masked. The masking of these exceptions is completely normal and what is done with all modern software. However, in the past century, these exceptions have been recognized as an asset for diagnosing floating point computing. In particular, the old Borland runtime libraries exposed these exceptions.

Well, this is all pretty bad news if you haven't received this message yet. The first thing to look at is trying to diagnose why this code is throwing floating point exceptions. Bad data is usually the most common cause. Second, you really need to do something with the changed FPU control register, this can cause managed code to crash. Particularly the problem is in WPF code, it likes to use NaN.



Finding such code is pretty easy with a debugger. Use the Debug + Windows + Registers debug window. Right-click the window and check the Floating Point option. The CTRL register value is critical and must be 027F

in the managed program. Step through the program, roughly at first, you found the problem when the case changed. If it is a 64-bit program, then also check "SSE", the MXCSR register must be 00001F80

.

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

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

      

Calling the _controlfp () function in msvcrt.dll is more direct. But, of course, with the side effect of the library now running in a mode it was not intended for, it certainly won't expect Nan and Infinity values. In the long run, you really need to consider leaving your old component or library.

+5


source







All Articles