簡體   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