繁体   English   中英

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

[英]Third party code is modifying the FPU control word

介绍 - 漫长而无聊的部分

(问题在最后)

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

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

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

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

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

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

问题

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

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

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

更新

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

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

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

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

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

我认为您的诊断该组件是用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%的结论性答案,但我无法将所有这些想法发表评论!

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM