在 valgrind 下 运行 时分配内存的地址不一样
Address of allocated memory not the same when running under valgrind
我正在测试 valgrind
并且有这个泄漏 4 个字节的小 C 程序:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* x = malloc(sizeof(int));
printf( "Address: %p\n", x);
return 0;
}
我编译它:gcc -g -o leak leak.c
,运行它:
$ leak
Address: 0x55a72e303260
$ leak
Address: 0x55f370273260
所以它为两个单独的 运行 显示了两个不同的地址。但是,如果我 运行 它在 valgrind 下它总是显示相同的地址:0x4a66040
:
$ valgrind --leak-check=full --show-leak-kinds=all leak
==8186== Memcheck, a memory error detector
==8186== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8186== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==8186== Command: leak
==8186==
Address: 0x4a66040
==8186==
==8186== HEAP SUMMARY:
==8186== in use at exit: 4 bytes in 1 blocks
==8186== total heap usage: 2 allocs, 1 frees, 1,028 bytes allocated
==8186==
==8186== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==8186== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8186== by 0x109156: main (leak.c:6)
==8186==
==8186== LEAK SUMMARY:
==8186== definitely lost: 4 bytes in 1 blocks
==8186== indirectly lost: 0 bytes in 0 blocks
==8186== possibly lost: 0 bytes in 0 blocks
==8186== still reachable: 0 bytes in 0 blocks
==8186== suppressed: 0 bytes in 0 blocks
==8186==
==8186== For counts of detected and suppressed errors, rerun with: -v
==8186== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
为什么会这样?并且valgrind
是否可以显示内存的真实地址?
它是分配内存的"real"地址。
Valgrind 将您的 malloc()
实现替换为它自己的版本,以便它可以做它做的事情,请参阅以下行:
==8186== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
因此,malloc()
的 "normal" libc 实现与 valgrind 的实现之间存在差异的是获取内存的底层调用。可能 libc 使用 brk()
而 valgrind 使用 mmap()
.
brk()
遵循 Address Space Layout Randomization 的规则,而 mmap()
允许显式选择要映射新分配内存的虚拟内存地址。
编辑:strace
两个版本,显示:
libc:
brk(NULL) = 0x5611e25ec000
brk(0x5611e260d000) = 0x5611e260d000
fstat(1, {st_dev=makedev(0, 22), st_ino=67, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=1000, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 64), st_atime=1566292432 /* 2019-08-20T11:13:52.993864629+0200 */, st_atime_nsec=993864629, st_mtime=1566292432 /* 2019-08-20T11:13:52.993864629+0200 */, st_mtime_nsec=993864629, st_ctime=1564479628 /* 2019-07-30T11:40:28.009864433+0200 */, st_ctime_nsec=9864433}) = 0
write(1, "Address: 0x5611e25ec260\n", 24) = 24
valgrind:
mmap(0x4c2c000, 2158912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x4c2c000
...
write(1027, "==18842== at 0x4C2FB0F: mallo"..., 91) = 91
所以实际上 Valgrind 明确选择了在哪里映射它的内存池。
我正在测试 valgrind
并且有这个泄漏 4 个字节的小 C 程序:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* x = malloc(sizeof(int));
printf( "Address: %p\n", x);
return 0;
}
我编译它:gcc -g -o leak leak.c
,运行它:
$ leak
Address: 0x55a72e303260
$ leak
Address: 0x55f370273260
所以它为两个单独的 运行 显示了两个不同的地址。但是,如果我 运行 它在 valgrind 下它总是显示相同的地址:0x4a66040
:
$ valgrind --leak-check=full --show-leak-kinds=all leak
==8186== Memcheck, a memory error detector
==8186== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8186== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==8186== Command: leak
==8186==
Address: 0x4a66040
==8186==
==8186== HEAP SUMMARY:
==8186== in use at exit: 4 bytes in 1 blocks
==8186== total heap usage: 2 allocs, 1 frees, 1,028 bytes allocated
==8186==
==8186== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==8186== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==8186== by 0x109156: main (leak.c:6)
==8186==
==8186== LEAK SUMMARY:
==8186== definitely lost: 4 bytes in 1 blocks
==8186== indirectly lost: 0 bytes in 0 blocks
==8186== possibly lost: 0 bytes in 0 blocks
==8186== still reachable: 0 bytes in 0 blocks
==8186== suppressed: 0 bytes in 0 blocks
==8186==
==8186== For counts of detected and suppressed errors, rerun with: -v
==8186== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
为什么会这样?并且valgrind
是否可以显示内存的真实地址?
它是分配内存的"real"地址。
Valgrind 将您的 malloc()
实现替换为它自己的版本,以便它可以做它做的事情,请参阅以下行:
==8186== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
因此,malloc()
的 "normal" libc 实现与 valgrind 的实现之间存在差异的是获取内存的底层调用。可能 libc 使用 brk()
而 valgrind 使用 mmap()
.
brk()
遵循 Address Space Layout Randomization 的规则,而 mmap()
允许显式选择要映射新分配内存的虚拟内存地址。
编辑:strace
两个版本,显示:
libc:
brk(NULL) = 0x5611e25ec000
brk(0x5611e260d000) = 0x5611e260d000
fstat(1, {st_dev=makedev(0, 22), st_ino=67, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=1000, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 64), st_atime=1566292432 /* 2019-08-20T11:13:52.993864629+0200 */, st_atime_nsec=993864629, st_mtime=1566292432 /* 2019-08-20T11:13:52.993864629+0200 */, st_mtime_nsec=993864629, st_ctime=1564479628 /* 2019-07-30T11:40:28.009864433+0200 */, st_ctime_nsec=9864433}) = 0
write(1, "Address: 0x5611e25ec260\n", 24) = 24
valgrind:
mmap(0x4c2c000, 2158912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x4c2c000
...
write(1027, "==18842== at 0x4C2FB0F: mallo"..., 91) = 91
所以实际上 Valgrind 明确选择了在哪里映射它的内存池。