Visual Studio C++ 和 Windows 中的调试内存填充模式是什么?

What are the debug memory fill patterns in Visual Studio C++ and Windows?

提问人:HidekiAI 提问时间:9/24/2008 最后编辑:Glenn SlaydenHidekiAI 更新时间:10/3/2023 访问量:122719

问:

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

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

有时,我们会遇到内存泄漏、缓冲区溢出等情况,这些信息会派上用场。

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

调试 Visual-C++

评论

0赞 phuclv 2/23/2016
操作系统何时以及为什么会在 malloc/free/new/delete 上将内存初始化为 0xCD、0xDD 等?
0赞 HidekiAI 2/24/2016
@Lưu Vĩnh Phúc :这不是操作系统,而是调试器。“D”(如 0xCD 和 0xDD)表示调试(即 malloc_dbg 是通过 malloc 调用的,如 msdn.microsoft.com/en-us/library/aa270812(v=vs.60).aspx 中所述)。我相信它还在堆周围添加了围栏/柱子,用于跟踪缓冲区溢出。当您遇到双重删除或多次释放(甚至可能调用 delete 而不是 delete[])和悬空指针时,当您检查数据时,它是“0xDD”(或当未初始化的堆显示0xCD时),捕获问题非常有用
0赞 phuclv 2/24/2016
我没有说这是操作系统。是另一个提问者写错了标题
0赞 phuclv 5/7/2018
操作系统何时以及为何在malloc/free/new/delete上初始化内存以0xCD、0xDD等的可能重复?

答:

357赞 Mark Ingram 9/24/2008 #1

此链接包含更多信息:

https://en.wikipedia.org/wiki/Magic_number_(编程)#Debug_values

* 0xABABABAB : Used by Microsoft's HeapAlloc() to mark "no man's land" guard bytes after allocated heap memory
* 0xABADCAFE : A startup to this value to initialize all free memory to catch errant pointers
* 0xBAADF00D : Used by Microsoft's LocalAlloc(LMEM_FIXED) to mark uninitialised allocated heap memory
* 0xBADCAB1E : Error Code returned to the Microsoft eVC debugger when connection is severed to the debugger
* 0xBEEFCACE : Used by Microsoft .NET as a magic number in resource files
* 0xCCCCCCCC : Used by Microsoft's C++ debugging runtime library to mark uninitialised stack memory
* 0xCDCDCDCD : Used by Microsoft's C++ debugging runtime library to mark uninitialised heap memory
* 0xDDDDDDDD : Used by Microsoft's C++ debugging heap to mark freed heap memory
* 0xDEADDEAD : A Microsoft Windows STOP Error code used when the user manually initiates the crash.
* 0xFDFDFDFD : Used by Microsoft's C++ debugging heap to mark "no man's land" guard bytes before and after allocated heap memory
* 0xFEEEFEEE : Used by Microsoft's HeapFree() to mark freed heap memory

评论

25赞 Anderson Green 2/16/2013
在这里,我看到(糟糕的食物)、(牛肉蛋糕)、(糟糕的电缆)、(糟糕的咖啡馆)和(死去的死者)。这是故意的吗?BAADF00DBEEFCACEBAADCAB1EBADCAFEDEADDEAD
47赞 5/9/2013
@AndersonGreen当然,这是故意的。它被称为 hexspeak
34赞 Per Lundberg 9/4/2013
过去,当我们做一些低级(操作系统内核)编程时,我们曾经使用C0CAC01A...... ;)
5赞 J. Paulding 4/9/2015
0xDEADBEEF,即使它们不属于MS的白话,也是经典0xC0EDBABE
4赞 BlueRaja - Danny Pflughoeft 6/7/2015
作为保罗·麦卡特尼的粉丝,我喜欢BEA71E5
115赞 John Dibling 12/10/2008 #2

实际上,调试分配中添加了相当多的有用信息。此表更完整:

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

Address  Offset After HeapAlloc() After malloc() During free() After HeapFree() Comments
0x00320FD8  -40    0x01090009    0x01090009     0x01090009    0x0109005A     Win32 heap info
0x00320FDC  -36    0x01090009    0x00180700     0x01090009    0x00180400     Win32 heap info
0x00320FE0  -32    0xBAADF00D    0x00320798     0xDDDDDDDD    0x00320448     Ptr to next CRT heap block (allocated earlier in time)
0x00320FE4  -28    0xBAADF00D    0x00000000     0xDDDDDDDD    0x00320448     Ptr to prev CRT heap block (allocated later in time)
0x00320FE8  -24    0xBAADF00D    0x00000000     0xDDDDDDDD    0xFEEEFEEE     Filename of malloc() call
0x00320FEC  -20    0xBAADF00D    0x00000000     0xDDDDDDDD    0xFEEEFEEE     Line number of malloc() call
0x00320FF0  -16    0xBAADF00D    0x00000008     0xDDDDDDDD    0xFEEEFEEE     Number of bytes to malloc()
0x00320FF4  -12    0xBAADF00D    0x00000001     0xDDDDDDDD    0xFEEEFEEE     Type (0=Freed, 1=Normal, 2=CRT use, etc)
0x00320FF8  -8     0xBAADF00D    0x00000031     0xDDDDDDDD    0xFEEEFEEE     Request #, increases from 0
0x00320FFC  -4     0xBAADF00D    0xFDFDFDFD     0xDDDDDDDD    0xFEEEFEEE     No mans land
0x00321000  +0     0xBAADF00D    0xCDCDCDCD     0xDDDDDDDD    0xFEEEFEEE     The 8 bytes you wanted
0x00321004  +4     0xBAADF00D    0xCDCDCDCD     0xDDDDDDDD    0xFEEEFEEE     The 8 bytes you wanted
0x00321008  +8     0xBAADF00D    0xFDFDFDFD     0xDDDDDDDD    0xFEEEFEEE     No mans land
0x0032100C  +12    0xBAADF00D    0xBAADF00D     0xDDDDDDDD    0xFEEEFEEE     Win32 heap allocations are rounded up to 16 bytes
0x00321010  +16    0xABABABAB    0xABABABAB     0xABABABAB    0xFEEEFEEE     Win32 heap bookkeeping
0x00321014  +20    0xABABABAB    0xABABABAB     0xABABABAB    0xFEEEFEEE     Win32 heap bookkeeping
0x00321018  +24    0x00000010    0x00000010     0x00000010    0xFEEEFEEE     Win32 heap bookkeeping
0x0032101C  +28    0x00000000    0x00000000     0x00000000    0xFEEEFEEE     Win32 heap bookkeeping
0x00321020  +32    0x00090051    0x00090051     0x00090051    0xFEEEFEEE     Win32 heap bookkeeping
0x00321024  +36    0xFEEE0400    0xFEEE0400     0xFEEE0400    0xFEEEFEEE     Win32 heap bookkeeping
0x00321028  +40    0x00320400    0x00320400     0x00320400    0xFEEEFEEE     Win32 heap bookkeeping
0x0032102C  +44    0x00320400    0x00320400     0x00320400    0xFEEEFEEE     Win32 heap bookkeeping
9赞 Glenn Slayden 1/15/2018 #3

特别是,这些是 1980 年代英特尔 8088/8086 处理器指令集的遗物。 是软件中断操作码INT的特例。特殊的单字节版本允许程序生成中断 30xCC0xCD0xCC0xCD0xCC

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

通常,x86 操作码需要两个字节:后跟 0-255 之间的所需中断数。因此,尽管您可以因此发布 ,但英特尔决定添加一个特殊版本(没有额外的字节),因为操作码必须只有一个字节才能用作未使用内存的可靠“填充字节”。INT0xCD0xCD 0x03INT 30xCC

这里的重点是,如果处理器错误地跳转到不包含任何预期指令的内存中,则允许正常恢复。多字节指令不适合此目的,因为错误的跳转可能会落在任何可能的字节偏移量处,而它必须继续使用正确格式的指令流。

显然,单字节操作码对此工作微不足道,但也可能有古怪的例外:例如,考虑到填充序列(本页也提到了),我们可以看到它是相当可靠的,因为无论指令指针落在何处(可能除了最后一个填充的字节),CPU 都可以继续执行有效的双字节 x86 指令, 在这种情况下,用于生成软件中断205(0xCD)。0xCDCDCDCDCD CD

更奇怪的是,虽然是 100% 可解释的——给出 either 或 ——序列不太可靠,如图所示只有 75%,但当作为 int 大小的内存填充物重复时,通常为 99.99%。CD CC CD CCINT 3INT 204CC CD CC CD

page from contemporaneous 8088/8086 instruction set manual showing INT instruction
宏汇编程序参考,1987 年

评论

0赞 HidekiAI 1/20/2018
哇,我没有意识到(将两者连接起来)0xCC是 INT3。这是有道理的(即不是巧合)。我曾经在有JMP的地方注入“NOP + INT3”来检查寄存器,然后才在少数情况下(很久以前)。感谢您的见解,谜团解开了!
0赞 Glenn Slayden 1/21/2018
这是干什么用的?使用(输入字节)命令输入单个字节还不够吗?NOP0xCCeb
0赞 HidekiAI 2/5/2018
只是一个习惯,那时候,有些代码会读取两个字节并尝试将其用作跳转表,或者在某些情况下,当我列出汇编代码时,通过添加 NOP,它在反汇编时不会显示为“???”或其他东西(更清晰);总而言之,由于多种原因,在 BRK 之前或之后注入 NOP 只是成为一种习惯;哦,在某些情况下,某些应用程序会尝试对地址块进行校验和,因此我会用 INT3 + [some-hex] grin 来平衡 JMP $XYZW