gpt4 book ai didi

c++ - 为什么 LD_PRELOAD 不适用于加载的共享库之一?

转载 作者:IT王子 更新时间:2023-10-29 01:01:39 31 4
gpt4 key购买 nike

我在 RedHat Linux 5.0 上有一个内部共享库,它提供函数 freemalloc:

>nm ./libmem_consumption.so | grep -P -e "\bfree\b|\bmalloc\b"
0000000000006540 T free
00000000000088a0 T malloc

此共享库负责提供有关进程内存消耗的信息。不幸的是,这个共享库在与 Apache httpd 一起使用时会出现问题。当 Apache httpd 与这个库一起运行时,我在 libc::free 中得到一个核心转储和一条指针无效的消息。问题似乎出在 http.so 中,它是由 libphp5.so 加载的共享库,由 httpd 加载。

实际上,当我不加载 http.so 时,一切正常,没有 coredump。(加载或不加载 http.so 由配置文件中的指令管理:extension=http.so)当我加载 http.so 时,httpd 进程核心转储。

httpd 是这样启动的:

LD_PRELOAD=./libmem_consumption.so ./bin/httpd -f config

和退出时的核心转储。

当我设置 LD_BIND_NOW=1 并加载 http.so 时,我看到(在 gdb 下)http.so 有 free@plt 指向 libc: :free 并在其他加载库(例如 libphp5.so)free@plt 指向 libmem_consumption.so::free。这怎么可能?

顺便说一句,当我导出 LD_DEBUG=all 并将输出保存到一个文件时,我看到了 libphp5.so(也已加载)的这些行:

 25788: symbol=free;  lookup in file=/apache2/bin/httpd [0]
25788: symbol=free; lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
25788: binding file /apache2/modules/libphp5.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free' [GLIBC_2.2.5]

和 http.so 完全不同:

 25825: symbol=free;  lookup in file=/apache2/ext/http.so [0]
25825: symbol=free; lookup in file=/apache2/ps/lib/libz.so.1 [0]
25825: symbol=free; lookup in file=/apache2/ps/lib/libcurl.so.4 [0]
25825: symbol=free; lookup in file=/lib64/libc.so.6 [0]
25825: binding file /apache2/ext/http.so [0] to /lib64/libc.so.6 [0]: normal symbol `free'

当查找free 时,LD_PRELOAD=./libmem_consumption.so 似乎没有用于http.so。为什么忽略 LD_PRELOAD?

最佳答案

似乎 http.so 加载了 RTLD_DEEPBIND 标志,这就是为什么 LD_PRELOAD 被其中一个共享库忽略的原因。

这是来自 http://linux.die.net/man/3/dlopen :

RTLD_DEEPBIND (since glibc 2.3.4) Place the lookup scope of the symbols in this library ahead of the global scope. This means that a self-contained library will use its own symbols in preference to global symbols with the same name contained in libraries that have already been loaded. This flag is not specified in POSIX.1-2001.

我写了一个测试共享库:

  #include <dlfcn.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void initialize_my_dlopen(void) __attribute__((constructor));

void* (*real_dlopen)(const char *, int flag);
static int unset_RTLD_DEEPBIND=0;
static int _initialized = 0;

static void initialize_my_dlopen(void)
{
if (_initialized)
return;
real_dlopen = (void *(*)(const char *,int))dlsym(RTLD_NEXT, "dlopen");
unset_RTLD_DEEPBIND = atoi(getenv("UNSET_RTLD_DEEPBIND") ? getenv("UNSET_RTLD_DEEPBIND") : "0");
printf("unset_RTLD_DEEPBIND: %d\n", unset_RTLD_DEEPBIND);
_initialized = 1;
}

extern "C" {

void *dlopen(const char *filename, int flag)
{
int new_flag = unset_RTLD_DEEPBIND == 0 ? flag : flag & (~RTLD_DEEPBIND);
return (*real_dlopen)(filename, new_flag);
}
}

并构建它:

  gcc -shared -fPIC -g -m64 my_dlopen.cpp -o libmy_dlopen.so -ldl

当我将 UNSET_RTLD_DEEPBIND 设置为 0 并运行 httpd 程序 coredumps。

export UNSET_RTLD_DEEPBIND=0
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config

当我将 UNSET_RTLD_DEEPBIND 设置为 1 并运行 httpd 时,一切正常。

export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config

这是 LD_DEBUG=all 将 UNSET_RTLD_DEEPBIND 设置为 1 的输出:

 10678: symbol=free;  lookup in file=/apache2/bin/httpd [0]
10678: symbol=free; lookup in file=/apache2/libmy_dlopen.so [0]
10678: symbol=free; lookup in file=/apache2/ps/lib/libmem_consumption.so [0]
10678: binding file /apache2/ext/http.so [0] to /apache2/ps/lib/libmem_consumption.so [0]: normal symbol `free'

关于c++ - 为什么 LD_PRELOAD 不适用于加载的共享库之一?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13374240/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com