【发布时间】:2021-10-01 10:52:38
【问题描述】:
我在calloc() 和free() 上编写了一个简单的wrapper.so 来监视内存调用,并且似乎pthreads_create() 正在泄漏内存。
在使用calloc(17, 16)(大部分时间为calloc(18, 16))进行初始分配后,似乎正在尝试释放内存,但nullptr 被传递给free()。
这里发生了什么?
// test.cpp
#include <pthread.h>
#include <cassert>
#include <cstdlib>
void* p_dummy(void*)
{
return nullptr;
}
int main(void)
{
void* ptr = calloc(11, 11);
free(ptr);
pthread_t thread;
assert(pthread_create(&thread, nullptr, p_dummy, nullptr) == 0);
assert(pthread_join(thread, nullptr) == 0);
return 0;
}
// wrapper.cpp
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <dlfcn.h>
#include <cstdio>
static void (*real_free)(void* ptr) = NULL;
static void* (*real_calloc)(size_t nmemb, size_t size) = NULL;
static bool initializing = false;
static void init()
{
initializing = true;
fprintf(stderr,"init()\n");
real_free = (void (*)(void*))dlsym(RTLD_NEXT, "free");
real_calloc = (void* (*)(size_t, size_t))dlsym(RTLD_NEXT, "calloc");
if (!real_free or !real_calloc) {
fprintf(stderr,"Error in `dlsym()`: %s\n", dlerror());
}
initializing = false;
}
extern "C" void free(void *ptr)
{
fprintf(stderr,"free(%p)\n", ptr);
if (!real_free) {
init();
}
real_free(ptr);
}
extern "C" void* calloc(size_t nmemb, size_t size)
{
static char memory[32] { 0 }; // Hack to provide memory to dlsym()
if (initializing) {
fprintf(stderr,"calloc(%lu, %lu): %p\n", nmemb, size, &memory);
return memory;
}
if (!real_calloc) {
init();
}
void* ptr = real_calloc(nmemb, size);
fprintf(stderr,"calloc(%lu, %lu): %p\n", nmemb, size, ptr);
return ptr;
}
# Makefile
CC = g++
CFLAGS = -std=c++17 -Wall
all: test
test: test.cpp wrapper.so
$(CC) $(CFLAGS) -pthread -o test test.cpp -ldl
wrapper.o: wrapper.cpp
$(CC) $(CFLAGS) -c -fPIC -o wrapper.o wrapper.cpp
wrapper.so: wrapper.o
$(CC) $(CFLAGS) -shared -o wrapper.so wrapper.o -ldl
clean:
rm -f *.o *.so test
输出:
$ LD_PRELOAD=./wrapper.so ./test
init()
calloc(1, 32): 0x7f2a02bf1080 -- dlsym() requests memory
calloc(11, 11): 0x7fffd400d260 -- calloc(11, 11) in test.cpp
free(0x7fffd400d260) -- free() in test.cpp
calloc(17, 16): 0x7fffd400d2f0 -- pthread_create() requests memory
free((nil)) -- an attempt to free previously allocated memory?
【问题讨论】:
-
线程有mmap(2)-ed 内存用于它们的call stack。见clone(2),研究GNU libc的源码。它是免费软件。
fprintf也会调用malloc -
fprintf和朋友们是相对高级的库函数,它们可以自己使用 malloc/free。从劫持的 malloc/free 调用中调用它们可能会产生不稳定的结果。 -
人们所说的“内存泄漏”至少有两种不同的含义。一个是程序在退出之前不会释放它分配的所有内存。您的程序似乎表现出这种行为,但如果仅此而已,这种泄漏不会产生太大影响。您需要担心的内存泄漏是当程序分配内存然后丢失指向它的指针时,它无法释放该内存。甚至这只是一个重大问题,泄漏单独较大或可能总体较大。
-
明确一点,我并不是在提倡草率的编程。我只是说问题中展示的行为,如果输出确实准确地反映了程序的行为,还不足以让我有理由担心。
-
在
nil触发断点并查看堆栈跟踪。