如何在Visual Studio中调试错误的调用堆栈

How to debug an erroneous call stack in Visual Studio

本文关键字:错误 调用 堆栈 调试 Visual Studio      更新时间:2023-10-16

我正在使用一个来自第三方库的巨大类,这里是相关内容的摘录:

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中查看类实例的调度向量?

对于这类问题,我的标准答案是:全部重建。在某些情况下,它就像那样简单/愚蠢(至少对于Visual Studio来说)。

如果错误仍然存在,那么我要做的就是调试:运行代码,直到你能说"它现在不可能发生"。然后一步一步、一行一行地调试,并密切观察调用堆栈。

不,这一点都不好玩。