[英]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_malloc
是libc
中malloc
的替代品。這些函數的地址重定向函數被存儲,並在客戶機執行時使用。這種機制也意味着不同的工具可以重定向不同的函數。例如, memcheck
需要重定向malloc
和new
的函數族,而DRD
和Helgrind
需要重定向pthread_*
和sema_*
.
對於重定向的另一端,該工具在加載 libc(以及可執行二進制文件本身,包括 static 鏈接的情況)時也會看到目標函數。
重定向並沒有完全替換目標 function,它只是充當一個 shim,允許工具跟蹤 function 請求的內容。
現在回到sbrk
。 Valgrind 確實知道這一點,但僅作為系統調用。 它將檢查size
參數是否來自無效存儲。 memcheck
不會像 malloc 那樣跟蹤malloc
。 如果您將massif
與--pages-as-heap=yes
一起使用,那么它將分析sbrk
的使用情況。
如果你想讓memcheck
驗證你的自定義分配函數,那么你必須做兩件事之一。
--soname-synonyms
參數更新:默認值 [自 3.12.0 版(2016 年 10 月 20 日)] 已更改為在測試 exe 中查找替換功能,文本已更新。
Valgrind 通過鏈接自己的函數來代替malloc
、 calloc
、 realloc
和free
來檢查 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 當前的依賴項是:memset
、memcmp
、stat
、system
、sbrk
、setjmp
和longjmp
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.