我正在创建一个小型快速应用,可以检测其他应用中的内存泄漏。我使用LD_PRELOAD覆盖默认值malloc
并使用存储在内存中的每次调用程序中的malloc
。问题是C的某些库函数也使用malloc
。此外,还有一些库函数不会释放分配的内存。让我们来说明一下:
MyApp.cpp
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
static void * (* LT_MALLOC)(size_t) = 0;
static void (* LT_FREE)(void *) = 0;
static void init_malloc ()
{
char *error;
*(void **) (<_MALLOC) = dlsym (RTLD_NEXT, "malloc");
dlerror ();
if ((error = dlerror ()) != NULL)
{
fprintf (stderr, "%s\n", error);
_exit(1);
}
}
static void init_free ()
{
char *error;
*(void **) (<_FREE) = dlsym (RTLD_NEXT, "free");
dlerror ();
if ((error = dlerror ()) != NULL)
{
fprintf (stderr, "%s\n", error);
_exit(1);
}
}
extern "C"
void * malloc (size_t size) throw ()
{
if (LT_MALLOC == 0)
init_malloc ();
printf ("malloc(%ld) ", size);
void *p = LT_MALLOC(size);
printf ("p = %p\n", p);
return p;
}
extern "C"
void free (void *p) throw ()
{
if (LT_FREE == 0)
init_free ();
printf ("free(%p)\n", p);
LT_FREE(p);
}
test.c
。 (假设最初没有源代码,我只有一个程序。)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main (void)
{
printf ("test start\n");
int *a = (int *)malloc(3 * sizeof (int));
if (a)
printf ("Allocated 3 int - %p\n", a);
time_t t = time(NULL);
a[0] = 1;
printf ("time - %s", ctime(&t));
printf ("a[0] = %d\n", a[0]);
free (a);
printf ("CALL FREE(a)\n");
printf ("test done\n");
return 0;
}
$ g++ -g -fPIC -c MyApp.cpp -o MyApp.o
$ g++ -g -shared MyApp.o -o MyApp.so -ldl
$ gcc -g test.c -o test
$ export LD_PRELOAD=./MyApp.so
运行程序./test
并查看:
malloc(72704) p = 0x8aa040
test start
malloc(12) p = 0x6a0c50
Allocated 3 int - 0x6a0c50
free((nil))
malloc(15) p = 0x6a0c70
malloc(552) p = 0x6a0c90
free((nil))
malloc(1014) p = 0x6a0ec0
free(0x6a0c90)
malloc(20) p = 0x6a0c90
malloc(20) p = 0x6a0cb0
malloc(20) p = 0x6a0cd0
malloc(21) p = 0x6a0cf0
malloc(20) p = 0x6a0d10
malloc(20) p = 0x6a0d30
malloc(20) p = 0x6a0d50
malloc(20) p = 0x6a0d70
malloc(21) p = 0x6a0d90
free((nil))
time - Mon Mar 14 18:30:14 2016
a[0] = 1
free(0x6a0c50)
CALL FREE(a)
test done
但我希望看到:
test start
malloc(12) p = 0x6a0c50
Allocated 3 int - 0x6a0c50
time - Mon Mar 14 18:30:14 2016
a[0] = 1
free(0x6a0c50)
CALL FREE(a)
test done
我希望我的应用避免在库函数中使用malloc
。但我不知道该怎么做。
malloc
可以找出哪个函数调用它:库还是你自己的函数?或者我们可以调用默认值而不是覆盖库函数中的malloc
吗?或其他什么?
附:我很抱歉我的英语不好。
答案 0 :(得分:0)
也许Dynamic Loader API可以帮助您。在那里你可以找到函数dladdr(),它返回模块和给定地址的符号名称(如果有的话)。
请参阅dlopen的手册页以获取详细说明。
答案 1 :(得分:0)
我有很多次使用用我的自己的版本替换malloc
的宏来编译我的代码的技术。我以为我写了一个答案来证明这一点,但显然不是。像这样:
在“debugmalloc.h”或其他一些内容中:
#if DEBUG_MALLOC
#define malloc(x) myTrackingMalloc(x, __FILE__, __LINE__)
#define free(x) myTrackngFree(x, __FILE__, __LINE__)
extern void* myTrackingMalloc(size_t size, const char* file, int line);
extern void myTrackingFree(void* ptr, const char* file, int line);
#endif
然后在源文件中,例如“debugmalloc.c”:
#if DEBUG_MALLOC
void* myTrackingMalloc(size_t size, const char* file, int line)
{
void *p = malloc(size);
... whatever extra stuff you need ...
return p;
}
void myTrackingFree(void* ptr, const char* file, int line)
{
... some extra code here ...
free(ptr);
}
#endif
[我通过修改size
分配了一些额外的字节,然后添加了一个偏移来返回适当的实际有效负载指针]
这相对容易实现,并且没有使用LD_PRELOAD注入的缺点 - 特别是您不需要区分代码和库。当然,您不需要实现自己的malloc。
它确实有一个轻微的缺点,它不会覆盖new
,delete
,也不会覆盖strdup
和其他本身进行内存分配的库函数 - 你可以实现{{ 1}}和new
全局运算符集[不要忘记数组版本!],但替换delete
和任何其他可能分配内存的函数是相当多的工作 - 并且在那时, strdup
可能会更快,即使它运行得很慢。
答案 2 :(得分:0)
在发布的代码中,您不会跟踪calloc
,realloc
和strdup
。跟踪所有malloc
相关分配函数会更加一致。
您还可以跟踪fopen
和fclose
,以便在执行期间停用malloc
和free
跟踪。这也可以让您跟踪丢失的fclose()
来电。
对于使用malloc
的其他C库函数,您也可以这样做。 printf
使用malloc
的可能性不大,但您可以跟踪vfprintf
以过滤掉任何此类调用。包装可变参数函数很困难,但printf
系列都会调用vfprintf
或一些近亲,这取决于您的C库的实现。 当您自己致电vfprintf
时,请小心禁用printf
跟踪!