给定一个指针,找到它所在的堆块
Given a pointer, find the heap block where it resides
一个例子:
char *p1 = HeapAlloc(GetProcessHeap(), 0, 12); // returns 0x1234
char *p2 = p1 + 7;
// ...
void *p;
size_t size;
if(GetHeapBlock(p2, &p, &size))
printf("%p (%zd)", p, size); // should print "0x1234 (12)"
如何实现上面的GetHeapBlock
功能?
我查看了 Proc Heap Viewer, HeapMemView 程序,但它们显示的信息与我期望的不完全一样。例如指针有时较低,尺寸较大,因此对于上面的示例,它们可以显示尺寸为 256 的 0x1200。此外,两者显示不同的信息。
一般来说,我可以调用 GetProcessHeaps
,并且对于每个指针的每个堆调用 HeapValidate
,从输入越来越低开始。然后我可以调用 HeapSize
。但这听起来效率极低。有更好的解决方案吗?
P.S。我需要这个用于诊断,而不是用于生产,所以不是 100% reliable/performant 的解决方案是可以接受的。
如何使用 HeapWalk
,并像这样遍历您的进程堆:
HANDLE hHeap = GetProcessHeap();
char *p1 = (char*)HeapAlloc(hHeap, 0, 12);
cout << "P1: " << static_cast<void*>(p1) << endl;
char *p2 = p1 + 7;
PROCESS_HEAP_ENTRY entry;
entry.lpData = NULL;
BYTE regionIndex = 0xFF;
bool found = false;
while (!found && HeapWalk(hHeap, &entry) != FALSE)
{
if ((entry.wFlags & PROCESS_HEAP_REGION) != 0)
{
if (p2 < entry.Region.lpLastBlock && p2 >= entry.Region.lpFirstBlock)
{
cout << "Heap Region" << endl;
cout << "First Block: " << entry.Region.lpFirstBlock << endl;
cout << "Overhead: " << entry.cbOverhead << endl;
cout << "Size: " << entry.cbData << endl;
cout << "Data: " << entry.lpData << endl;
regionIndex = entry.iRegionIndex;
}
else
{
// should work to skip to the last block in the region. YMMV. Didn't test this scenario.
entry.lpData = entry.Region.lpLastBlock;
}
}
else if ((entry.wFlags & (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_MOVEABLE)) != 0)
{
if (entry.iRegionIndex == regionIndex)
{
if (p2 >= entry.lpData && p2 < ((char*)entry.lpData + entry.cbData))
{
cout << "Heap Block" << endl;
cout << "Heap Data: " << entry.lpData << endl;
cout << "Block hMem: " << entry.Block.hMem << endl;
cout << "Block Size: " << (int)entry.cbData << endl;
cout << "Overhead: " << (int)entry.cbOverhead << endl;
found = true;
}
}
}
}
从技术上讲,这个示例是 C++,但即使对于纯 C,想法也保持不变。(我只是懒惰,我已经有一个 C++ 临时程序,而且 std::cout
很方便。)基本上你初始化一个 PROCESS_HEAP_ENTRY
结构,其 lpData
设置为 NULL,以在堆的开头开始遍历。有关详细信息,请参阅 MSDN HeapWalk()
文章。
当我在我的系统上 运行 时,我得到:
P1: 00379FC0
Heap Region
First Block: 00360598
Overhead:
Size: 1416
Data: 00360000
Heap Block
Heap Data: 00379FC0
Block hMem: 0001A000
Block Size: 12
Overhead: 28
编辑添加:您也可以使用此方法转储整个进程堆。
一个例子:
char *p1 = HeapAlloc(GetProcessHeap(), 0, 12); // returns 0x1234
char *p2 = p1 + 7;
// ...
void *p;
size_t size;
if(GetHeapBlock(p2, &p, &size))
printf("%p (%zd)", p, size); // should print "0x1234 (12)"
如何实现上面的GetHeapBlock
功能?
我查看了 Proc Heap Viewer, HeapMemView 程序,但它们显示的信息与我期望的不完全一样。例如指针有时较低,尺寸较大,因此对于上面的示例,它们可以显示尺寸为 256 的 0x1200。此外,两者显示不同的信息。
一般来说,我可以调用 GetProcessHeaps
,并且对于每个指针的每个堆调用 HeapValidate
,从输入越来越低开始。然后我可以调用 HeapSize
。但这听起来效率极低。有更好的解决方案吗?
P.S。我需要这个用于诊断,而不是用于生产,所以不是 100% reliable/performant 的解决方案是可以接受的。
如何使用 HeapWalk
,并像这样遍历您的进程堆:
HANDLE hHeap = GetProcessHeap();
char *p1 = (char*)HeapAlloc(hHeap, 0, 12);
cout << "P1: " << static_cast<void*>(p1) << endl;
char *p2 = p1 + 7;
PROCESS_HEAP_ENTRY entry;
entry.lpData = NULL;
BYTE regionIndex = 0xFF;
bool found = false;
while (!found && HeapWalk(hHeap, &entry) != FALSE)
{
if ((entry.wFlags & PROCESS_HEAP_REGION) != 0)
{
if (p2 < entry.Region.lpLastBlock && p2 >= entry.Region.lpFirstBlock)
{
cout << "Heap Region" << endl;
cout << "First Block: " << entry.Region.lpFirstBlock << endl;
cout << "Overhead: " << entry.cbOverhead << endl;
cout << "Size: " << entry.cbData << endl;
cout << "Data: " << entry.lpData << endl;
regionIndex = entry.iRegionIndex;
}
else
{
// should work to skip to the last block in the region. YMMV. Didn't test this scenario.
entry.lpData = entry.Region.lpLastBlock;
}
}
else if ((entry.wFlags & (PROCESS_HEAP_ENTRY_BUSY | PROCESS_HEAP_ENTRY_MOVEABLE)) != 0)
{
if (entry.iRegionIndex == regionIndex)
{
if (p2 >= entry.lpData && p2 < ((char*)entry.lpData + entry.cbData))
{
cout << "Heap Block" << endl;
cout << "Heap Data: " << entry.lpData << endl;
cout << "Block hMem: " << entry.Block.hMem << endl;
cout << "Block Size: " << (int)entry.cbData << endl;
cout << "Overhead: " << (int)entry.cbOverhead << endl;
found = true;
}
}
}
}
从技术上讲,这个示例是 C++,但即使对于纯 C,想法也保持不变。(我只是懒惰,我已经有一个 C++ 临时程序,而且 std::cout
很方便。)基本上你初始化一个 PROCESS_HEAP_ENTRY
结构,其 lpData
设置为 NULL,以在堆的开头开始遍历。有关详细信息,请参阅 MSDN HeapWalk()
文章。
当我在我的系统上 运行 时,我得到:
P1: 00379FC0
Heap Region
First Block: 00360598
Overhead:
Size: 1416
Data: 00360000
Heap Block
Heap Data: 00379FC0
Block hMem: 0001A000
Block Size: 12
Overhead: 28
编辑添加:您也可以使用此方法转储整个进程堆。