在Visual Studio C ++中,什么是内存分配表示形式?


216

在Visual Studio中,我们所有人都有“ baadf00d”,在运行时在C ++中的调试器中检查变量时看到“ CC”和“ CD”。

据我了解,“ CC”处于DEBUG模式,仅表示何时对内存进行new()或alloc()并统一化。而“ CD”代表已删除或已释放的内存。我只在RELEASE版本中看到过“ baadf00d”(但是我可能错了)。

有时,我们会遇到解决内存泄漏,缓冲区溢出等问题的情况,这些信息非常有用。

有人会善良地指出何时以及在哪种模式下将内存设置为可识别的字节模式以进行调试吗?



@LưuVĩnhPhúc:它不是操作系统,而是调试器。“ D”(如在0xCD和0xDD上)用于调试(即,如msdn.microsoft.com/en-us/library/aa270812(v=vs.60).aspx中所述,malloc_dbg是通过malloc调用的)。我相信它还会在堆周围添加围栏/柱子以跟踪缓冲区溢出。当您遇到两次删除或多次释放(甚至可能调用delete而不是delete []的错误)和悬空的指针(已处置)并且检查数据时,它是“ 0xDD”,这对于捕获问题非常有用。 (或未初始化的堆显示0xCD时)
HidekiAI 2016年

我没有说是操作系统。是其他
请求者

Answers:


316

该链接具有更多信息:

http://en.wikipedia.org/wiki/Magic_number_(编程)

* 0xABABABAB:由Microsoft的HeapAlloc()用于在分配堆内存后标记“无人区”保护字节
* 0xABADCAFE:对此值的启动以初始化所有可用内存以捕获错误的指针
* 0xBAADF00D:由Microsoft的LocalAlloc(LMEM_FIXED)用来标记未初始化的已分配堆内存
* 0xBADCAB1E:当断开与调试器的连接时,错误代码返回到Microsoft eVC调试器
* 0xBEEFCACE:由Microsoft .NET在资源文件中用作幻数
* 0xCCCCCCCC:由Microsoft的C ++调试运行时库用来标记未初始化的堆栈内存
* 0xCDCDCDCD:由Microsoft的C ++调试运行时库用来标记未初始化的堆内存
* 0xDDDDDDDD:由Microsoft的C ++调试堆用来标记释放的堆内存
* 0xDEADDEAD:当用户手动启动崩溃时使用的Microsoft Windows STOP错误代码。
* 0xFDFDFDFD:由Microsoft的C ++调试堆用来在分配的堆内存之前和之后标记“无人区”保护字节
* 0xFEEEFEEE:由Microsoft的HeapFree()用来标记释放的堆内存

19
在这里,我看到了BAADF00D(不良食物),BEEFCACE(牛肉蛋糕), BAADCAB1E(不良电缆),BADCAFE(不良咖啡馆)和DEADDEAD(死者)。这是故意的吗?
安德森·格林

38
@AndersonGreen当然是故意的。叫做hexspeak

28
过去,当我们做一些低级(操作系统内核)编程时,我们曾经使用C0CAC01A ...;)
Per Lundberg 2013年

2
0xDEADBEEF0xC0EDBABE即使它们不属于MS的语言,也都是经典之作
J. Paulding

3
作为Paul McCartney的球迷,我很喜欢BEA71E5
BlueRaja-Danny Pflughoeft 2015年

111

实际上,在调试分配中添加了很多有用的信息。该表比较完整:

http://www.nobugs.org/developer/win32/debug_crt_heap.html#table

在HeapAlloc()之后在malloc()之后在free()在HeapFree()之后的地址偏移
0x00320FD8 -40 0x01090009 0x01090009 0x01090009 0x0109005A Win32堆信息
0x00320FDC -36 0x01090009 0x00180700 0x01090009 0x00180400 Win32堆信息
0x00320FE0 -32 0xBAADF00D 0x00320798 0xDDDDDDDD 0x00320448指向下一个CRT堆块的Ptr(在时间上较早分配)
0x00320FE4 -28 0xBAADF00D 0x00000000 0xDDDDDDDD 0x00320448 Ptr到上一个CRT堆块(在以后分配)
0x00320FE8 -24 0xBAADF00D 0x00000000 0xDDDDDDDD 0xFEEEFEEE malloc()调用的文件名
0x00320FEC -20 0xBAADF00D 0x00000000 0xDDDDDDDD 0xFEEEFEEE malloc()调用的行号
0x00320FF0 -16 0xBAADF00D 0x00000008 0xDDDDDDDD 0xFEEEFEEE要分配给malloc()的字节数
0x00320FF4 -12 0xBAADF00D 0x00000001 0xDDDDDDDD 0xFEEEFEEE类型(0 =已释放,1 =正常,2 =使用CRT等)
0x00320FF8 -8 0xBAADF00D 0x00000031 0xDDDDDDDD 0xFEEEFEEE请求编号,从0开始增加
0x00320FFC -4 0xBAADF00D 0xFDFDFDFD 0xDDDDDDDD 0xFEEEFEEE无人登陆
0x00321000 +0 0xBAADF00D 0xCDCDCDCD 0xDDDDDDDD 0xFEEEFEEE您想要的8个字节
0x00321004 +4 0xBAADF00D 0xCDCDCDCD 0xDDDDDDDD 0xFEEEFEEE您想要的8个字节
0x00321008 +8 0xBAADF00D 0xFDFDFDFD 0xDDDDDDDD 0xFEEEFEEE无人登陆
0x0032100C +12 0xBAADF00D 0xBAADF00D 0xDDDDDDDD 0xFEEEFEEE Win32堆分配舍入为16个字节
0x00321010 +16 0xABABABAB 0xABABABAB 0xABABABAB 0xFEEEFEEE Win32堆簿记
0x00321014 +20 0xABABABAB 0xABABABAB 0xABABABAB 0xFEEEFEEE Win32堆簿记
0x00321018 +24 0x00000010 0x00000010 0x00000010 0xFEEEFEEE Win32堆簿记
0x0032101C +28 0x00000000 0x00000000 0x00000000 0xFEEEFEEE Win32堆簿记
0x00321020 +32 0x00090051 0x00090051 0x00090051 0xFEEEFEEE Win32堆簿记
0x00321024 +36 0xFEEE0400 0xFEEE0400 0xFEEE0400 0xFEEEFEEE Win32堆簿记
0x00321028 +40 0x00320400 0x00320400 0x00320400 0xFEEEFEEE Win32堆簿记
0x0032102C +44 0x00320400 0x00320400 0x00320400 0xFEEEFEEE Win32堆簿记

5

关于0xCC0xCD特别是,这些是从遗物英特尔8088 / 8086在1980处理器指令集回来。0xCC软件中断操作码 的特例。特殊的单字节版本允许程序生成中断3INT 0xCD0xCC

尽管从原则上讲,软件中断号是任意的,INT 3但传统上它是用于调试器的breakbreakpoint函数,这一约定一直存在至今。每当启动调试器时,它都会安装一个中断处理程序,INT 3以便在执行该操作码时将触发调试器。通常,它将暂停当前正在运行的程序并显示交互式提示。

通常,x86 INT操作码为两个字节:0xCD后跟0-255之间的所需中断号。现在,尽管您可以提出0xCD 0x03要求INT 3,但英特尔还是决定添加一个特殊版本- 0xCC不增加任何字节-因为操作码必须仅为一个字节,才能用作未使用内存的可靠“填充字节”。

这里的重点是,如果处理器错误地跳入不包含任何预期指令的内存,则可以进行正常恢复。多字节指令不适合此目的,因为错误的跳转可能落在任何可能的字节偏移处,在这种情况下,它必须继续以正确形成的指令流继续。

显然,一字节操作码对此很简单,但是也可能有一些古怪的例外:例如,考虑到填充序列0xCDCDCDCD(也在本页上提到),我们可以看到它是相当可靠的,因为无论指令指针位于何处(除了可能的最后一个填充字节之外),CPU可以继续执行有效的两个字节的 x86指令CD CD,在这种情况下,会产生软件中断205(0xCD)。

尽管如此,Weirder仍然CD CC CD CC是100%可以解释的-给出一个INT 3或一个INT 204序列CC CD CC CD的可靠性较低,如图所示仅为75%,但作为整数大小的存储填充物重复使用时通常为99.99%。

同期8088/8086指令集手册中的页面显示INT指令
宏汇编程序参考,1987年


哇,我没有意识到(连接两个)0xCC是INT3。这是有道理的(即不是巧合)。我曾经在有JMP检查寄存器的地方注入“ NOP + INT3”,然后才有几次出现跳跃(回溯到何时)。感谢您的见解,神秘感得到了解决!
HidekiAI

这是NOP为了什么?0xCC使用eb(输入字节)命令输入单个字节是否足够?
Glenn Slayden

只是一种习惯,那时,某些代码会读取两个字节并尝试将其用作跳转表,或者在某些情况下,当我通过添加NOP列出汇编代码时,它不会显示为“ ???”。或拆卸时的东西(更清晰);总而言之,出于多种原因,在BRK之前或之后注入NOP成为一种习惯。哦,在某些情况下,某些应用程序会尝试执行地址块的校验和,因此我会用INT3 + [some-hex] 笑容
HidekiAI
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.