Gwinel / gperftools

Automatically exported from code.google.com/p/gperftools
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Segfault on OS X 10.9.2 #617

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

I compile and run a very simple C program, linking against tcmalloc:

{{{
#include <gperftools/tcmalloc.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
  int major, minor;
  const char* patch;
  tc_version(&major, &minor, &patch);
  printf("Hello, World! gperftools version %d.%d%s %d.%d%s\n",
         TC_VERSION_MAJOR, TC_VERSION_MINOR, TC_VERSION_PATCH,
         major, minor, patch);
  return 0;
}
}}}

gcc -Wall -g -I/tmp/gperftools/include -c hello-c.c
gcc -Wall -g -L/tmp/gperftools/lib -o hello-c hello-c.o
./hello

What is the expected output? What do you see instead?

I expect this to output the tcmalloc version number. Instead, I see a segfault:

{{{
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x0000000100005dda in do_calloc (n=Cannot access memory at address 
0x7fff5f3ffff8
) at src/tcmalloc.cc:1109
1109    inline void* do_calloc(size_t n, size_t elem_size) {
(gdb) bt
#0  0x0000000100005dda in do_calloc (n=Cannot access memory at address 
0x7fff5f3ffff8
) at src/tcmalloc.cc:1109
#1  0x00000001000288ca in tc_calloc (n=34, elem_size=8) at src/tcmalloc.cc:1575
#2  0x0000000100003dd4 in mz_calloc (zone=0x10003c880, num_items=34, size=8) at 
libc_override_osx.h:115
#3  0x00007fff93590b61 in malloc_zone_calloc ()
#4  0x00007fff935912ca in calloc ()
#5  0x00000001000d10cc in __emutls_get_address ()
}}}

What version of the product are you using? On what operating system?

This is gperftools 2.1, on OS X 10.9.2. I tried this with clang 3.4, gcc 4.6.4, 
and gcc 4.8.2.

Please provide any additional information below.

It seems that __emutls_get_address calls calloc(), which is forwarded to 
tcmalloc's tc_calloc(). Apparently this call has only a very small stack 
available, and by the time tc_calloc is reached, the stack pointer points to an 
address 8 bytes before addressable memory. In the backtrace above, 
0x7fff5f3ffff8 is not accessible, while 0x7fff5f3ffff8+0x8 is. I confirmed this 
by stepping up the stack and looking at $rsp.

I do not know how to enlarge the stack that is used by __emutls_get_address. 
However, this error can apparently be avoided by initializing tcmalloc later. 
By chaning line 904 of tcmalloc.cc to

  if (tcmallocguard_refcount++ == 1) {

things appear to work fine. I expect that this then executes the calloc() call 
from __emutls_get_address() with libc, only to activate tcmalloc later.

Original issue reported on code.google.com by schnetter on 7 Apr 2014 at 11:57

GoogleCodeExporter commented 9 years ago
Some emutls-related issue is fixed on master branch. May I ask you you to test 
latest master, please ?

Original comment by alkondratenko on 8 Apr 2014 at 12:00

GoogleCodeExporter commented 9 years ago
Yes, this also fixes the issue. Thanks for the pointer.

Original comment by schnetter on 8 Apr 2014 at 12:07

GoogleCodeExporter commented 9 years ago
Marking as CannotReproduce to avoid finding exactly issue number that fixed the 
problem on master.

Upcoming 2.2 release does not have the problem.

Original comment by alkondratenko on 8 Apr 2014 at 12:18