簡體   English   中英

sbrk - Valgrind 不報告 memory 泄漏

[英]sbrk - Valgrind doesn't report the memory leak

我寫了這個小版本的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));
}

這是代碼的output:

before allocation: 0x1796000
after allocation: 0x1796008
after allocation outside: 0x1796008

可以看到,my_malloc分配的my_malloc還沒有被釋放。 然而,當我通過valgrind運行它時:

valgrind --leak-check=yes ./main

我明白了:

==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)

如您所見, valgrind沒有發現任何memory 泄漏! 我是否錯誤地使用了valgrind ,或者這是一個錯誤?

第一個答案不是很准確。

OP 的簡短回答:Valgrind 不會檢測到自定義 memory 池中的泄漏,除非你告訴它更多關於你的分配器的信息。

長答案。

當您運行valgrind時,將運行兩個可執行文件。 首先valgrind本身。 這是一個小型應用程序,它將讀取一些命令行 arguments,設置一些環境變量,然后查看來賓應用程序以確定其位數,然后執行適當的工具,例如execve memcheck-x86-freebsd

該工具不與任何東西鏈接。 不是 libc,甚至不是 libc 啟動代碼。 入口點在匯編程序中,它創建一個新堆棧並啟動valgrind_main 由於該工具沒有任何鏈接,它必須自己實現它需要或想要使用的所有 C 運行時函數。 這包括編譯器可能隱式生成的一些函數。 例如,執行結構賦值的代碼可能會導致編譯器生成對memcpy()的調用。 這就是引用的文本所指的內容。 這些功能也是由工具而不是 libc 提供的。 這與重定向機制無關。

所以,重定向。 valgrind將設置LD_PRELOAD (或特定於平台的版本,例如LD_32_PRELOAD )。 這將指向一個“核心”組件(例如vgpreload_core-x86-freebsd.so和一個工具組件,例如vgpreload_memcheck-x86-freebsd.so 。該工具完成鏈接加載器的工作,並將這些文件映射到mmap . 在此過程中,它將讀取Elf信息並記錄任何“特殊”函數。這些函數使用復雜的名稱修飾系統,並且該工具將識別出,例如, _vgr10010ZU_libcZdsoZa_malloclibcmalloc的替代品。這些函數的地址重定向函數被存儲,並在客戶機執行時使用。這種機制也意味着不同的工具可以重定向不同的函數。例如, memcheck需要重定向mallocnew的函數族,而DRDHelgrind需要重定向pthread_*sema_* .

對於重定向的另一端,該工具在加載 libc(以及可執行二進制文件本身,包括 static 鏈接的情況)時也會看到目標函數。

重定向並沒有完全替換目標 function,它只是充當一個 shim,允許工具跟蹤 function 請求的內容。

現在回到sbrk Valgrind 確實知道這一點,但僅作為系統調用。 它將檢查size參數是否來自無效存儲。 memcheck不會像 malloc 那樣跟蹤malloc 如果您將massif--pages-as-heap=yes一起使用,那么它將分析sbrk的使用情況。

如果你想讓memcheck驗證你的自定義分配函數,那么你必須做兩件事之一。

更新:默認值 [自 3.12.0 版(2016 年 10 月 20 日)] 已更改為在測試 exe 中查找替換功能,文本已更新。

Valgrind 通過鏈接自己的函數來代替malloccallocreallocfree來檢查 memory 泄漏。 當 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)

您可以在此處看到調用了strdup的 libc 版本,但調用了malloc的 valgrind 替代品,而不是 libc malloc

您正在使用sbrk在較低級別分配 memory 。 Valgrind 不會攔截 function,因此它不會檢測到泄漏。 事實上,根據valgrind 文檔,它將sbrk列為依賴項。 從第 1.1.4 節開始:

要找出 Valgrind 使用了哪些 glibc 符號,請恢復鏈接標志-nostdlib -Wl,-no-undefined 這會導致鏈接失敗,但會告訴你你依賴什么。 我大部分但不是完全擺脫了 glibc 依賴項; 剩下的是,IMO,相當無害。 AFAIK 當前的依賴項是: memsetmemcmpstatsystemsbrksetjmplongjmp

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM