2009-02-24 52 views
3

我目前正在一個相當大(和老,嘆)代碼庫,最近升級到VS2005(SP1)。我和我的團隊正在改變/更新/替換此代碼中的模塊,但我們偶爾會遇到vtables似乎破裂的問題。我不是vtables的專家,但這些確定似乎已被打破。錯誤表現與此錯誤:VS2005 C++破vtables

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

當然可以有很多其他原因造成的錯誤,但調試(調試版本)時,其實我可以確認爲對象的虛函數表我想上一下運行奇怪:

引用每個vtable的堆棧和堆看起來很好,並且指向vtable的指針與映射文件完全匹配。這表明這不是內存覆蓋錯誤或類似的問題,因爲那樣會影響堆棧和堆,而不是存儲vtables的位置。 (它們被存儲在只讀區域中嗎?)無論如何,目前所有這些看起來都不錯。但是當查看vtable的內存時,我發現所有的值,如果我將它們解釋爲指針,儘管它們在相同的範圍內(例如,0x00f203db 0x00f0f9be 0x00ecdda7 0x00f171e1)與映射文件中的任何條目都不匹配,並且其中很多甚至沒有對齊到4個字節。我不知道VS2005如何構建vtables的所有細節,但這看起來不對。如果這是正確的行爲,也許有人可以向我解釋這一點?

我想我的問題歸結爲什麼會導致這種行爲?例如,當太複雜的類層次結構時,鏈接器中是否有任何已知的錯誤?有沒有人見過類似的東西?目前,我們可以通過將受影響的類的函數移至內聯(可怕的東西!)來解決我們的崩潰問題,但顯然這不是一個可行的長期解決方案。

感謝您的任何見解!

更新:我被問到關於該項目的更多細節,當然我會提供這個。但首先,問題並不完全與ESP值不被保存錯誤相關。我最感興趣的是爲什麼我在vtable中看到奇怪的值。這就是說,這裏有一些額外的信息:解決方案依賴於幾個外部和內部項目,但這些都沒有改變很長一段時間,所有使用相同的調用約定。它似乎打破的代碼都在解決方案的一個非常標準的C++「主」項目中。所有代碼都使用相同的編譯器構建。該解決方案還沒有使用任何DLL,但是用大量靜態庫的鏈接:

SHFolder.lib,python25.lib,DXGUID.LIB,d3d9.lib,d3dx9.lib,dinput8.lib,ddraw.lib,dxerr9 .lib ws2_32.lib mss32.lib Winmm.lib vtuneapi.lib vttriggers.lib DbgHelp.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib ,shell32.lib,ole32.lib,oleaut32.lib,uuid.lib,odbc32.lib,odbccp32.lib

回答

2

我發現了這個問題。真的很傻,但導致問題的類層次結構有一個稱爲GetObject的虛函數,它與#define具有相同名稱的窗口衝突。頭文件以不同的順序包含這些窗口頭文件,這使鏈接器變得混亂。所以,事實上問題是vtables損壞了,但我沒有想到這是理由!那麼你每天都會學到一些東西......

但是,非常感謝所有回覆!

1

我覺得這裏的大提示是在「這通常是調用一個函數聲明的結果一個調用約定與一個函數指針聲明與不同的調用約定「的錯誤的一部分。在我看來,調用者的API和處理該調用的庫之間存在不匹配。

此外,您可能會混淆使用不同編譯器構建的代碼。你還能告訴我們關於這個項目的性質嗎?您正在調用的函數位於外部庫中嗎?或者你可以通過整個調用堆棧進行調試嗎?

編輯:你說該項目不使用任何DLL的。靜態庫呢?

+0

嗨,謝謝!上面的問題增加了一些更多的信息。 – Dan 2009-02-24 09:32:04

+0

bwah ...我很難過,因爲你的構建環境看起來很健全。讓我考慮一下這個問題,並回來一些新的建議/問題。 – 2009-02-24 14:06:38

+0

呵呵,是的,我在這裏也畫了一個空白,除了我看到的奇怪的vtable。感謝您提出任何想法:) – Dan 2009-02-25 03:52:13

0

每當我有這樣的消息時,答案總是涉及重新編譯部分或全部代碼。作爲第一步,我會嘗試全面重建。 Sqook關於外部庫的建議聽起來似乎是合理的,並且如果可能的話,還會涉及到使用與主代碼相同的調用約定來重新編譯該庫。

我有時會發現Build命令可能會遺漏需要重新編譯的文件,這會導致您的消息。再次,全面重建將理順事情。

+0

嗨,謝謝你的建議。我也看到有時通過重建來解決這個問題,但這次似乎並非如此。我們已經重新構建,包括幾臺機器上的所有庫,並獲得每隔一段時間的相同行爲。 – Dan 2009-02-24 09:31:04

0

當我在發生COM錯誤之前就已經發生了這個錯誤。 幾乎總是與重入特別有關 - 你使用COM嗎?你在使用STA,消息過濾器嗎?

1

請注意增量鏈接和Edit + Continue對功能地址(包括v表條目)的影響。它通過一個跳轉表間接調用方法來工作。這允許鏈接器在需要重新定位方法而無需重新鏈接整個圖像時修補跳轉表。該跳轉表中的地址相距5個字節。它們不會出現在.map文件中。切換到組裝視圖並跟蹤執行呼叫時,很容易看到。

這也是您應該用來診斷RTC故障的技術。找出實際調用的方法。最可能的原因是您已將虛擬方法添加到類中,但該類的客戶端未重新編譯。使用v表中的錯誤插槽。當改變接口但不是IID時,傳統上也是COM問題。

0

我有完全相同的問題 - 調用對象上的重載虛函數導致「ESP未正確保存」錯誤,但調試顯示編譯器爲此調用生成了vtable的錯誤偏移量,所以另一個具有更多參數的函數被調用。被調用的函數更新了ESP,就好像調用者已經在堆棧上推入了更多參數一樣,這反過來又導致了返回時無效的ESP值。

在將包含類的頭文件錯誤地放在源文件的頂部之後,問題就消失了。我還沒有進一步調查究竟是什麼導致了這一點,但我想這是爲了同樣的情況 - 一些定義與虛擬成員的聲明混亂。

希望能幫助別人絆倒同樣的問題。