我有三个与此问题相关的课程。我正在为应用程序实现硬件服务。 PAPI(Platform API)是一种硬件服务类,用于跟踪各种硬件接口。我已经实现了一个抽象的HardwareInterface类,以及一个派生它的类,名为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的主体中设置断点时,一切都显得正常。然后我在调试器中“跳过”。从函数调用返回后,我对'this'的引用设置为0x00000000。
发生了什么事?它看起来像是在返回堆栈上推送了一个空值?有没有人见过这样的事情发生过?我是否错误地使用虚拟方法?
修改 在进一步解剖之后,我发现在调用write之前我正在读取,而我正在读取的缓冲区是在本地范围内声明的。当新的读取进入时,它们被推入堆栈,破坏它。下一个名为write的函数将返回到已销毁的堆栈。
答案 0 :(得分:1)
缓冲区溢出会丢弃堆栈上的返回地址。您似乎正在使用void指针读取和写入数据包,而不会传递显式大小,因此很可能出现一个简单的溢出错误。 Visual Studio编译器具有添加堆栈完整性检查以检测这些类型的错误的选项,但它们并非100%完美。尽管如此,请确保打开它们。
另请注意,Visual Studio调试器偶尔会(但很少)显示this
的错误值,尤其是在您尝试调试优化代码时。如果您在方法结束时}
处,我不必担心调试器会显示this
的奇怪值。
答案 1 :(得分:0)
经过进一步剖析后,我发现在调用write之前我正在读取,而我正在读取的缓冲区是在本地范围内声明的(在read函数中)。
当新的读取进入时,它们被推入堆栈,破坏它。我调用的下一个函数write将返回一个被破坏的堆栈。