转储的 watch-window 中 "RtlpAnalyzeHeapFailure" 的含义
Meaning of "RtlpAnalyzeHeapFailure" in the watch-window of a dump
我正在处理以下访问冲突:
Unhandled exception at 0x77DB2A10 (ntdll.dll) in <Process>.exe.dmp:
0xC0000005: Access violation reading location 0x184487B8. occurred
源代码如下所示:
Result CParameter::SetValue(..., ..., <internal_Class>* pBlock, ...)
{
...
<internal_Class>* pStore = nullptr;
if (!pBlock)
{
pStore = &m_Data; // m_Data is a global variable
}
else pStore = pBlock;
if (pStore->pbData)
{
pStore->Clear(); // here we have the crash
}
调用堆栈如下所示:
ntdll.dll!_RtlpCoalesceFreeBlocks@16() Unknown Non-user code. Symbols loaded.
ntdll.dll!@RtlpFreeHeap@16() Unknown Non-user code. Symbols loaded.
ntdll.dll!_RtlFreeHeap@12() Unknown Non-user code. Symbols loaded.
ole32.dll!CRetailMalloc_Free(IMalloc * pThis=0x777476bc, void * pv=0x1842de40) Line 687 C++ Non-user code. Symbols loaded.
ole32.dll!CoTaskMemFree(void * pv=0x1842de40) Line 475 C++ Non-user code. Symbols loaded.
=> <Process>.exe!CParameter::SetValue(..., <internal_Class> * pBlock=0x00000000, ...) Line 5528 C++ Symbols loaded.
在 watch-window 中,我看到 &m_Data 的以下值:
0x77e4f9ae {Inside ntdll.dll!_RtlpAnalyzeHeapFailure@12()} {pbData=0xd2b70f3d <Error reading characters of string.> ...}
更多信息:
pBlock
的值为NULL
- 调试器不知道
pStore
的值
问题:
- 调用堆栈中的函数"Clear()"在哪里?
- watch-window中的值"RtlpAnalyzeHeapFailure"呢?这是否意味着我的转储已损坏到无法从中获取任何有用信息的程度?
提前致谢
Where is the function "Clear()" in the call stack?
这看起来像是内联的。
The value of pStore is unknown by the debugger
不还是m_Data的吗?
看一下崩溃点附近的代码,可以看到最近在哪个寄存器,如果保存了,那么应该可以看到某个时候保存了。
错误是由于内存系统检测到内存被错误释放。这可能是 m_Data 持有浮动值,或已被删除。
我也制作过类似的功能
__declspec(noinline) void Type::Clear()
{
delete pbData;
pbData = nullptr;
}
__declspec(noinline) void SetValue(Type * pBlock)
{
Type * pStore = nullptr;
if (!pBlock)
{
pStore = &m_Data; // m_Data is a global variable
}
else pStore = pBlock;
if (pStore->pbData)
{
pStore->Clear(); // here we have the crash
}
}
它的反汇编(来自 windbg)是:-
0:000:x86> uf debugging2!SetValue
debugging2!Type::Clear [c:\source\example\debugging2\debugging2.cpp @ 17]:
17 01041020 56 push esi
17 01041021 8bf1 mov esi,ecx
18 01041023 6a00 push 0
18 01041025 ff36 push dword ptr [esi]
18 01041027 e85c000000 call debugging2!operator delete (01041088)
18 0104102c 83c408 add esp,8
19 0104102f c70600000000 mov dword ptr [esi],0
19 01041035 5e pop esi
20 01041036 c3 ret
debugging2!SetValue [c:\source\example\debugging2\debugging2.cpp @ 23]:
23 01041040 833df833040100 cmp dword ptr [debugging2!m_Data (010433f8)],0
31 01041047 740a je debugging2!SetValue+0x13 (01041053)
Branch
debugging2!SetValue+0x9 [c:\source\example\debugging2\debugging2.cpp @ 33]:
33 01041049 b9f8330401 mov ecx,offset debugging2!m_Data (010433f8)
33 0104104e e9cdffffff jmp debugging2!Type::Clear (01041020) Branch
debugging2!SetValue+0x13 [c:\source\example\debugging2\debugging2.cpp @ 35]:
35 01041053 c3 ret Branch
这表明(在我的例子中)对 Clear() 的调用已被跳转替换,通过优化将其隐藏在堆栈中。
这也表明在地址 01041049
ecx 加载了调用的值。
MSDN : x86 calling conventions
Ecx 不是保留值,因此我们无法找到它所持有的值(除了从您的评论中似乎是 &m_Data)。
但是我们可以查看堆栈中的函数...
在 ::Clear 函数中,ecx 被移动到 esi。所以 esi(保留的)现在具有相同的值。
查看下一个函数(运算符删除),
debugging2!operator delete
[f:\dd\vctools\crt\vcstartup\src\heap\delete_scalar_size.cpp @ 14]:
14 01041088 55 push ebp
14 01041089 8bec mov ebp,esp
15 0104108b ff7508 push dword ptr [ebp+8]
15 0104108e e890030000 call debugging2!operator delete (01041423)
15 01041093 59 pop ecx
16 01041094 5d pop ebp
16 01041095 c3 ret
我们看到esi没有改变,也没有保存。所以我们看看栈上的下一个函数....
0:000:x86> uf 01041423
Flow analysis was incomplete, some code may be missing
debugging2!operator delete
[f:\dd\vctools\crt\vcstartup\src\heap\delete_scalar.cpp @ 15]:
15 01041423 e982090000 jmp debugging2!free (01041daa) Branch
在每种情况下,我们都在寻找存储在堆栈某处的 esi,这样我们就可以找到它...
我正在处理以下访问冲突:
Unhandled exception at 0x77DB2A10 (ntdll.dll) in <Process>.exe.dmp:
0xC0000005: Access violation reading location 0x184487B8. occurred
源代码如下所示:
Result CParameter::SetValue(..., ..., <internal_Class>* pBlock, ...)
{
...
<internal_Class>* pStore = nullptr;
if (!pBlock)
{
pStore = &m_Data; // m_Data is a global variable
}
else pStore = pBlock;
if (pStore->pbData)
{
pStore->Clear(); // here we have the crash
}
调用堆栈如下所示:
ntdll.dll!_RtlpCoalesceFreeBlocks@16() Unknown Non-user code. Symbols loaded.
ntdll.dll!@RtlpFreeHeap@16() Unknown Non-user code. Symbols loaded.
ntdll.dll!_RtlFreeHeap@12() Unknown Non-user code. Symbols loaded.
ole32.dll!CRetailMalloc_Free(IMalloc * pThis=0x777476bc, void * pv=0x1842de40) Line 687 C++ Non-user code. Symbols loaded.
ole32.dll!CoTaskMemFree(void * pv=0x1842de40) Line 475 C++ Non-user code. Symbols loaded.
=> <Process>.exe!CParameter::SetValue(..., <internal_Class> * pBlock=0x00000000, ...) Line 5528 C++ Symbols loaded.
在 watch-window 中,我看到 &m_Data 的以下值:
0x77e4f9ae {Inside ntdll.dll!_RtlpAnalyzeHeapFailure@12()} {pbData=0xd2b70f3d <Error reading characters of string.> ...}
更多信息:
pBlock
的值为NULL
- 调试器不知道
pStore
的值
问题:
- 调用堆栈中的函数"Clear()"在哪里?
- watch-window中的值"RtlpAnalyzeHeapFailure"呢?这是否意味着我的转储已损坏到无法从中获取任何有用信息的程度?
提前致谢
Where is the function "Clear()" in the call stack?
这看起来像是内联的。
The value of pStore is unknown by the debugger
不还是m_Data的吗?
看一下崩溃点附近的代码,可以看到最近在哪个寄存器,如果保存了,那么应该可以看到某个时候保存了。
错误是由于内存系统检测到内存被错误释放。这可能是 m_Data 持有浮动值,或已被删除。
我也制作过类似的功能
__declspec(noinline) void Type::Clear()
{
delete pbData;
pbData = nullptr;
}
__declspec(noinline) void SetValue(Type * pBlock)
{
Type * pStore = nullptr;
if (!pBlock)
{
pStore = &m_Data; // m_Data is a global variable
}
else pStore = pBlock;
if (pStore->pbData)
{
pStore->Clear(); // here we have the crash
}
}
它的反汇编(来自 windbg)是:-
0:000:x86> uf debugging2!SetValue
debugging2!Type::Clear [c:\source\example\debugging2\debugging2.cpp @ 17]:
17 01041020 56 push esi
17 01041021 8bf1 mov esi,ecx
18 01041023 6a00 push 0
18 01041025 ff36 push dword ptr [esi]
18 01041027 e85c000000 call debugging2!operator delete (01041088)
18 0104102c 83c408 add esp,8
19 0104102f c70600000000 mov dword ptr [esi],0
19 01041035 5e pop esi
20 01041036 c3 ret
debugging2!SetValue [c:\source\example\debugging2\debugging2.cpp @ 23]:
23 01041040 833df833040100 cmp dword ptr [debugging2!m_Data (010433f8)],0
31 01041047 740a je debugging2!SetValue+0x13 (01041053)
Branch
debugging2!SetValue+0x9 [c:\source\example\debugging2\debugging2.cpp @ 33]:
33 01041049 b9f8330401 mov ecx,offset debugging2!m_Data (010433f8)
33 0104104e e9cdffffff jmp debugging2!Type::Clear (01041020) Branch
debugging2!SetValue+0x13 [c:\source\example\debugging2\debugging2.cpp @ 35]:
35 01041053 c3 ret Branch
这表明(在我的例子中)对 Clear() 的调用已被跳转替换,通过优化将其隐藏在堆栈中。
这也表明在地址 01041049
ecx 加载了调用的值。
MSDN : x86 calling conventions
Ecx 不是保留值,因此我们无法找到它所持有的值(除了从您的评论中似乎是 &m_Data)。
但是我们可以查看堆栈中的函数...
在 ::Clear 函数中,ecx 被移动到 esi。所以 esi(保留的)现在具有相同的值。
查看下一个函数(运算符删除),
debugging2!operator delete
[f:\dd\vctools\crt\vcstartup\src\heap\delete_scalar_size.cpp @ 14]:
14 01041088 55 push ebp
14 01041089 8bec mov ebp,esp
15 0104108b ff7508 push dword ptr [ebp+8]
15 0104108e e890030000 call debugging2!operator delete (01041423)
15 01041093 59 pop ecx
16 01041094 5d pop ebp
16 01041095 c3 ret
我们看到esi没有改变,也没有保存。所以我们看看栈上的下一个函数....
0:000:x86> uf 01041423
Flow analysis was incomplete, some code may be missing
debugging2!operator delete
[f:\dd\vctools\crt\vcstartup\src\heap\delete_scalar.cpp @ 15]:
15 01041423 e982090000 jmp debugging2!free (01041daa) Branch
在每种情况下,我们都在寻找存储在堆栈某处的 esi,这样我们就可以找到它...