Почему LD_PRELOAD не работает для одной из загруженных разделяемых библиотек?

У меня есть собственная общая библиотека в 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 игнорируется?

3

Решение

Кажется, что 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'
8

Другие решения

Других решений пока нет …