TCMALLOC和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 在 *__GI_raise (sig=( 中0x00007ffff6c7c875 在 ../nptl/sysdeps/unix/sysv/linux/raise.c:64

#1 在 *__GI_abort (( 中的 0x00007ffff6c7de51 在 abort.c:92

#2 0x00007ffff6cbd8bf in __libc_message (do_abort=2, fmt=0x7ffff6d8c460 "*** glibc 检测到 *** %s: %s: 0x%s ***"( 在 ../sysdeps/unix/sysv/linux/libc_fatal.c:186

#3 0x00007ffff6cc30c8 in malloc_printerr (action=2, str=0x7ffff6d88fec "free((: 无效指针", 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 在 *__GI_getaddrinfo (name=0x400814 "myserver", service=0x0, hints=0x7fffffffe1d0, pai=0x7fffffffe200( 中的 0x00007ffff6d14301 在 ../sysdeps/posix/getaddrinfo.c:2452

#8 在 main (( 中0x00000000004006f0 在 temp.cpp:12

原因是_nss_dns_gethostbyname4_r()libnss_dns.so调用的free()函数来自libc.so,而相应的malloc()是从libresolv.solibtcmalloc_minimal.so调用的。tcmalloc的malloc()free()函数的地址正在进入导致这次崩溃的libresolv.so的GOT中。如果我不将我的程序链接到libresolv.so,崩溃就会消失。

现在回答我的问题。是否有任何文档可以解释如何安全地使用 tcmalloc 来避免这样的崩溃?

glibc 有一些用于插入malloc的文档:

  • 替换malloc

不过,这里一定还有其他东西。 glibc 和 glibc 的典型构建将做到这一点(即使在任何一个包的相当旧的版本中(。

我最好的猜测是你正在使用一些SUSE glibc变体,它使用RTLD_DEEPBIND用于NSS模块。 这会导致malloc干预的已知问题。 SUSE 建议将RTLD_DEEPBIND=0环境变量设置为解决方法。

最新更新