Ser*_*kov 4 c++ linux coredump apache2 shared-libraries
我在RedHat Linux 5.0提供功能的内部共享库free和malloc:
>nm ./libmem_consumption.so | grep -P -e "\bfree\b|\bmalloc\b"
0000000000006540 T free
00000000000088a0 T malloc
Run Code Online (Sandbox Code Playgroud)
此共享库负责提供有关进程内存消耗的信息.不幸的是,当它与Apache一起使用时,这个共享库存在问题httpd.当使用这个库运行Apache httpd时,我得到一个coredump in libc::free和一条指针无效的消息.问题似乎是在http.so中,这是一个由libphp5.so加载的共享库,由httpd.
实际上,当我没有加载http.so一切都没关系,没有coredump.(加载或不加载http.so由配置文件中的指令管理:extension = http.so)当我加载http.sohttpd进程coredumps时.
httpd 以这种方式推出:
LD_PRELOAD=./libmem_consumption.so ./bin/httpd -f config
Run Code Online (Sandbox Code Playgroud)
和退出时的coredumps.
当我设置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]
Run Code Online (Sandbox Code Playgroud)
和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'
Run Code Online (Sandbox Code Playgroud)
看来,LD_PRELOAD=./libmem_consumption.so不用于http.so当free被查找.为什么忽略LD_PRELOAD?
它看起来http.so加载了RTLD_DEEPBIND标志,这就是为什么LD_PRELOAD被其他一个共享库忽略的原因.
这是来自http://linux.die.net/man/3/dlopen:
RTLD_DEEPBIND(自glibc 2.3.4起)将符号的查找范围放在此库的全局范围之前.这意味着一个独立的库将使用自己的符号而不是全局符号,这些符号包含在已加载的库中.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);
}
}
Run Code Online (Sandbox Code Playgroud)
并建立它:
gcc -shared -fPIC -g -m64 my_dlopen.cpp -o libmy_dlopen.so -ldl
Run Code Online (Sandbox Code Playgroud)
当我将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
Run Code Online (Sandbox Code Playgroud)
当我将UNSET_RTLD_DEEPBIND设置为1并运行httpd一切正常时.
export UNSET_RTLD_DEEPBIND=1
LD_PRELOAD=./libmy_dlopen.so:./ps/lib/libmem_consumption.so ./bin/httpd -f config
Run Code Online (Sandbox Code Playgroud)
这是UNSET_RTLD_DEEPBIND为1的LD_DEBUG = all的输出:
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'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2671 次 |
| 最近记录: |