从函数返回将上下文更改为 NULL

Returning from Function changes context to NULL

我有三个 class 与此问题相关。我正在为应用程序实施硬件服务。 PAPI(平台API)是一种硬件服务class,用于跟踪各种硬件接口。我已经实现了一个抽象的 HardwareInterface class,以及一个派生它的 class,称为 HardwareWinUSB。

下面是与我所做的类似的示例。我已经排除了似乎与此问题无关的成员,例如打开 USB 连接的函数:

class PAPI {
    HardwareInterface *m_pHardware;

    PAPI() {
        m_pHardware = new HardwareWinUSB();
    }

    ~PAPI() {
        delete m_pHardware;
    }

    ERROR_CODE WritePacket(void* WriteBuf)
    {
        return m_pHardware->write( WriteBuf);
    }
};

class HardwareInterface {
    virtual ERROR_CODE write( void* WriteBuf) = 0;
};

class HardwareWinUSB : public HardwareInterface
{
    ERROR_CODE write( void* Params)
    {
        // Some USB writing code.
        // This had worked just fine before attempting to refactor
        // Into this more sustainable hardware management scheme
    {
};

我已经为此纠结了几个小时。这是一个奇怪的、可重现的问题,但有时是间歇性的。如果我在更高的上下文中单步执行调试器,事情就会执行得很好。如果我挖掘得不够深入,我会遇到一个错误

Exception thrown at 0x00000000 in <ProjectName.exe>: 0xC0000005: Access violation executing location 0x00000000

如果我深入研究 PAPI 代码,我会看到奇怪的行为。 当我在 WritePacket 的主体中设置断点时,一切看起来都很正常。然后我在调试器中执行 "step over" 。在函数调用 return 之后,我对 'this' 的引用设置为 0x00000000.

这是怎么回事?看起来 return 栈上压入了一个空值?有没有人见过这样的事情发生过?我是否错误地使用了虚拟方法?

编辑 经过进一步的剖析,我发现我在调用 write 之前正在读取,并且我正在读取的缓冲区是在本地范围内声明的。当新的读取进来时,它们被推入堆栈,破坏它。调用的下一个函数 write 将 return 写入已销毁的堆栈。

缓冲区溢出会破坏堆栈中的 return 地址。您似乎正在使用 void 指针读取和写入数据包并且没有传递明确的大小,因此很可能是一个简单的溢出错误。 Visual Studio 编译器可以选择添加堆栈完整性检查来检测这些类型的错误,但它们并非 100% 完美。尽管如此,请确保将它们打开。

另请注意,Visual Studio 调试器有时(但很少)会显示 this 的错误值,尤其是在您尝试调试优化代码时。如果您在方法末尾的 },我不一定会担心调试器显示 this.

的奇怪值

经过进一步剖析,我发现我在调用write之前先读,并且我读入的缓冲区是在本地范围内声明的(在read函数中)。

当新的读取进入时,它们被推入堆栈,破坏它。我调用的下一个函数 write 将 return 写入已销毁的堆栈。