gpt4 book ai didi

memory - 为什么 !address 和 !heap 的输出不匹配?

转载 作者:行者123 更新时间:2023-12-04 11:03:16 25 4
gpt4 key购买 nike

我正在 Windbg 中调试以下 C 程序:

int main()
{
size_t size = 500*1024*1024;
void *p = malloc(size);
memset(p, 'a', size);
printf("%p", p);
}

我使用以下方法编译了程序:
cl/子泄漏.c
并且生成了一个leak.exe。

我在 printf 行设置了一个断点。我运行以下命令:
0:000> !address -summary

--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 21 5f0f6000 ( 1.485 Gb) 74.27%
Heap 3 1f501000 ( 501.004 Mb) 95.07% 24.46%
<unknown> 39 1436000 ( 20.211 Mb) 3.84% 0.99%
Image 35 300000 ( 3.000 Mb) 0.57% 0.15%
MappedFile 4 182000 ( 1.508 Mb) 0.29% 0.07%
Stack 3 100000 ( 1.000 Mb) 0.19% 0.05%
Other 6 3f000 ( 252.000 kb) 0.05% 0.01%
TEB 1 1000 ( 4.000 kb) 0.00% 0.00%
PEB 1 1000 ( 4.000 kb) 0.00% 0.00%

--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 21 207f0000 ( 519.938 Mb) 98.66% 25.39%
MEM_IMAGE 64 54c000 ( 5.297 Mb) 1.01% 0.26%
MEM_MAPPED 7 1be000 ( 1.742 Mb) 0.33% 0.09%

--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_FREE 21 5f0f6000 ( 1.485 Gb) 74.27%
MEM_COMMIT 73 1f9c9000 ( 505.785 Mb) 95.98% 24.70%
MEM_RESERVE 19 1531000 ( 21.191 Mb) 4.02% 1.03%

--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 27 1f45f000 ( 500.371 Mb) 94.95% 24.43%
PAGE_EXECUTE_READ 9 376000 ( 3.461 Mb) 0.66% 0.17%
PAGE_READONLY 26 1e4000 ( 1.891 Mb) 0.36% 0.09%
PAGE_WRITECOPY 9 c000 ( 48.000 kb) 0.01% 0.00%
PAGE_READWRITE|PAGE_GUARD 2 4000 ( 16.000 kb) 0.00% 0.00%

--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
Free 1fb51000 5590f000 ( 1.337 Gb)
Heap 750000 1f401000 ( 500.004 Mb)
<unknown> 7f0e0000 f00000 ( 15.000 Mb)
Image 77bc0000 d6000 ( 856.000 kb)
MappedFile 7efe5000 fb000 (1004.000 kb)
Stack 210000 fd000 (1012.000 kb)
Other 7efa0000 33000 ( 204.000 kb)
TEB 7efdd000 1000 ( 4.000 kb)
PEB 7efde000 1000 ( 4.000 kb)

我可以看到堆大约是 500MB,这和预期的一样。

但是 !heap 命令看不到此信息:

只有 1 个堆。
0:000> !heap
Index Address Name Debugging options enabled
1: 00650000 tail checking free checking validate parameters

0:000> !heap -a 00650000
Index Address Name Debugging options enabled
1: 00650000
Segment at 00650000 to 00750000 (0000f000 bytes committed) // Why so few memory committed.
Flags: 40000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 00000517
Max. Allocation Size: 7ffdefff
Lock Variable at: 00650138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 006500a0
Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at 00750000
Uncommitted ranges: 00650090
0065f000: 000f1000 (987136 bytes)
FreeList[ 00 ] at 006500c4: 0065b340 . 0065b340
0065b338: 00458 . 028b8 [104] - free

Segment00 at 00650000:
Flags: 00000000
Base: 00650000
First Entry: 00650588
Last Entry: 00750000
Total Pages: 00000100
Total UnCommit: 000000f1
Largest UnCommit:00000000
UnCommitted Ranges: (1)

0:000> dt p
Local var @ 0x30ff04 Type void*
0x00750020
Void
0:000> !heap -p -a 0x00750020
address 00750020 found in
_HEAP @ 650000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
00750018 3e80200 0000 [00] 00750020 1f400000 - (busy VirtualAlloc)
0:000> !heap -s
NtGlobalFlag enables following debugging aids for new heaps:
tail checking
free checking
validate parameters
LFH Key : 0x343f9ad2
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
Virtual block: 00fa0000 - 00fa0000 (size 00000000)
006d0000 40000062 1024 36 1024 1 1 1 1 0
-----------------------------------------------------------------------------

为什么我在 !heap -s 中看不到上面的信息?如何转储堆中的所有条目?

最佳答案

首先需要解释一下...

堆与虚拟内存

恕我直言,堆的发明是因为 VirtualAlloc() 的粒度(即 64kB)对于少量数据来说太浪费了。如果我查看 !heap <address> 的输出, 我可以看到

Heap entries for Segment00 in Heap 00100000
address: psize . size flags state (requested size)
00100000: 00000 . 00588 [101] - busy (587)

size有 5 位数字的列。这可能意味着堆条目的最大有用大小是
0:001> ? fffff
Evaluate expression: 1048575 = 000fffff

大约 1 MB。超过这个大小,堆的粒度可能没有意义,你可以使用 VirtualAlloc()直接地。或者,不是你,而是 malloc()功能为您决定。

输出中的错误消息

在您的输出中,您是否注意到这两行
Virtual Alloc List:   006500a0
Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at 00750000

这表明堆中有部分由 VirtualAlloc() 实际处理。 .但是,WinDbg 无法找到它的数据类型:
0:001> dt nt!_HEAP_VIRTUAL_ALLOC_ENTRY
Symbol nt!_HEAP_VIRTUAL_ALLOC_ENTRY not found.
!heap -s 的输出丢失了,所以我在我的机器上创建了它(WinDbg 6.3.9600.16384):
0:001> !heap 00100000 -s
LFH Key : 0x62502d13
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
Virtual block: 005b0000 - 005b0000 (size 00000000)
Virtual block: 006b0000 - 006b0000 (size 00000000)
...

Virtual block: 1fab0000 - 1fab0000 (size 00000000)
00100000 00000002 1024 204 1024 4 7 1 500 0 LFH
-----------------------------------------------------------------------------

在我的演示中,我创建了大约 500 个 1 MB 的 block 。请注意,00000000 的大小似乎已损坏。但是,如果我使用 !address在一个 block 上,它得到正确的区域大小(00100000):
0:001> !address 005b0000                                     
...
Usage: Heap
Base Address: 005b0000
End Address: 006b0000
Region Size: 00100000
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 005b0000
Allocation Protect: 00000004 PAGE_READWRITE

丢失的 _HEAP_VIRTUAL_ALLOC_ENTRY 会是什么样子?
0:001> dd 770000 L10
00770000 00870000 00670000 00000000 00000000
00770010 00100000 00100000 c8d50110 04000000
00770020 003df5a8 00870020 00000000 00000000
00770030 000ffc00 00000001 000000c1 fdfdfdfd

偏移量 0 处的值 870000 似乎是到下一个内存块的 FLink,偏移量 4 处的值 670000 似乎是到前一个内存块的 BLink。

偏移量 10 和 14 都将与区域大小匹配。
0:001> ? 0n1023*0n1024
Evaluate expression: 1047552 = 000ffc00

偏移量 +30 是大小(我在这里分配了 1023 kB 的 block )。
FDFDFDFD是一个众所周知的调试魔数(Magic Number),指示无人区,因此这很可能是结构的结束。

从 XP 转储中提取结构

我有一个可从 Windows XP 获得的转储。看看 nt!_HEAP_VIRTUAL_ALLOC_ENTRY 如何在那里解决:
0: kd> dt -r1 nt!_HEAP_VIRTUAL_ALLOC_ENTRY
+0x000 Entry : _LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
+0x008 ExtraStuff : _HEAP_ENTRY_EXTRA
+0x000 AllocatorBackTraceIndex : Uint2B
+0x002 TagIndex : Uint2B
+0x004 Settable : Uint4B
+0x000 ZeroInit : Uint8B
+0x010 CommitSize : Uint4B
+0x014 ReserveSize : Uint4B
+0x018 BusyBlock : _HEAP_ENTRY
+0x000 Size : Uint2B
+0x002 PreviousSize : Uint2B
+0x000 SubSegmentCode : Ptr32 Void
+0x004 SmallTagIndex : UChar
+0x005 Flags : UChar
+0x006 UnusedBytes : UChar
+0x007 SegmentIndex : UChar

结论
!heap malloc() 创建的大块似乎有问题实际使用 VirtualAlloc()在这种情况下。 WinDbg 找不到将内存内容映射到的数据类型。微软可能应该修复这个错误。
!address -summary 堆的输出统计信息似乎是合理的。

关于memory - 为什么 !address 和 !heap 的输出不匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30670253/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com