C++逆向分析——new和delete new[]和delete[]

在堆中创建对象

我们可以在什么地方创建对象?

  1. 全局变量区,在函数外面

  2. 在栈中创建对象,也就是函数内

  3. 在堆中创建对象

注意:之前一直提到的堆栈实际上是两个概念->堆、栈,我们之前所讲的就是栈,从本章开始要严格区分。

在C语言中,我们可以通过一个函数去申请一块内存,就是malloc(N);申请的这一块内存就是在堆中的。

在堆中创建对象我们可以使用new、delete这两个关键词来创建和释放:

Person* p = new Person();
delete p;

我们可以来实际的看一下new、delete这两个关键词主要做了什么。

首先我们使用new关键词的时候会发现,其除了在堆中创建了对象还会调用构造函数:

images/download/attachments/12714553/image2021-4-4_22-10-14.png

再跟进看看使用delete,它会释放空间并调用析构函数

images/download/attachments/12714553/image2021-4-4_22-11-41.png

我们想要了解其本质,还是要去跟一下汇编代码,这里跟一下new关键词的执行流程看看其分别调用的函数(跟进call operator new (004012e0)):

images/download/attachments/12714553/image2021-4-4_22-17-13.png

而后调用了构造函数:call @ILT+0(Person::Person) (00401005)

我们再来跟下malloc函数的调用步骤:

call malloc (00401a20) → _nh_malloc_dbg → _heap_alloc_dbg → _heap_alloc_base → HeapAlloc

那么这时候一下就清楚了new的本质,实际上就是malloc+构造函数,同样的方法可以跟下delete看下它跟free函数。

跟进delete关键词,会发现其会先调用析构函数函数然后再去调用operator delete然后就是_free_dbg:

images/download/attachments/12714553/image2021-4-4_22-30-48.png

所以delete的本质就是析构函数+free。

如果我们想要在堆中申请数组,需要使用new[]、delete[]这两个关键词来创建和释放。

// C、C++的方式在堆中申请、释放int数组
int* p = (int*)malloc(sizeof(int)*10); free(p);
int* p = new int[10]; delete[] p;
 
// C、C++的方式在堆中申请、释放Class类型数组
Person* p = (Person*)malloc(sizeof(Person)*10); free(p);
Person* p = new Person[10]; delete[] p;

malloc和new[]的区别:

  1. malloc不会调用构造函数

  2. new[]会调用构造函数,创建一次则调用一次,例如new Person[10]则调用10次

同理也可以知道free和delete[]的区别。

delete和delete[]是有区别的,如果使用new[]在堆中创建对象,使用delete去释放则只会释放第一个对象,其他的不会释放。

 

手动实践下:

 

#include <stdio.h>
class Person {
private:
	int age;
	int sex;

public:
	Person(int a, int b) {
		age = a;
		sex = b;
	}

	Person() {
		age = 0;
		sex = -1;
	}
};


void main() {
	Person* p = new Person;
	delete p;
	// Person* p = new Person[3];
	// delete[] p;
	p = nullptr;
	return;
}

 反汇编的代码贴下:

Person* p = new Person;
00275914 6A 08                push        8  ;size==8,因为person空间大小
00275916 E8 FD B7 FF FF       call        operator new (0271118h) ;malloc好  
0027591B 83 C4 04             add         esp,4  
0027591E 89 85 14 FF FF FF    mov         dword ptr [ebp-0ECh],eax  
00275924 C7 45 FC 00 00 00 00 mov         dword ptr [ebp-4],0  
0027592B 83 BD 14 FF FF FF 00 cmp         dword ptr [ebp-0ECh],0  
00275932 74 13                je          __$EncStackInitStart+5Dh (0275947h)  
00275934 8B 8D 14 FF FF FF    mov         ecx,dword ptr [ebp-0ECh]  
0027593A E8 CC BA FF FF       call        Person::Person (027140Bh)  ;在malloc地址基础上去调用构造函数
0027593F 89 85 00 FF FF FF    mov         dword ptr [ebp-100h],eax  
00275945 EB 0A                jmp         __$EncStackInitStart+67h (0275951h)  
00275947 C7 85 00 FF FF FF 00 00 00 00 mov         dword ptr [ebp-100h],0  
00275951 8B 85 00 FF FF FF    mov         eax,dword ptr [ebp-100h]  
00275957 89 85 20 FF FF FF    mov         dword ptr [ebp-0E0h],eax  
0027595D C7 45 FC FF FF FF FF mov         dword ptr [ebp-4],0FFFFFFFFh  
00275964 8B 8D 20 FF FF FF    mov         ecx,dword ptr [ebp-0E0h]  
0027596A 89 4D EC             mov         dword ptr [p],ecx  
	delete p;
0027596D 8B 45 EC             mov         eax,dword ptr [p]  
00275970 89 85 08 FF FF FF    mov         dword ptr [ebp-0F8h],eax  
00275976 6A 08                push        8  
00275978 8B 8D 08 FF FF FF    mov         ecx,dword ptr [ebp-0F8h]  
0027597E 51                   push        ecx  
0027597F E8 FE B6 FF FF       call        operator delete (0271082h)  ;delete
00275984 83 C4 08             add         esp,8  
00275987 83 BD 08 FF FF FF 00 cmp         dword ptr [ebp-0F8h],0  
0027598E 75 0C                jne         __$EncStackInitStart+0B2h (027599Ch)  
00275990 C7 85 00 FF FF FF 00 00 00 00 mov         dword ptr [ebp-100h],0  
0027599A EB 10                jmp         __$EncStackInitStart+0C2h (02759ACh)  
0027599C C7 45 EC 23 81 00 00 mov         dword ptr [p],8123h  
002759A3 8B 55 EC             mov         edx,dword ptr [p]  
002759A6 89 95 00 FF FF FF    mov         dword ptr [ebp-100h],edx  
	// Person* p = new Person[3];
	// delete[] p;
	p = nullptr;
002759AC C7 45 EC 00 00 00 00 mov         dword ptr [p],0  

return;

 类似的讲解:

换成数组:

#include <stdio.h>
class Person {
private:
	int age;
	int sex;

public:
	Person(int a, int b) {
		age = a;
		sex = b;
	}

	Person() {
		age = 0;
		sex = -1;
	}
};


void main() {
	Person* p = new Person[3];
	delete[] p;
	p = nullptr;
	return;
}

 反汇编比较复杂,todo吧。

 

 

posted @ 2023-04-09 10:47  bonelee  阅读(59)  评论(0编辑  收藏  举报