第三方代码正在修改FPU控制字

Jör*_*son 10 windows delphi com components fpu

介绍 - 漫长而无聊的部分

(问题在最后)

我正在对第三方COM组件产生严重的头痛,这些组件不断更改FPU控制字.

我的开发环境是Windows和Visual C++ 2008.普通的FPU控制字指定在各种条件下不应抛出任何异常.我已经通过查看中_CW_DEFAULT找到的宏float.h以及在启动时查看调试器中的控制字来验证这一点.

每次我调用COM对象时,控制字在返回时被修改.这很容易防御.我只是重置控制字,一切都很好.问题是当COM组件开始调用我的事件接收器时.我可以在收到事件调用后立即通过重置控制字来保护我的代码,但是一旦从事件调用返回,我就无法做任何事情.

我没有此COM组件的源代码,但我与作者联系.我从他那里得到的回答是"嗯?".我不认为他对我正在谈论的内容有任何线索,所以我担心自己必须对此做些什么.我相信他的运行时(我认为它是Delphi或Borland C++,因为DLL中充满了符号名称,都以大写字母T开头),或者他正在使用的其他一些第三方代码,这导致了问题.我不认为他的代码明确地修改了FPU控制字.

那么,我该怎么办?从业务角度来看,必须使用此第三方组件.从技术角度来看,我可以抛弃它,并自己实现通信协议.然而,这将是非常昂贵的,因为该协议涉及处理信用卡交易.我们不想承担责任.

我迫切需要一个关于Borland产品中FPU设置的黑客或一些有用的信息,我可以传递给组件的作者.

问题

有什么能做的吗?我不认为组件作者有什么需要解决它(通过他的相当无知的回答判断).

我一直在想着安装自己的异常处理程序,我只是在处理程序中重置控制字,并告诉Windows继续执行.我试过安装处理程序SetUnhandledExceptionFilter(),但由于某种原因,没有捕获异常.

  1. 为什么我不抓住例外?
  2. 如果我成功捕获FPU异常,重置FPU控制字,只是让执行继续,因为没有发生任何事情 - 所有赌注都关闭了吗?

更新

我想感谢大家的建议.我已经向作者发送了关于他可以做些什么的说明,以便让我的生活变得更轻松,而不仅仅是我的代码的许多其他客户.我向他建议他应该对FPU控制字进行采样DllMain(DLL_PROCESS_ATTACH),并保存控制字以供日后使用,这样他就可以在调用我的事件处理程序之前重置FPU CW,并从我的调用中返回.

就目前而言,如果有人有兴趣,我会有一个黑客攻击.黑客攻击可能是一个糟糕的,因为我不知道它对他的代码会做什么.我之前收到的确认是他在代码中没有使用任何浮点数,所以这应该是安全的,除非他使用的某些第三方代码依赖于FPU异常.

我对我的应用程序进行的两项修改:

  1. 包裹我的消息泵
  2. 安装一个窗口挂钩(WH_CALLWNDPROC)以捕获绕过消息泵的转角情况

在这两种情况下,我都会检查FPU CW是否已更改.如果有,我将其重置为_CW_DEFAULT.

Dav*_*nan 6

我认为您的诊断该组件是用Embarcadero产品编写的,很可能是真的.Delphi的运行时库确实启用了浮点异常,对于C++ Builder也是如此.

Embarcaderos工具的一个好处是浮点错误被转换成语言异常,这使得数字编码更容易.这对你来说几乎没什么安慰!

整个区域都是庞大的PITA.关于FP控制字没有任何规则.这是一个完全免费的.

我不相信捕获未处理的异常不会完成任务,因为MS C++运行时可能已经捕获了这些异常,但我不是那个领域的专家,我可能错了.

我相信您唯一可行的解​​决方案是将FPU设置为执行到达代码时所需的FPU,并在执行离开代码时将其恢复.我不太了解COM事件接收器,以了解它们为什么会出现这样做的障碍.

我的产品包含一个用Delphi实现的DLL,我遇到了相反的问题.通常,调用的客户端具有禁用异常的FPU控制字.我们采用的策略是在进入时记住8087CW,在执行代码之前将其设置为标准Delphi CW,然后在出口点恢复它.在进行回调之前,我们还会通过恢复来电者的8087CW来处理回调问题.这是一个普通的DLL而不是COM对象,因此它可能更简单一些.

如果您决定尝试让COM供应商修改他们的代码,那么他们需要调用该Set8087CW()函数.

但是,由于游戏没有规则,我相信COM对象供应商在拒绝更改代码并将责任推回给您时是合理的.

对不起,如果这不是一个100%的结论性答案,但我无法将所有这些想法发表评论!


She*_* 蒋晟 6

虽然FP控制字是每线程的,但是在创建新线程时会调用dllmain函数,我认为你不能避免这种新的进程.

我建议您分拆一个新进程来运行COM并使用您最喜欢的进程间通信方法(例如Windows消息,进程外COM,命名管道,套接字等)与进程聊天.通过这种方式,COM服务器可以自由地进行各种损坏(包括崩溃),而不会导致主机进程崩溃.

另一个想法是编写一个DLL,其唯一目的是重置其DllMain中的FPU并在违规DLL之后立即加载它.Windows可能正在使用加载顺序在创建新线程时调用DllMain,包括COM服务器创建的线程.请注意,这取决于Windows的内部行为.此外,COM服务器实际上可能依赖于fp异常,因为它启用了它们.禁用FP异常可能会导致COM服务器意外运行.