我们有一个测试用例,它使我们基于 MFC 的大型应用程序因堆损坏错误而崩溃。
我使用 App Verifier 为有问题的 DLL 打开了页面堆(不幸的是,由于其他原因,为整个进程打开堆是不可行的。)验证器没有给我们提供比我们已经拥有的更多的信息。它与原始崩溃在同一点触发。
现在我有两个相互竞争的理论。您认为哪种理论更有可能是正确的,您的下一步是什么?
- 这确实是堆损坏。验证程序没有捕捉到原始损坏,因为它发生在另一个 DLL 中。我们应该尝试为更多 DLL 激活验证程序,并确定哪些代码正在破坏堆。
- 堆很好;问题是我们将堆栈地址视为堆地址。我们应该进一步研究此调用堆栈中的代码以找出问题所在。
我倾向于#2,因为 free() 的参数看起来像一个堆栈地址,但到目前为止,没有人提出解释如何实现这一点。
这是调用堆栈的片段。MyString 是 CString 的简单包装器。MyAppDll 是设置为使用页堆的 DLL。
msvcr90.dll!free(void * pBlock=0x000000000012d6e8) 第 110 行 mfc90u.dll!ATL::CStringT > >::~CStringT > >() 第 1011 行 + 0x1e 字节 MyStringDll.dll!MyString::~MyString() 第 59 行 MyAppDll.dll!doStuffWithLotsOfStringInlining(MyClass* input=0x000000000012d6d0) 第 863 行 + 0x26 字节
以下是 free() 堆栈帧内的寄存器:
RAX = 0000000000000000 RBX = 000000000012D6E8 RCX = 0000000000000000 RDX = 0000000000000000 RSI = 000000000012D6D0 RDI = 00000000253C1090 R8 = 0000000000000000 R9 = 0000000000000000 R10 = 0000000000000000 R11 = 0000000000000000 R12 = 000000000012D7D0 R13 = 000007FFFFC04CE0 R14 = 0000000025196600 R15 = 0000000000000000 RIP = 00000000725BC7BC RSP = 000000000012D570 RBP = 000007FFF3670900 EFL = 00000000
这是应用验证程序消息:
验证器停止 0000000000000010:pid 0x1778:堆块的开始标记损坏。 00000000083B1000 :调用中使用的堆句柄。 000000006DD394E8 :操作中涉及的堆块。 54D32858A8747589 :堆块的大小。 000000005E33BA8D:损坏的戳值。