tcmalloc 和 glibc 公开的符号冲突

conflict in symbols exposed by tcmalloc and glibc

我最近在调试一个产品的崩溃,并确定原因是 glibc 和 tcmalloc 公开的内存分配符号发生冲突。我写了下面的示例代码来暴露这个问题:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <assert.h>
#include <stdlib.h>

int main()
{
        struct addrinfo hints = {0}, *res = NULL;
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
        int rc = getaddrinfo("myserver", NULL, &hints, &res);
        assert(rc == 0);
        return 0;
}

我使用以下命令编译它:

g++ temp.cpp -g -lresolv

我使用以下命令执行程序:

LD_PRELOAD=/path/to/libtcmalloc_minimal.so.4 ./a.out

程序崩溃并出现以下堆栈:

#0 0x00007ffff6c7c875 in *__GI_raise (sig=) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

#1 0x00007ffff6c7de51 in *__GI_abort () at abort.c:92

#2 0x00007ffff6cbd8bf in __libc_message (do_abort=2, fmt=0x7ffff6d8c460 "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:186

#3 0x00007ffff6cc30c8 in malloc_printerr (action=2, str=0x7ffff6d88fec "free(): invalid pointer", ptr=) at malloc.c:6282

#4 0x00007ffff6cc810c in *__GI___libc_free (mem=) at malloc.c:3733

#5 0x00007ffff6839e89 in _nss_dns_gethostbyname4_r (name=0x400814 "myserver", pat=0x7fffffffdfa8, buffer=0x7fffffffd9b0 "myserver.mydomain.com", buflen=1024, errnop=0x7fffffffdfbc, herrnop=0x7fffffffdf98, ttlp=0x0) at nss_dns/dns-host.c:341

#6 0x00007ffff6d11917 in gaih_inet (name=0x400814 "myserver", service=0x7fffffffdf88, req=0x7fffffffe1d0, pai=0x7fffffffe160, naddrs=0x7fffffffe168) at ../sysdeps/posix/getaddrinfo.c:880

#7 0x00007ffff6d14301 in *__GI_getaddrinfo (name=0x400814 "myserver", service=0x0, hints=0x7fffffffe1d0, pai=0x7fffffffe200) at ../sysdeps/posix/getaddrinfo.c:2452

#8 0x00000000004006f0 in main () at temp.cpp:12

这是因为 _nss_dns_gethostbyname4_r()libnss_dns.so 调用的 free() 函数是从 libc.so 调用的,而相应的 malloc() 是从 libresolv.so 来自 libtcmalloc_minimal.so。 tcmalloc 的 malloc()free() 函数的地址进入 libresolv.so 的 GOT 导致了这次崩溃。如果我不 link 我的程序到 libresolv.so.

,崩溃就会消失

现在是我的问题。是否有任何文档说明如何安全地使用 tcmalloc 来避免像这样的崩溃?

glibc 有一些用于插入 malloc:

的文档

不过,这里一定有其他事情要做。 glibc 和 glibc 的典型构建将得到这个权利(即使在任一包的相当旧的版本中)。

我最好的猜测是您正在使用一些 SUSE glibc 变体,which uses RTLD_DEEPBIND for NSS modules. This results in a known issue with malloc interposition. SUSE suggests setting the RTLD_DEEPBIND=0 environment variable 作为解决方法。