【问题标题】:How does memory leak checkers like Valgrind identify freeValgrind 之类的内存泄漏检查器如何免费识别
【发布时间】:2012-07-19 23:20:53
【问题描述】:

我想了解内存泄漏检查器如何识别是否为给定的 malloc 调用了 free。 malloc 可以通过 brk 系统调用轻松识别,因此如果我正在编写分析器并在系统调用中断的进程上执行单步操作,我可以很容易地理解 malloc 已经完成。 我怎样才能找到这个 malloc 是否调用了 free?

以下是 strace 的输出。这段代码有 free,我们如何通过检查这个 strace 来判断是否调用了 free -

read(0, "13608\n", 4096)                = 6
brk(0)                                  = 0x8cc6000
brk(0x8ce7000)                          = 0x8ce7000
write(1, "File name - /proc/13608/maps\n", 29) = 29
open("/proc/13608/maps", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x55559000
read(3, "00349000-00363000 r-xp 00000000 "..., 4096) = 1046
write(1, "ptr1-ffd1f49a\n", 14)         = 14
write(1, "ptr2-ffd1f4a8\n", 14)         = 14
write(1, "Buffer read - 00349000-00363000 "..., 102) = 102
write(1, "\n", 1)                       = 1
write(1, "ptr1-ffd1f49a\n", 14)         = 14
write(1, "ptr2-ffd1f4aa\n", 14)         = 14
write(1, "Buffer read - 00367000-004a6000 "..., 104) = 104
write(1, "\n", 1)                       = 1
write(1, "ptr1-ffd1f49a\n", 14)         = 14
write(1, "ptr2-ffd1f4bd\n", 14)         = 14
write(1, "Buffer read - 08048000-08049000 "..., 123) = 123
write(1, "\n", 1)                       = 1
write(1, "ptr1-ffd1f49a\n", 14)         = 14
write(1, "ptr2-ffd1f4a1\n", 14)         = 14
write(1, "Buffer read - ffad8000-ffaf1000 "..., 95) = 95
write(1, "\n", 1)                       = 1
write(1, "ptr1-ffd1f479\n", 14)         = 14
write(1, "ptr2-ffd1f479\n", 14)         = 14
write(1, "Buffer read - ffffe000-fffff000 "..., 55) = 55
write(1, "\n", 1)                       = 1
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0x55559000, 4096)                = 0
write(1, "Starting Address - 00349000\n", 28) = 28
write(1, "Ending Address - 00363000\n", 26) = 26
write(1, "Permissions - r-xp\n", 19)    = 19
write(1, "Offset - 00000000\n", 18)     = 18
write(1, "PathName - </lib/ld-2.5.so>\n", 28) = 28
write(1, "\n", 1)                       = 1
write(1, "\n", 1)                       = 1
write(1, "Starting Address - 00367000\n", 28) = 28
write(1, "Ending Address - 004a6000\n", 26) = 26
write(1, "Permissions - r-xp\n", 19)    = 19
write(1, "Offset - 00000000\n", 18)     = 18
write(1, "PathName - </lib/libc-2.5.so>\n", 30) = 30
write(1, "\n", 1)                       = 1
write(1, "\n", 1)                       = 1
write(1, "Starting Address - 08048000\n", 28) = 28
write(1, "Ending Address - 08049000\n", 26) = 26
write(1, "Permissions - r-xp\n", 19)    = 19
write(1, "Offset - 00000000\n", 18)     = 18
write(1, "PathName - </fs_user/samirba/myP"..., 49) = 49
write(1, "\n", 1)                       = 1
write(1, "\n", 1)                       = 1
write(1, "Starting Address - ffad8000\n", 28) = 28
write(1, "Ending Address - ffaf1000\n", 26) = 26
write(1, "Permissions - rw-p\n", 19)    = 19
write(1, "Offset - 7ffffffe6000\n", 22) = 22
write(1, "PathName - <[stack]>\n", 21)  = 21
write(1, "\n", 1)                       = 1
write(1, "\n", 1)                       = 1
write(1, "Starting Address - ffffe000\n", 28) = 28
write(1, "Ending Address - fffff000\n", 26) = 26
write(1, "Permissions - r-xp\n", 19)    = 19
write(1, "Offset - ffffe000\n", 18)     = 18
write(1, "PathName - <EMPTY>\n", 19)    = 19
write(1, "\n", 1)                       = 1
write(1, "\n", 1)                       = 1
exit_group(0)                           = ?

【问题讨论】:

    标签: debugging memory-management memory-leaks


    【解决方案1】:

    malloc 调用和系统调用之间没有一对一的关系。 通常,malloc 库会从操作系统获取大块 使用例如brk 系统调用或 mmap 系统调用。 然后这些大块将被切成小块以供​​食用 连续的 malloc 调用。免费通常不会引起系统调用 (例如 munmap)被调用。 因此,您无法真正在系统调用级别跟踪 malloc 和 free。

    Valgrind 可以跟踪内存泄漏,因为它拦截(并替换) malloc,免费,... Valgrind 替换函数正在维护已分配块的列表。

    真正的泄漏(即无法再访问的内存,即所有指向它的指针 已丢失/擦除)由 Valgrind 使用扫描所有活动的 记忆。

    【讨论】:

    • 当我们调用 valgrind 的 memcheck 工具时,它不需要在编译过程中通过 valgrind 标志检测程序,但它仍然可以计算出调用了多少 malloc 和 free。我想了解它如何计算出调用的免费次数。
    【解决方案2】:

    AFAIK,操作系统分配的内存块由起始地址标识。因此,查找使用相同参数调用的free(),之前由malloc() 返回。由于strace 记录更多低级mmapbrk 调用,请使用ltrace 记录高级库调用,同时注意返回值和参数。

    【讨论】:

    • 如果我正在跟踪一个进程,例如使用 strace,我不会看到 malloc,我只会在输出中看到 brk。下面是 strace 的输出,这段代码是免费的。查看调用 free 的输出,你怎么知道?请看我上面编辑的问题
    • ok... ltrace 工作正常,因为它显示为免费...但是如果我正在编写分析器并且它正在对进程执行 ptrace,那么我可以识别正在发生的系统调用...有什么方法可以使用系统调用找到免费的?
    猜你喜欢
    • 2022-08-14
    • 2013-01-26
    • 2016-08-08
    • 2015-02-28
    • 2011-02-14
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    相关资源
    最近更新 更多