[英]sbrk - Valgrind doesn't report the memory leak
I wrote this little version of malloc
(no free
):我写了这个小版本的
malloc
(没有free
):
#include <cstdio>
#include <cstddef>
#include <unistd.h>
#define word_size sizeof(intptr_t)
#define align(n) ((n + word_size - 1) & ~(word_size - 1))
void* my_malloc(size_t size) {
void* p = sbrk(0);
printf("before allocation: %p\n", p);
if (sbrk(align(size)) == (void*) -1) {
// failed to allocate memory
return NULL;
}
printf("after allocation: %p\n", sbrk(0));
return p;
}
int main() {
int* foo = (int*) my_malloc(1);
*foo = 100;
printf("after allocation outside: %p\n", sbrk(0));
}
Here is the output of the code:这是代码的output:
before allocation: 0x1796000
after allocation: 0x1796008
after allocation outside: 0x1796008
As you can see, the memory allocated by my_malloc
has not been freed.可以看到,my_malloc分配的
my_malloc
还没有被释放。 Yet when I run it through valgrind
with this:然而,当我通过
valgrind
运行它时:
valgrind --leak-check=yes ./main
I get this:我明白了:
==1592== Memcheck, a memory error detector
==1592== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1592== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1592== Command: ./main
==1592== HEAP SUMMARY:
==1592== in use at exit: 0 bytes in 0 blocks
==1592== total heap usage: 2 allocs, 2 frees, 73,728 bytes allocated
==1592==
==1592== All heap blocks were freed -- no leaks are possible
==1592==
==1592== For counts of detected and suppressed errors, rerun with: -v
==1592== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
As you can see, valgrind
didn't find any memory leaks!如您所见,
valgrind
没有发现任何memory 泄漏! Am I using valgrind
incorrectly, or is this a bug?我是否错误地使用了
valgrind
,或者这是一个错误?
The first answer is not very accurate.第一个答案不是很准确。
Short answer for the OP: Valgrind won't detect a leak in custom memory pools unless you tell it more about your allocator. OP 的简短回答:Valgrind 不会检测到自定义 memory 池中的泄漏,除非你告诉它更多关于你的分配器的信息。
Long answer.长答案。
When you run valgrind
there are two executables that will run.当您运行
valgrind
时,将运行两个可执行文件。 Firstly valgrind
itself.首先
valgrind
本身。 This is a small application that will read a few command line arguments, set a few environment variables then look at the guest application to determine its bitness and then execve
the appropriate tool, for instance memcheck-x86-freebsd
.这是一个小型应用程序,它将读取一些命令行 arguments,设置一些环境变量,然后查看来宾应用程序以确定其位数,然后执行适当的工具,例如
execve
memcheck-x86-freebsd
。
The tool does not link with anything .该工具不与任何东西链接。 Not libc, not even the libc startup code.
不是 libc,甚至不是 libc 启动代码。 The entry point is in assembler that creates a new stack and starts
valgrind_main
.入口点在汇编程序中,它创建一个新堆栈并启动
valgrind_main
。 Since the tool links with nothing, it has to implement for itself all of the C runtime functions that it needs or wants to use.由于该工具没有任何链接,它必须自己实现它需要或想要使用的所有 C 运行时函数。 This includes some functions that compilers may implicitly generate.
这包括编译器可能隐式生成的一些函数。 For instance, code that does struct assignment may result in the compiler generating a call to
memcpy()
.例如,执行结构赋值的代码可能会导致编译器生成对
memcpy()
的调用。 This is what the quoted text is referring to.这就是引用的文本所指的内容。 These functions are also provided by the tool rather than libc.
这些功能也是由工具而不是 libc 提供的。 This is not related to the redirection mechanism.
这与重定向机制无关。
So, redirection.所以,重定向。
valgrind
will have set LD_PRELOAD
(or a platform specific version such as LD_32_PRELOAD
). valgrind
将设置LD_PRELOAD
(或特定于平台的版本,例如LD_32_PRELOAD
)。 This will point to a 'core' component (such as vgpreload_core-x86-freebsd.so
and a tool component such as vgpreload_memcheck-x86-freebsd.so
. The tool does the job of the link loader, and will mmap
these files into memory. During this process it will read the Elf
information and note any "special" functions. These functions use an elaborate name mangling system, and the tool will recognize that, for instance, _vgr10010ZU_libcZdsoZa_malloc
is a replacement for malloc
in libc
. The addresses of these redirection functions are stored and will be used when the guest executes. This mechanism also means that different tools can redirect different functions. For instance, memcheck
needs to redirect the malloc
and new
families of functions whilst DRD
and Helgrind
need to redirect pthread_*
and sema_*
.这将指向一个“核心”组件(例如
vgpreload_core-x86-freebsd.so
和一个工具组件,例如vgpreload_memcheck-x86-freebsd.so
。该工具完成链接加载器的工作,并将这些文件映射到mmap
. 在此过程中,它将读取Elf
信息并记录任何“特殊”函数。这些函数使用复杂的名称修饰系统,并且该工具将识别出,例如, _vgr10010ZU_libcZdsoZa_malloc
是libc
中malloc
的替代品。这些函数的地址重定向函数被存储,并在客户机执行时使用。这种机制也意味着不同的工具可以重定向不同的函数。例如, memcheck
需要重定向malloc
和new
的函数族,而DRD
和Helgrind
需要重定向pthread_*
和sema_*
.
For the other end of the redirection, the tool will also see the target function(s) when it loads libc (and the executable binary itself, which covers the case of static linking).对于重定向的另一端,该工具在加载 libc(以及可执行二进制文件本身,包括 static 链接的情况)时也会看到目标函数。
The redirection does not fully replace the target function, it just acts as a shim allowing the tool to track what the function has requested.重定向并没有完全替换目标 function,它只是充当一个 shim,允许工具跟踪 function 请求的内容。
Now to get right back to sbrk
.现在回到
sbrk
。 Valgrind does know about this, but only as a syscall. Valgrind 确实知道这一点,但仅作为系统调用。 It will check that the
size
argument does not come from invalid storage.它将检查
size
参数是否来自无效存储。 memcheck
won't track the memory as it does with malloc
. memcheck
不会像 malloc 那样跟踪malloc
。 If you use massif
with --pages-as-heap=yes
then it will profile the sbrk
usage.如果您将
massif
与--pages-as-heap=yes
一起使用,那么它将分析sbrk
的使用情况。
If you want memcheck
to validate your custom allocation functions then you have to do one of two things.如果你想让
memcheck
验证你的自定义分配函数,那么你必须做两件事之一。
--soname-synonyms
argument--soname-synonyms
参数 UPDATE: The default [since Release 3.12.0 (20 October 2016)] has changed to look for replacement functions in the test exe, text updated.更新:默认值 [自 3.12.0 版(2016 年 10 月 20 日)] 已更改为在测试 exe 中查找替换功能,文本已更新。
Valgrind checks for memory leaks by linking in its own functions in place of malloc
, calloc
, realloc
, and free
. Valgrind 通过链接自己的函数来代替
malloc
、 calloc
、 realloc
和free
来检查 memory 泄漏。 You can see this when valgrind reports a memory leak:当 valgrind 报告 memory 泄漏时,您可以看到这一点:
==24877== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==24877== at 0x4C29EA3: malloc (vg_replace_malloc.c:309)
==24877== by 0x4EC3AA9: strdup (in /usr/lib64/libc-2.17.so)
==24877== by 0x40058E: main (x1.c:9)
You can see here that the libc version of strdup
is called but the valgrind replacement for malloc
is called instead of the libc malloc
.您可以在此处看到调用了
strdup
的 libc 版本,但调用了malloc
的 valgrind 替代品,而不是 libc malloc
。
You're allocating memory at a lower level using sbrk
.您正在使用
sbrk
在较低级别分配 memory 。 Valgrind doesn't intercept that function, so it won't detect a leak. Valgrind 不会拦截 function,因此它不会检测到泄漏。 In fact, according to the valgrind documentation , it lists
sbrk
as a dependency.事实上,根据valgrind 文档,它将
sbrk
列为依赖项。 From section 1.1.4:从第 1.1.4 节开始:
To find out which glibc symbols are used by Valgrind, reinstate the link flags
-nostdlib -Wl,-no-undefined
.要找出 Valgrind 使用了哪些 glibc 符号,请恢复链接标志
-nostdlib -Wl,-no-undefined
。 This causes linking to fail, but will tell you what you depend on.这会导致链接失败,但会告诉你你依赖什么。 I have mostly, but not entirely, got rid of the glibc dependencies;
我大部分但不是完全摆脱了 glibc 依赖项; what remains is, IMO, fairly harmless.
剩下的是,IMO,相当无害。 AFAIK the current dependencies are:
memset
,memcmp
,stat
,system
,sbrk
,setjmp
andlongjmp
.AFAIK 当前的依赖项是:
memset
、memcmp
、stat
、system
、sbrk
、setjmp
和longjmp
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.