英文原文: http://www.debuginfo.com/tips/userbpntdll.html

在调试程序的时候,有时编译器会跳出一个对话框,比如:

User breakpoint called from code at 0x77fa018c

或者是:
Unhandled exception at 0x77f767cd (ntdll.dll) in myapp.exe: User breakpoint.
    发生了什么事呢?我们并没有设置任何断点,所以为什么会说有一个用户设置的断点呢?当程序在调试器外运行正常的时候,我们会更加觉得这个问题奇怪。但是在调试的时候,它总是跳出这个错误消息,导致我们不能继续调试我们的运用程序了。
    为了找到答案,我们察看下Debug输出窗口,可以看到有另外一个消息:
HEAP[myapp.exe]: Heap block at 00360F78 modified at 00360F90 past requested size of 10

看起来是堆崩溃了,Call Stack 窗口也指向这个堆:

NTDLL! DbgBreakPoint@0 address 0x77fa018c
NTDLL! RtlpBreakPointHeap@4 + 38 bytes
NTDLL! RtlpCheckBusyBlockTail@4 + 106 bytes
NTDLL! RtlpValidateHeapEntry@12 + 146975 bytes
NTDLL! RtlDebugFreeHeap@12 + 191 bytes
NTDLL! RtlFreeHeapSlowly@12 + 70765 bytes
NTDLL! RtlFreeHeap@12 + 4078 bytes
MYAPP! free + 102 bytes
MYAPP! operator delete(void *) + 9 bytes
main(int 1, char * * 0x003610b0) line 21 + 15 bytes
MYAPP! mainCRTStartup + 180 bytes
KERNEL32! BaseProcessStart@4 + 130958 bytes

结果证明是:当我们在编译器下开始这个程序的时候,操作系统用了一个特殊的堆“Debug Win32 heap"来代替原来的堆。任何时候在栈里的一个操作(比如分配或释放内存), 调试堆管理器就会检查整个堆的完整性和内部的结构。一旦发现它崩溃了,就会告诉我们有一个断点,而这个就是通过编译器报出的。

    我们如何找出堆崩溃的原因呢?我们当然可以用一个专门的运行检查程序(比如BoundCheckerPurify或者Memory Validator),但是我更倾向于用PageHeap, 因为它是操作系统的一部分(从Windows2000 SP2 开始)而且也很容易使用。关于PageHeap更多的内容可以参考KB286470.
    我们可以在注册表的帮助下启动Full PageHeap:
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\yourapp.exe
    GlobalFlag = REG_DWORD 0x2000000
    PageHeapFlags = REG_DWORD 0x3
(yourapp.exe就是可执行程序的名称)
   如果你的电脑上安装了 “Debugging Tools for Windows”, 可以有另外一个办法--运行下面的命令:
gflags –p /enable yourapp.exe /full
   (gflags.exe在Debugging Tools的安装目录中找到)

    在启动Full PageHeap之后,我们应该调试器下运行应用程序,然后等待编码违规或者断点的出现。当编码违规或者断点出现之后,检查当前源代码行,调用栈通常会允许我们马上看到是哪个语句导致栈的崩溃。
    还应该注意的是,连接应用程序的时候,推荐使用release版本的CRT库(就是用 /ML,/MT,或者/MD连接选项(或者相当的IDE)来代替/MLD,/MTD或者是/MDd选项)。 这是因为debug版本的CRT库用它自己的栈检查它的基本结构的(顺便说一下,功能没有Full PageHeap那么强大),它会和PageHeap重复并且会隐藏一些错误。
    另外一个值得讨论的情况是我们什么时候需要调试被一个大型应用软件(通常是一个第三方应用程序)装载的DLL。既然用PageHeap来检查整个应用程序有可能是毫无意义的,我们可以只对那些被DLL分配的堆内存进行检查。

gflags –p /enable yourapp.exe /full /dlls yourdll.dll