文章目录
1、测试程序如下:
#include "stdafx.h"
#include "CBaseDrvTest.h"
int _tmain(int argc, _TCHAR* argv[])
{
CBaseDrvTest* pBase = new CBaseDrvTest;
pBase->Init();
std::cout << pBase->nValue << std::endl;
delete pBase;
pBase->UnInit();
pBase->nLignt = 111;
std::cout << pBase->nValue << std::endl;
system("pause");
return 0;
}
2、测试时发现测试所用的VS2008有时候也不会触发崩溃,抓取的dump信息如下:
0:000:x86> ~0s; .ecxr ; kb
ntdll_76e90000!NtWaitForMultipleObjects+0xc:
76f032fc c21400 ret 14h
Minidump doesn't have an exception context
Unable to get exception context, HRESULT 0x80004002
ChildEBP RetAddr Args to Child
005df0ec 76647ef3 00000003 005df320 00000001 ntdll_76e90000!NtWaitForMultipleObjects+0xc
WARNING: Stack unwind information not available. Following frames may be wrong.
005df280 76647da8 00000003 005df320 00000000 KERNELBASE!WaitForMultipleObjectsEx+0x133
005df29c 75ec6967 00000003 005df320 00000000 KERNELBASE!WaitForMultipleObjects+0x18
005df348 75ec6598 00000000 00000000 005df43c kernel32!WerpReportFaultInternal+0x3b7
005df364 75e9c299 005df40c 766fce6b 005df43c kernel32!WerpReportFault+0x9d
005df36c 766fce6b 005df43c 00000001 5c7948c7 kernel32!BasepReportFault+0x19
005df40c 76f3287e 005df43c 76f072f2 005dfddc KERNELBASE!UnhandledExceptionFilter+0x29b
005dfddc 76ef8774 ffffffff 76f1a120 00000000 ntdll_76e90000!__RtlUserThreadStart+0x3a109
005dfdec 00000000 00f37b48 00763000 00000000 ntdll_76e90000!_RtlUserThreadStart+0x1b
从上面看,没有相关的堆栈信息,接下来按照之前说过的方法操作,得到
3、从dump信息看,应该是进程在退出的时候free内存出现了问题,导致了崩溃
提示**“scalar deleting destructor”**,怀疑是指针被delete、或者delete之后还使用了指针,即使用了野指针、或者被释放的内存越界等就会出现这个提示
4、除此之没有其他的信息,但是测试用例相对简单,所以我们可以直接查看源代码
5、从代码看,在delete之后,还使用指针访问了成员函数和成员变量。从调试来看,在delete之后,可以调用成员函数,只有当访问成员变量时,程序会中断(对于VS2008来说,也可能不会,偶现)
delete pBase;
pBase->UnInit();
pBase->nLignt = 111;
std::cout << pBase->nValue << std::endl;
因此delete一个指针时,指针指向的内存区域并不会被清空,因为这样会占用CPU周期,此时它是一个危险的指针,会造成一些未定义的现象(或者是个野指针,若打印成员变量的值可能是个随机值)。根据测试情况,有可能发生崩溃有可能不会,因此就会出现,这些代码可能长时间运行不崩溃的情况,接着可能在某个时间点或者修改了某些逻辑后发生了崩溃,这种问题在大型的项目中是比较难发现的,有时候也不好复现。因此在代码编写的时候我们就要养成良好的习惯,在delete指针之后,最好是将其置为NULL,保证我们所使用的是一个有效的指针,而不是会造成不可预见错误的野指针。
使用new或malloc分配内存时,C ++会在内存中找到一些未使用的空间,将其标记为“已分配”(以确保该空间不会在释放前再次被使用),并为我们提供其地址。当使用delete操作指针, C ++会将其指向的内存区域标记为“未分配”,并可能将其交给任何要求它的人。这时候这块空间就可以被其他人进行操作:写入或者读取。因此再次操作类对象或类成员就会出错,因为内存中的内容以及大小都可能发生了变化。