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

时间:2011-08-03 21:44:02

标签: windows delphi com components fpu

介绍 - 冗长乏味的部分

(问题在最后)

对于不断更改FPU控制字的第三方COM组件,我的头疼得厉害。

我的开发环境是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控制字,只是让执行继续,因为没有发生任何事情 - 那么所有的赌注都关闭了吗?
  3. 更新

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

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

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

    1. 包裹我的消息泵
    2. 安装窗口挂钩(WH_CALLWNDPROC)以捕获绕过消息泵的转角情况
    3. 在这两种情况下,我都会检查FPU CW是否已更改。如果有,我将其重置为_CW_DEFAULT

2 个答案:

答案 0 :(得分:6)

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

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

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

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

我相信您唯一可行的解​​决方案是将FPU设置为执行到达代码时所需的FPU,并在执行离开代码时将其恢复。我对COM事件接收器知之甚少,无法理解它们为什么会出现这样的障碍。

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

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

但是,由于游戏没有规则,我相信COM对象供应商在拒绝更改代码并将责任重新放在您身上时是合理的。

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

答案 1 :(得分:6)

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

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

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