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

标签 c++ linux apache2 shared-libraries coredump

我在 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/

相关文章:

python - 在 Ubuntu 14.04 上使用 Apache2 和 mod_wsgi 服务 Django 1.8 应用程序时出错

c - stat() 函数似乎在测试 PAM 模块中不起作用

linux - 如何指定 sshfs 的 key 文件?

apache - 如何使用 .htaccess 重定向错误的引用?

C++ 输入验证

c++ - 为什么我的线程调用函数对象而不是将其返回值分配给 packaged_task 的 future 对象?

c++ - 数组的静态 vector

ubuntu 虚拟主机上的 Symfony2 调试工具栏未找到

ubuntu - phpmyadmin 为 PMA_DBI_num_rows() 发出 fatal error

c++ - 为 numeric_limit<T>::max() 指定无限限制?