覆盖“malloc”使用LD_PRELOAD机制
我正在尝试编写一个简单的共享库,它将记录对 stderr 的 malloc 调用(如果您愿意,可以称为“mtrace”)。
然而,这是行不通的。 这就是我所做的:
/* mtrace.c */
#include <dlfcn.h>
#include <stdio.h>
static void* (*real_malloc)(size_t);
void *malloc(size_t size)
{
void *p = NULL;
fprintf(stderr, "malloc(%d) = ", size);
p = real_malloc(size);
fprintf(stderr, "%p\n", p);
return p;
}
static void __mtrace_init(void) __attribute__((constructor));
static void __mtrace_init(void)
{
void *handle = NULL;
handle = dlopen("libc.so.6", RTLD_LAZY);
if (NULL == handle) {
fprintf(stderr, "Error in `dlopen`: %s\n", dlerror());
return;
}
real_malloc = dlsym(handle, "malloc");
if (NULL == real_malloc) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
我用以下命令进行编译:
gcc -shared -fPIC -o mtrace.so mtrace.c
然后当我尝试执行 ls 时:
$ LD_PRELOAD=./mtrace.so ls
malloc(352) = Segmentation fault
现在,我怀疑 dlopen 需要 malloc,并且当我在共享库中重新定义它时,它使用该版本仍然未分配的real_malloc
。
问题是……我该如何让它发挥作用?
PS 抱歉,标签很少,我找不到合适的标签,而且我仍然没有足够的声誉来创建新标签。
I'm trying to write a simple shared library that would log malloc calls to stderr (a sort of 'mtrace' if you will).
However, this is not working.
Here's what I do:
/* mtrace.c */
#include <dlfcn.h>
#include <stdio.h>
static void* (*real_malloc)(size_t);
void *malloc(size_t size)
{
void *p = NULL;
fprintf(stderr, "malloc(%d) = ", size);
p = real_malloc(size);
fprintf(stderr, "%p\n", p);
return p;
}
static void __mtrace_init(void) __attribute__((constructor));
static void __mtrace_init(void)
{
void *handle = NULL;
handle = dlopen("libc.so.6", RTLD_LAZY);
if (NULL == handle) {
fprintf(stderr, "Error in `dlopen`: %s\n", dlerror());
return;
}
real_malloc = dlsym(handle, "malloc");
if (NULL == real_malloc) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
I compile this with:
gcc -shared -fPIC -o mtrace.so mtrace.c
And then when I try to execute ls
:
$ LD_PRELOAD=./mtrace.so ls
malloc(352) = Segmentation fault
Now, I suspect that dlopen needs malloc, and as I am redefining it within the shared library, it uses that version with the still unassigned real_malloc
.
The question is...how do I make it work?
P.S. sorry for the paucity in tags, I couldn't find appropriate tags, and I still don't have enough reputation to create new ones.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我总是这样做:
不使用构造函数,只需在第一次调用
malloc
时进行初始化。使用RTLD_NEXT
避免dlopen
。您还可以尝试 malloc 挂钩。请注意,所有这些都是 GNU 扩展,可能在其他地方不起作用。I always do it this way:
Don't use constructors, just initialize at first call to
malloc
. UseRTLD_NEXT
to avoiddlopen
. You can also try malloc hooks. Be aware that all those are GNU extensions, and probably wont work elsewhere.如果您确实想将 LD_PRELOAD 与 malloc 一起使用,并且发现接受的答案中的代码仍然存在段错误,那么我有一个似乎可行的解决方案。
段错误是由于 dlsym 调用 32 个字节的 calloc 引起的,导致递归到堆栈末尾。
我的解决方案是创建一个超级简单的静态分配器,在 dlsym 返回 malloc 函数指针之前处理分配。
希望这对某人有帮助。
If you really want to use LD_PRELOAD with malloc and found that the code in the accepted answer still segfaults, I have a solution that seems to work.
The segfault was caused by dlsym calling calloc for 32 bytes, causing a recursion to the end of the stack.
My solution was to create a super-simple static allocator that takes care of allocations before dlsym returns the malloc function pointer.
Hope this helps someone.
如果您使用 glibc,则应该使用其 内置 malloc挂钩机制 - 本页中的示例有一个如何查找原始 malloc 的示例。如果您要向分配添加额外的跟踪信息,这一点尤其重要,以确保返回 malloc 缓冲区的库函数与您的
free()
实现保持一致。If you are using glibc, you should use its built in malloc hooking mechanism - the example in this page has an example of how to look up the original malloc. This is particularly important if you're adding additional tracking information to allocations, to ensure library functions which return malloc'd buffers are consistent with your
free()
implementation.下面是上述示例的扩展,它通过使用
mmap
直到初始化完成来避免 dlsym 中的段错误:Here's an extension to the above examples which avoids segfaults in dlsym by using
mmap
until initialization is complete:这是 malloc 和 free hooking 的最简单示例。
Here is the simplest example for malloc and free hooking.
对于 C++ 编译器,可能需要像这样 extern 直接重写函数
For c++ compiler there could be a need to extern directly overridden function like this