【发布时间】:2012-03-17 08:29:19
【问题描述】:
我在 Windows 应用程序中托管 Internet Explorer。我可以向下滚动到文档的底部。然后当我尝试向上滚动时,我得到一个除以零异常:
当我使用 Page Up 滚动时,崩溃似乎发生在调用
- IOleInPlaceActiveObject:TranslateAccelerator
当我使用鼠标滚动时,在调用过程中会发生崩溃
无论哪种方式,崩溃都发生在 Internet Explorer 中。
Delphi 在异常时显示的堆栈跟踪:
与Jedi的异常追踪显示的堆栈追踪不同:
Exception EZeroDivide in module mshtml.dll at 00378B89.
Floating point division by zero.
Exception raised by object: TEmbeddedWB
Full Exception Details:
EZeroDivide
ExceptionCode: 0xC000008E (EXCEPTION_FLT_DIVIDE_BY_ZERO)
The thread tried to divide a floating-point value by a floating-point divisor of zero.
ExceptionFlags: 0x00000002
ExceptionAddress: 0x574C8B89
Parameters: (0x00000000)
EXCEPTION_RECORD: nil
Message: Floating point division by zero
Stack Trace:
[574C8B89] Unknown function at DllGetClassObject + $FF033
[004CA61E] OleCtrls.TOleControl.WndProc (Line 2171, "olectrls.pas" + 12) + $10
[006CF62A] EmbeddedWB.TEmbeddedWB.WBWndProc (Line 1492, "EmbeddedWB.pas" + 31) + $8
[0046200C] Forms.StdWndProc (Line 1459, "Forms.pas" + 8) + $0
[0046D2A2] Forms.TApplication.IsKeyMsg (Line 6588, "Forms.pas" + 20) + $1E
[0046D43F] Forms.TApplication.ProcessMessage (Line 6626, "Forms.pas" + 9) + $2A
[0046D4AB] Forms.TApplication.HandleMessage (Line 6649, "Forms.pas" + 1) + $6
[0046938C] Forms.TCustomForm.ShowModal (Line 4692, "Forms.pas" + 22) + $5
[007D72AD] FMain.TfrmMain.actControlPanelExecute (Line 566, "FMain.pas" + 5) + $5
[00424AF5] Classes.TBasicAction.Execute (Line 8077, "Classes.pas" + 3) + $9
[00455369] ActnList.TContainedAction.Execute + $31
[0045B6AE] Menus.TMenuItem.Click (Line 1738, "Menus.pas" + 9) + $8
[0045CD71] Menus.TMenu.DispatchCommand (Line 2446, "Menus.pas" + 5) + $5
我尝试在 WinDbg 中调试崩溃:
ModLoad: 00000000`75360000 00000000`75372000 C:\Windows\syswow64\DEVOBJ.dll
ModLoad: 00000000`71940000 00000000`719fa000 C:\Windows\SysWOW64\d2d1.dll
ModLoad: 00000000`715e0000 00000000`716ea000 C:\Windows\SysWOW64\DWrite.dll
ModLoad: 00000000`71870000 00000000`718f3000 C:\Windows\SysWOW64\dxgi.dll
ModLoad: 00000000`74fb0000 00000000`74fdd000 C:\Windows\syswow64\WINTRUST.dll
ModLoad: 00000000`71db0000 00000000`71ddc000 C:\Windows\SysWOW64\d3d10_1.dll
ModLoad: 00000000`71900000 00000000`7193a000 C:\Windows\SysWOW64\d3d10_1core.dll
ModLoad: 00000000`6e5c0000 00000000`6e6ec000 C:\Windows\SysWOW64\D3D10Warp.dll
ModLoad: 00000000`6d480000 00000000`6d63b000 C:\Windows\SysWOW64\jscript9.dll
ModLoad: 00000000`714f0000 00000000`714fb000 C:\Windows\SysWOW64\msimtf.dll
ModLoad: 00000000`6f080000 00000000`6f0ab000 C:\Windows\SysWOW64\msls31.dll
ModLoad: 00000000`082c0000 00000000`082fc000 C:\Windows\SysWOW64\Oleacc.dll
ModLoad: 00000000`613e0000 00000000`6140e000 C:\Windows\SysWOW64\MLANG.dll
ModLoad: 00000000`62bb0000 00000000`62cb2000 C:\Windows\SysWOW64\d3d10.dll
ModLoad: 00000000`62b70000 00000000`62ba3000 C:\Windows\SysWOW64\d3d10core.dll
(834.d04): Unknown exception - code c000008e (first chance)
但是因为 Delphi 捕获所有异常,它从不泄露并破坏 WinDbg。 (或者也许这就是 WinDbg 不崩溃的原因)。
如何阻止 Delphi 捕获异常,以便允许应用程序发生故障崩溃,以便我可以获取导致问题的指令。这是一个浮点异常,somewhere 是试图除以零的代码。
其他人在相同的情况下遇到相同的崩溃:
根据 Microsoft 的有用建议,他关闭了任何 3rd 方插件,并尝试在安全模式下运行 IE。
虽然很高兴能够证明我不是唯一遇到此问题的人;我对解决方案更感兴趣。
可以通过要求浮点单元不引发异常,通过使用FLDCW 指令摆弄浮点控制字来屏蔽异常:
procedure TfrmControlPanel.FormCreate(Sender: TObject);
begin
FSaved8087CW := Default8087CW; // Save this because Set8087CW changes it.
Set8087CW($027F); //restore later using Set8087CW(FSaved8087CW);
//$027F comes from http://msdn.microsoft.com/en-us/library/ms235300.aspx
{
Scrolling in browser was causing floating point exceptions
http://stackoverflow.com/questions/9472265/how-to-debug-division-by-zero-exception-in-internet-explorer
What it boils down to is that MS habitually compile their code with FP exceptions masked.
Embarcadero tools habitually unmask them. Thus the MS code is written assuming that FP exceptions
will not be raised and is not resilient to them. To deal with that you have to mask the exceptions
before calling into the MS code. If your app does not floating point then just mask the exceptions
at start up and be done with it. Call Set8087CW($027F) at start up and you are good to go.
Default8087CW: $1332 = 0001 0011 0011 0010
New 8087CW: $027F = 0000 0010 0111 1111
...I RCPC ..MM MMMM
Bit 0: Invalid Operation (IM) |
Bit 1: Denormal Operand (DM) |
Bit 2: Zero Divide (ZM) | Exception Masks (Bits 0..5)
Bit 3: Overflow (OM) | When one of these mask bits is set, its corresponding x87 FPU
Bit 4: Underflow (UM) | floating-point exception is blocked from being generated
Bit 5: Precision (PM) |
Bit 6: (reserved)
Bit 7: (reserved)
Bit 8: +Precision Control (PC) 00=Single Precision (24 bits), 10=Double Precision (53 bits), 11=Double Extended Precision (64 bits), 01=reserved
Bit 9: /
Bit 10: + Rounding Control (RC)
Bit 11: /
Bit 12: Infinity Control | not meaningful for anything past the 80287 math coprocessor
Bit 13: (reserved)
Bit 14: (reserved)
Bit 15: (reserved)
}
不过,我想知道如何找到引发异常的 行。
【问题讨论】:
-
我认为这只是经典问题:您必须设置控制字(Set8087CW)。
-
@AndreasRejbrand 这是所有应用程序都应该始终打开的东西吗?还是应该只打开和关闭以掩盖我遇到的异常? (即,如果我只打开它以在此表单上隐藏此异常,我不知道有多少其他不是我的代码仍然会崩溃)如果它是每个程序都应该始终打开的东西,那么为什么会它默认关闭?
-
归结为 MS 习惯性地在编译代码时屏蔽了 FP 异常。 Embarcadero 工具习惯性地揭开它们的面纱。因此,MS 代码是在假设 FP 异常不会被引发并且对它们没有弹性的情况下编写的。为了解决这个问题,您必须在调用 MS 代码之前屏蔽异常。如果您的应用程序没有浮点,那么只需在启动时屏蔽异常并完成它。在启动时致电
Set8087CW($027F),您就可以开始了。这就是你的解决方案。 -
它在英特尔处理器文档中有记录。需要大量的旋转。不太透明的方法是调用
Math.SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision])。当然,我敢打赌,它是在 D6 中引入的,我想您的项目仍处于良好的旧 D5 中! -
“不过,我想知道如何找到引发异常的行。”那是没有意义的。当你得到这些信息时你会做什么。该代码是在假设 FP 异常被屏蔽的情况下编写的。该代码,引发异常的代码是正确的。它完全按照设计工作。这不是您的代码,您无法更改它。你所能做的就是给它提供它想要的CW。
标签: delphi internet-explorer-9 delphi-5 twebbrowser