使用 Set8087CW、SetMXCSR 和 TWebBrowser 屏蔽浮点异常 [英] Masking floating point exceptions with Set8087CW, SetMXCSR and TWebBrowser

查看:19
本文介绍了使用 Set8087CW、SetMXCSR 和 TWebBrowser 屏蔽浮点异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我在使用 TWebBrowser 和 TEmbeddedWB 时不时收到浮点除以零"异常,我发现我需要屏蔽除零异常 Set8087CW 或 SetMXCSR.

As I am receiving "Floating point division by zero" exception when using TWebBrowser and TEmbeddedWB from time to time, I discovered that I need to mask division by zero exceptions Set8087CW or SetMXCSR.

问题 1:执行此操作的最佳方法是什么:

Q1: What would be the best approach to do this:

  1. 要在应用程序启动的早期屏蔽此类异常并且不再触碰它们(应用程序是多线程的)?
  2. 使用OnBeforeNavigateOnDocumentComplete 事件来屏蔽/取消屏蔽异常?(加载文档后是否有可能发生异常?)
  1. to mask such exceptions early in the application startup and never touch them again (the app is multithreaded)?
  2. to use OnBeforeNavigate and OnDocumentComplete events to mask / unmask exceptions? (is there a chance that exception could occur after the document is loaded?)

Q2:什么是最好的命令"来屏蔽被零除"而不是别的 - 如果应用程序是 32 位的,是否也需要屏蔽 64 位异常?

Q2: What would be the best "command" to mask only "division by zero" and nothing else - if application is 32-bit is there a need to mask 64 bit exception too?

我正在使用的应用程序具有 TWebBrowser 控件,可始终用于显示电子邮件内容.

The application I am using it it has TWebBrowser control available all the time for displaying email contents.

另外,如果有人可以澄清 - 这是来自 Microsoft 的 TWebBrowser 控件的特定错误还是 Delphi/C++ Builder 和 Microsoft 工具之间的区别?如果我在 Visual C++ 应用程序中托管 TWebBrowser 会发生什么,如果出现除以零错误 - 它不会被转换为异常,但会发生什么 - Visual C++ 将如何处理除以零"异常呢?

Also, if anyone can clarify - is this a particular bug with TWebBrowser control from Microsoft or just difference between Delphi/C++ Builder and Microsoft tools? What would happen if I would host TWebBrowser inside Visual C++ application if division by zero error would appear - it wouldn't be translated into exception but what would happen then - how would Visual C++ handle "division by zero" exception then?

微软这么长时间没有注意到这个问题有点奇怪 - 也奇怪的是 Embarcardero 也从来没有注意到它.因为屏蔽浮点异常也有效地屏蔽了您自己的程序异常用于特定目的.

It is kind of strange that Microsoft didn't notice this problem for such a long time - also it is strange that Embarcardero never noticed it too. Because masking floating point exception effectively also masks your own program exception for that particular purpose.

更新

经过一些检查,我的最终解决方案是:

My final solution after some examination is:

SetExceptionMask(GetExceptionMask() << exZeroDivide);

GetExceptionMask() 的默认状态返回:TFPUExceptionMask() <<exDenormalized<.很明显,一些异常已经被屏蔽了——这只是将 exZeroDivide 添加到被屏蔽的异常中.

The default state from GetExceptionMask() returns: TFPUExceptionMask() << exDenormalized << exUnderflow << exPrecision. So obviously, some exceptions are already masked - this just adds exZeroDivide to the masked exceptions.

因此,现在每除以零都会导致 +INF 浮点数而不是异常.我可以接受 - 对于代码的生产版本,它会被屏蔽以避免错误,对于调试版本,它将被取消屏蔽以检测浮点除以零.

As a result every division by zero now results with +INF in floating point instead of exception. I can live with that - for the production version of the code it will me masked to avoid errors and for the debug version it will be unmasked to detect floating point division by zero.

推荐答案

假设您不需要在应用程序代码中取消屏蔽浮点异常,最简单的方法就是在某个时刻屏蔽异常在您的初始化代码中.

Assuming that you have no need for floating point exceptions to be unmasked in your application code, far and away the simplest thing to do is to mask exceptions at some point in your initialization code.

最好的方法是这样:

SetExceptionMask(exAllArithmeticExceptions);

这将在 32 位目标上设置 8087 控制字,在 64 位目标上设置 MXCSR.您将在 Math 单元中找到 SetExceptionMask.

This will set the 8087 control word on 32 bit targets, and the MXCSR on 64 bit targets. You will find SetExceptionMask in the Math unit.

如果您希望在您的代码中不屏蔽浮点异常,那么它就会变得棘手.一种策略是在取消屏蔽异常的专用线程中运行您的浮点代码.这当然可以工作,但如果您依赖 RTL 函数 Set8087CWSetMXCSR,则不行.请注意,RTL 中控制 FP 单元的所有内容都通过这些函数进行路由.例如 SetExceptionMask 可以.

If you wish to have floating point exceptions unmasked in your code then it gets tricky. One strategy would be to run your floating point code in a dedicated thread that unmasks the exceptions. This certainly can work, but not if you rely on the RTL functions Set8087CW and SetMXCSR. Note that everything in the RTL that controls FP units routes through these functions. For example SetExceptionMask does.

问题在于 Set8087CWSetMXCSR 不是线程安全的.似乎很难相信 Embarcadero 会如此无能,以至于产生了在线程上下文上运行但又不能保证线程安全的基本例程.但这就是他们所做的.

The problem is that Set8087CW and SetMXCSR are not threadsafe. It seems hard to believe that Embarcadero could be so inept as to produce fundamental routines that operate on thread context and yet fail to be threadsafe. But that is what they have done.

要消除他们留下的烂摊子是非常困难的,并且要做到这一点需要大量的代码修补.缺乏线程安全性归结为(误)使用全局变量 Default8087CWDefaultMXCSR.如果两个线程同时调用Set8087CWSetMXCSR,那么这些全局变量可能会导致值从一个线程泄漏到另一个线程.

It's surprisingly hard to undo the mess that they have left, and to do so involves quite a bit of code patching. The lack of thread safety is down to the (mis)use of the global variables Default8087CW and DefaultMXCSR. If two threads call Set8087CW or SetMXCSR at the same time then these global variables can have the effect of leaking the value from one thread to the other.

您可以将 Set8087CWSetMXCSR 替换为不改变全局状态的版本,但遗憾的是它没有那么简单.全局状态用于其他各种地方.这可能看起来不谦虚,但如果您想了解更多关于此事的信息,请阅读我附在此 QC 报告中的文档:http://qc.embarcadero.com/wc/qcmain.aspx?d=107411

You could replace Set8087CW and SetMXCSR with versions that did not change global state, but it's sadly not that simple. The global state is used in various other places. This may seem immodest, but if you want to learn more about this matter, read my document attached to this QC report: http://qc.embarcadero.com/wc/qcmain.aspx?d=107411

这篇关于使用 Set8087CW、SetMXCSR 和 TWebBrowser 屏蔽浮点异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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