首页 > 代码库 > VS2013下的new[]和delete[]分析

VS2013下的new[]和delete[]分析

编译模式:Debug
编译环境:Microsoft Visual Studio Ultimate 2013 (12.0.30501.00) Update 2
//////////////////////////////////////////////////////////////////////////////
一. New[]:
C++代码:
  int *lpNum = new int[16];

汇编代码:
PUSH 0x40                      ; new申请的空间大小
CALL XXXXXXXX                   ; CALL NEW
ADD ESP, 0x4                     ; _cdecl调用约定的平栈
MOV DWORD PTR SS:[EBP-0xD4], EAX          ; 把返回值(申请空间的地址)给临时变量(猜测用于保存)
MOV EAX, DWORD PTR SS:[EBP-0xD4]              ; 从临时变量中取出地址
MOV DWORD PTR SS:[EBP-0x8], EAX             ; 赋值给函数内的指针

看一下New里面干了什么:

PUSH EBP                       ; void *New(int nSize);
MOV EBP, ESP                      ; ebp+0x8 nSize的栈空间
SUB ESP, 0x10
MOV EAX, DWORD PTR SS:[EBP+0x8]          ; 取nSize
PUSH EAX                        ; 压入nSize
CALL malloc                         ; call malloc
ADD ESP, 0x4                      ; _cdecl调用约定的平栈
MOV DWORD PTR SS:[EBP-0x4], EAX          ; 返回值为malloc申请的地址
CMP DWORD PTR SS:[EBP-0x4], 0x0         ; 如果返回值 == NULL
JNZ SHORT msvcr120.0FB0C2A3
MOV ECX, DWORD PTR SS:[EBP+0x8]          ; 取大小
PUSH ECX                        ; 压入大小
CALL _callnewh                     ; _callnewh(size)
ADD ESP, 0x4                     ; _cdecl调用约定的平栈
TEST EAX, EAX                     ; 如果返回值等于 NULL
JNZ SHORT msvcr120.0FB0C2A1
LEA ECX, DWORD PTR SS:[EBP-0x10]
CALL bad_alloc                      ; call bad_alloc
PUSH msvcr120.0FB753D8
LEA EDX, DWORD PTR SS:[EBP-0x10]
PUSH EDX
CALL _CxxThrowException               ; CALL _CxxThrowException
JMP SHORT msvcr120.0FB0C266
MOV EAX, DWORD PTR SS:[EBP-0x4]          ; 不等于NULL,返回值给EAX,返回到main函数
MOV ESP, EBP
POP EBP
RETN

因VS2013无法查看其实现代码,以下为个人猜测如有错误忘请不吝赐教:

void* _cdecl operator new(unsigned int nSize)_THROW1(_STD bad_alloc)
{
  void *lpBuf;
  while ((lpBuf = malloc(nSize)) == NULL)
  {
    if (_callnewh(nSize) == NULL)
    {
      static const std::bad_alloc nomem;
      _RAISE(nomem);
    }
  }
  return lpBuf;
}

二. Delete[]:
C++代码:
  int *lpNum = new int[16];
  delete lpNum;

汇编代码:
MOV EAX, DWORD PTR SS:[EBP-0x8]         ; 从变量中取出lpNum地址
MOV DWORD PTR SS:[EBP-0xD4], EAX         ; 放入临时变量EBP-0xD4
MOV ECX, DWORD PTR SS:[EBP-0xD4]          ; 从临时变量中取出地址
PUSH ECX                          ; 压入参数
CALL NewDELET.013011DB               ; call delete
ADD ESP, 0x4                      ; _cdecl调用约定平栈
CMP DWORD PTR SS:[EBP-0xD4], 0x0        ; 判断临时变量EBP-0xD4中的地址值是否等于NULL
JNZ SHORT NewDELET.01301A54
MOV DWORD PTR SS:[EBP-0xE8], 0x0        ; 如果临时变量EBP-0xD4不为NULL就把临时变量EBP-0xE8填为NULL
JMP SHORT NewDELET.01301A64
MOV DWORD PTR SS:[EBP-0x8], 0x8123        ; 给lpNum传入一个值0x8123
MOV EDX, DWORD PTR SS:[EBP-0x8]          ; 从lpNum取出值
MOV DWORD PTR SS:[EBP-0xE8], EDX          ; 临时变量EBP-0xE8填为0x8123

看一下Delete里面干了什么:

PUSH EBP                       ; void _cdecl operator delete (void *pBuf)
MOV EBP, ESP                     ; EBP+0x8 pBuf的栈空间
PUSH -0x2
PUSH msvcr120.52499400
PUSH msvcr120.5243FEF0
MOV EAX, DWORD PTR FS:[0]
PUSH EAX
ADD ESP, -0xC
PUSH EBX
PUSH ESI
PUSH EDI
MOV EAX, DWORD PTR DS:[0x524A8100]
XOR DWORD PTR SS:[EBP-0x8], EAX
XOR EAX, EBP
PUSH EAX
LEA EAX, DWORD PTR SS:[EBP-0x10]
MOV DWORD PTR FS:[0], EAX
CMP DWORD PTR SS:[EBP+0x8], 0x0           ; 判断pBuf是否 == NULL
JNZ SHORT msvcr120.5243A9CB
JMP msvcr120.5243AA68                  ; 跳向函数尾部 (return)
PUSH 0x4 ; 4
CALL msvcr120._lock                     ; call _lock
ADD ESP, 0x4                          ; _cdecl调用约定平栈
MOV DWORD PTR SS:[EBP-0x4], 0x0
MOV EAX, DWORD PTR SS:[EBP+0x8]           ; pBuf - 0x20
SUB EAX, 0x20
MOV DWORD PTR SS:[EBP-0x1C], EAX                ; 临时变量[EBP-0x1C] = pBuf - 0x20
MOV ECX, DWORD PTR SS:[EBP-0x1C]            ; 取出运算后的pBuf
MOV EDX, DWORD PTR DS:[ECX+0x14]              ; 取pBuf+0x14 由此可以判断ebp-0x1c是一个结构体变量 结果为1 是个逻辑值
AND EDX, 0xFFFF
CMP EDX, 0x4                        ; [[EBP-0x1C]+0x14] & 0xffff != 4
JE SHORT msvcr120.5243AA3C
MOV EAX, DWORD PTR SS:[EBP-0x1C]
CMP DWORD PTR DS:[EAX+0x14], 0x1           ; [[EBP-0x1C]+0x14] != 0x1
JE SHORT msvcr120.5243AA3C
MOV ECX, DWORD PTR SS:[EBP-0x1C]
MOV EDX, DWORD PTR DS:[ECX+0x14]
AND EDX, 0xFFFF                        ; [[EBP-0x1C]+0x14] & 0xffff != 0x2
CMP EDX, 0x2
JE SHORT msvcr120.5243AA3C
MOV EAX, DWORD PTR SS:[EBP-0x1C]
CMP DWORD PTR DS:[EAX+0x14], 0x3             ; [[EBP-0x1C]+0x14] != 0x3
JE SHORT msvcr120.5243AA3C
PUSH msvcr120.52321BF8                    ; UNICODE "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"
PUSH msvcr120.5230127C                   ; UNICODE "%s"
PUSH 0x0                            ; NULL
PUSH 0x34                            ; __LINE__
PUSH msvcr120.52321C48                    ; __FILE__
PUSH 0x2
CALL msvcr120._CrtDbgReportW   ; call _CrtDbgReportW : _CrtDbgReportW(0x2,?,0x34,0x0,%s,_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))

ADD ESP, 0x18                         ; _cdecl调用约定平栈
CMP EAX, 0x1                         ; if( _CrtDbgReportW == 1)
JNZ SHORT msvcr120.5243AA3C
INT3
MOV EDX, DWORD PTR SS:[EBP-0x1C]
MOV EAX, DWORD PTR DS:[EDX+0x14]
PUSH EAX ; push [[EBP-0x1C]+0x14]
MOV ECX, DWORD PTR SS:[EBP+0x8]
PUSH ECX ; push pBuf
CALL msvcr120._free_dbg ; call _free_dbg           : _free_dbg(pbuf,[[EBP-0x1C]+0x14])
ADD ESP, 0x8 ; _cdecl调用约定平栈
MOV DWORD PTR SS:[EBP-0x4], -0x2
CALL msvcr120.5243AA5D                    ; 调用下面的 _unlock
JMP SHORT msvcr120.5243AA68
PUSH 0x4
CALL msvcr120._unlock                      ;call _unlock : _unlock(4)
ADD ESP, 0x4 ; _cdecl调用约定平栈
RETN
MOV ECX, DWORD PTR SS:[EBP-0x10]             ; 函数尾部
MOV DWORD PTR FS:[0], ECX
POP ECX
POP EDI
POP ESI
POP EBX
MOV ESP, EBP
POP EBP
RETN

因VS2013无法查看其实现代码,以下为个人猜测如有错误忘请不吝赐教:

void _cdecl operator delete (void *pBuf)
{
  _CrtMemBlockHeader * pHead;

  if (pBuf == NULL)
  {
    return;
  }

  _lock(4);

  pHead = ((_CrtMemBlockHeader *)pBuf) - 0x20;

  if ((pHead->nBlockUse & 0xFFFF) == 4 
  || (pHead->nBlockUse) == 1 || (pHead->nBlockUse & 0xFFFF) == 2
  || (pHead->nBlockUse) == 3 
  && (1 == _CrtDbgReport(0x2, __FILE__, __LINE__, NULL, 
  (pHead->nBlockUse & 0xFFFF) == 4 
  || (pHead->nBlockUse) == 1 || (pHead->nBlockUse & 0xFFFF) == 2 
  || (pHead->nBlockUse) == 3) )
  )
  {
    __asm 
    { 
      int 3
    }
  }

  _free_dbg( pBuf, pHead->nBlockUse );
  _munlock(4)
  return;
}

int _CrtDbgReport( int reportType, const char *filename, int linenumber, const char *moduleName, const char *format [, argument] ... );

VS2013下的new[]和delete[]分析