从函数返回将上下文更改为 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 写入已销毁的堆栈。
我有三个 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 写入已销毁的堆栈。