3

我從一個3-Pary庫龐大類的工作,這裏是相關的東西摘錄:如何調試在Visual Studio中的錯誤調用堆棧

class SomeClass { 
    // ... 
public: 
    // ... 
    virtual int SetTableSize(unsigned int uiTableID, int iSize); 
    // ... 
protected: 
    // ... 
    virtual int Set_0xB0_0x23_IsoTableData(unsigned char* ucData, int iLen); 
    // ... 
}; 

我的應用程序中斷與內存訪問衝突。在調用堆棧最上面的項目是在Set_0xB0_0x23_IsoTableData執行情況的代碼行,第二項是代碼行是這樣的:

someClassInstance.SetTableSize(2, 400); 

在調試視圖,ucData具有價值0x00000002,所以纔像代替根據代碼調用SetTableSize的實現,Set_0xB0_0x23_IsoTableData被調用指定的參數 - 這顯然會導致錯誤,因爲指針是無效的。

我已經花了很多時間弄清楚這裏發生了什麼。我在Linux上使用GCC在不同的應用程序中編譯相同的代碼,並且它在那裏工作。這是一個Visual Studio編譯器錯誤?編譯此代碼時,我沒有收到任何警告。

不可能構建一個最小的工作示例來重現錯誤 - 至少直到我找出發生這種情況的原因爲止。 SomeClass頭部確實有一些#ifdef s,所以我首先想到的是,編譯包含SomeClass的模塊時,預編譯器定義的編譯方式與編譯我的調用代碼時不同。但是,我仔細檢查,定義是相同的。

所以,我要問的是基本上是:

  • 在什麼情況下可以對虛擬方法的調用調用另一個虛擬方法的實現? (這不是關於繼承 - 兩種方法是在同一類中定義的,甚至不共享其簽名並具有不同的可見性)
  • 如何調試此類錯誤?是否有可能在Visual Studio中查看類實例的調度向量?
+0

您可能已經破壞了堆棧,例如通過寫入緩衝區末尾或使用陳舊指針。不幸的是,這可能發生在遠離堆棧中的代碼的地方。 – molbdnilo

+0

這是一個相當常見的模塊邊界問題。進行調用的代碼是使用該類的不兼容視圖構建的。可能是因爲您使用了使用不同版本的編譯器或標準C++庫構建的靜態庫。可能是一個DLL地獄問題。可以像調試和發佈版本一樣簡單。你的問題不包括這些事故。用完全相同的設置重建所有內容。 –

+0

@HansPassant作爲我的解決方案的一部分,我已經從源代碼編譯第三方庫,並且該解決方案由CMake創建,它確保定義相同。 – flyx

回答

0

我對這些問題的標準答案:重建所有。在某些情況下,它至少像Visual Studio一樣簡單/愚蠢。

如果錯誤仍然存​​在,那麼我要做的就是調試:儘可能地運行代碼,直到你可以說「現在不可能發生」。然後逐步調試,一行一行地仔細觀察調用堆棧。

不,這並不好玩。

+0

我已經多次重建所有東西。逐步調試僅顯示我已經知道的內容:方法調用調用錯誤的方法。所有變量值在整個過程中似乎都沒問題。我不知道還有什麼要尋找。 – flyx