C++ —— 用delete []去释放非[]的对象导致崩溃的原因

假设有个类Test , 定义了Test *p = new Test;    之后却用delete []p 去释放内存,就会导致程序崩溃或者直接进入无限循环。

分析如下:一段测试的代码

#include<iostream>
using namespace std;

class Test
{
public :
	int m_a;
	~Test() {};
};
void main()
{
	Test *p = new Test;
	delete []p;
	cout << "end";
}

这段代码在VS的Debug/Release模式下,程序陷入循环卡死并不打印end,也不异常退出,对delete下断分析:

002322C8  mov         eax,dword ptr [p]                  //eax = 对象的指针
002322CB  mov         dword ptr [ebp-0ECh],eax           //保存对象指针到ebp-0xEC
002322D1  mov         ecx,dword ptr [ebp-0ECh]           //ecx = 对象指针
002322D7  mov         dword ptr [ebp-0E0h],ecx           //0xe0保存对象指针
002322DD  cmp         dword ptr [ebp-0E0h],0             //判断是否为NULL
002322E4  je          main+8Bh (02322FBh)  
002322E6  push        3                                  //释放标志,delete[]为3,delete为1
002322E8  mov         ecx,dword ptr [ebp-0E0h]           //ecx = 对象指针
002322EE  call        Test::`vector deleting destructor' //delete函数
002322F3  mov         dword ptr [ebp-0F4h],eax  
002322F9  jmp         main+95h (0232305h)  

跟进去delete destructor函数再看看:

00232612  mov         eax,dword ptr [ebp+8]              //eax = 释放标记
00232615  and         eax,2                              //判断释放为3
00232618  je          (023265Eh)  
0023261A  push        offset Test::~Test (0231492h)      //push析构函数地址
0023261F  mov         eax,dword ptr [this]               //eax = 对象地址
00232622  mov         ecx,dword ptr [eax-4]              //new[],对象地址前4字节为对象个数
00232625  push        ecx                                //push对象的个数
00232626  push        4  
00232628  mov         edx,dword ptr [this]  
0023262B  push        edx                                //push 对象首地址
0023262C  call        (0231276h)                         //析构代理函数
00232631  mov         eax,dword ptr [ebp+8]  
00232634  and         eax,1                              //看释放标记为1则跳
00232637  je          (0232656h)  
00232639  mov         eax,dword ptr [this]               //对象首地址
0023263C  mov         ecx,dword ptr [eax-4]              //new []保存个数的地方
0023263F  lea         edx,[ecx*4+4]                      //4+个数*大小 = 总内存大小
00232646  push        edx                                //push 释放空间总大小
00232647  mov         eax,dword ptr [this]               //eax = 对象首地址
0023264A  sub         eax,4                              //在new[]下申请的地址要-4
0023264D  push        eax                                //push申请的内存地址
0023264E  call        operator delete[] (0231037h)       //call delete[]
00232653  add         esp,8  

可以看到如果我们程序误用delete[][来删除非new []的对象时候,会将我们对象的前四字节当作对象个数来传入析构代理函数,这里再debug模式下没用用的堆空间为0xFDFDFDFD,所以程序就一直循环,卡死这里

如果这里通过后,下面delete[]仍然会将对象地址-4以及对象[]的总大小进行堆空间的释放,此时就会出现堆空间释放粗偶,导致程序崩溃。

猜你喜欢

转载自blog.csdn.net/a893574301/article/details/81480821