У меня есть собственная общая библиотека в RedHat Linux 5.0, которая предоставляет функции free
а также malloc
:
>nm ./libmem_consumption.so | grep -P -e "\bfree\b|\bmalloc\b"0000000000006540 T free
00000000000088a0 T malloc
Эта общая библиотека отвечает за предоставление информации о потреблении памяти процессом.
К сожалению, существует проблема с этой общей библиотекой, когда она используется с Apache httpd
,
Когда Apache httpd запускается с этой библиотекой, я получаю coredump в libc::free
и сообщение о том, что указатель недействителен.
Проблема, кажется, в http.so, который является общей библиотекой, загруженной libphp5.so, которая загружается httpd
,
На самом деле, когда я не загружаю http.so
все ок и нет coredump.
(Загружается или не загружается http.so
управляется директивой в файле конфигурации: extension = http.so)
Когда я загружаю http.so
httpd процесс coredumps.
httpd
получается так:
LD_PRELOAD=./libmem_consumption.so ./bin/httpd -f config
и 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]
И совершенно другой для 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'
Кажется, что 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 (начиная с версии 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);
}
}
И построил это:
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'
Других решений пока нет …