简体   繁体   English

sbrk - Valgrind 不报告 memory 泄漏

[英]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_malloclibcmalloc的替代品。这些函数的地址重定向函数被存储,并在客户机执行时使用。这种机制也意味着不同的工具可以重定向不同的函数。例如, memcheck需要重定向mallocnew的函数族,而DRDHelgrind需要重定向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验证你的自定义分配函数,那么你必须做两件事之一。

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 通过链接自己的函数来代替malloccallocreallocfree来检查 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 and longjmp . AFAIK 当前的依赖项是: memsetmemcmpstatsystemsbrksetjmplongjmp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM