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 作为解决方法。
我最近在调试一个产品的崩溃,并确定原因是 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 作为解决方法。