mzhaom / gperftools

Fast, multi-threaded malloc() and nifty performance analysis tools
https://code.google.com/p/gperftools/
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

tcmalloc crashes, missing function handlers #107

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi!

I wanted to give tcmalloc a try, but my program crashes. I tracked down the
issue to strdup() (and may be more functions that allocate memory which
must be freed again later) not being tracked. So a following free() on the
obtained pointer crashes the program.

It would be really nice if this could be fixed quite soon as for now
tcmalloc is unusable for a lot of programs (all which link to libraries
which use a not supported function).

Corin

Original issue reported on code.google.com by wakath...@gmail.com on 12 Feb 2009 at 6:53

GoogleCodeExporter commented 9 years ago
strdup calls (should call) malloc internally, and thus work fine.  What 
compiler are
you using?  What libc?  What kernel?  It would also be great if you could show a
minimal program that reproduces this problem, and the commands you ran to 
compile,
link, and run it.

Original comment by csilv...@gmail.com on 12 Feb 2009 at 7:36

GoogleCodeExporter commented 9 years ago
Any more info on this?  I hope to have a new perftools release out next week, 
and
would love to resolve this issue before then.  Otherwise, I'm afraid I will 
have to
close this bug as CannotReproduce.

Original comment by csilv...@gmail.com on 6 Mar 2009 at 9:03

GoogleCodeExporter commented 9 years ago
Sorry for the long delay. The error only seems to occur when a library with 
dlopen is
loaded. I created a small test application which reproduces the crash. It 
builds fine
using gcc-Version 4.2.3 (Ubuntu 4.2.3-2ubuntu7).

Output when run without tcmalloc:
==11564== Memcheck, a memory error detector.
==11564== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==11564== Using LibVEX rev 1854, a library for dynamic binary translation.
==11564== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==11564== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation 
framework.
==11564== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==11564== For more details, rerun with: -v
==11564== 
test: haha
all done
==11564== 
==11564== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 2)
==11564== malloc/free: in use at exit: 1,734 bytes in 7 blocks.
==11564== malloc/free: 12 allocs, 5 frees, 1,783 bytes allocated.
==11564== For counts of detected errors, rerun with: -v
==11564== searching for pointers to 7 not-freed blocks.
==11564== checked 204,656 bytes.
==11564== 
==11564== LEAK SUMMARY:
==11564==    definitely lost: 0 bytes in 0 blocks.
==11564==      possibly lost: 0 bytes in 0 blocks.
==11564==    still reachable: 1,734 bytes in 7 blocks.
==11564==         suppressed: 0 bytes in 0 blocks.
==11564== Rerun with --leak-check=full to see details of leaked memory.

Output when run with tcmalloc:
==11615== Memcheck, a memory error detector.
==11615== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==11615== Using LibVEX rev 1854, a library for dynamic binary translation.
==11615== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==11615== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation 
framework.
==11615== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==11615== For more details, rerun with: -v
==11615== 
==11615== Syscall param msync(start) points to uninitialised byte(s)
==11615==    at 0x509F7A0: __msync_nocancel (in /lib/libpthread-2.8.90.so)
==11615==    by 0x5FC7F27: access_mem (Ginit.c:128)
==11615==    by 0x5FC8A1D: _ULx86_64_step (libunwind_i.h:128)
==11615==    by 0x4E566DD: GetStackTrace(void**, int, int)
(stacktrace_libunwind-inl.h:78)
==11615==    by 0x4E40D13: tcmalloc::PageHeap::GrowHeap(unsigned long) 
(page_heap.cc:375)
==11615==    by 0x4E41017: tcmalloc::PageHeap::New(unsigned long) 
(page_heap.cc:91)
==11615==    by 0x4E3F84C: tcmalloc::CentralFreeList::Populate()
(central_freelist.cc:269)
==11615==    by 0x4E3FA27: tcmalloc::CentralFreeList::FetchFromSpansSafe()
(central_freelist.cc:236)
==11615==    by 0x4E3FABC: tcmalloc::CentralFreeList::RemoveRange(void**, 
void**,
int) (central_freelist.cc:214)
==11615==    by 0x4E41681: tcmalloc::ThreadCache::FetchFromCentralCache(unsigned
long, unsigned long) (thread_cache.cc:148)
==11615==    by 0x4E44F94: (anonymous namespace)::cpp_alloc(unsigned long, bool)
(thread_cache.h:280)
==11615==    by 0x4E5A217: operator new(unsigned long) (tcmalloc.cc:1036)
==11615==  Address 0x7ff000000 is on thread 1's stack
test: haha
==11615== 
==11615== Invalid free() / delete / delete[]
==11615==    at 0x4C252AF: free (vg_replace_malloc.c:323)
==11615==    by 0x61DB23B: dict_c::set(char const*, char const*) (dict.h:59)
==11615==    by 0x61DAE8B: test_c::test_c() (test.cpp:18)
==11615==    by 0x61DAEDB: test_create (test.cpp:28)
==11615==    by 0x400C1E: main_c::main_c(int, char**) (main.cpp:36)
==11615==    by 0x400C4C: main (main.cpp:48)
==11615==  Address 0x44820d8 is not stack'd, malloc'd or (recently) free'd
==11615== 
==11615== Invalid free() / delete / delete[]
==11615==    at 0x4C252AF: free (vg_replace_malloc.c:323)
==11615==    by 0x61DB1DC: dict_c::~dict_c() (dict.h:30)
==11615==    by 0x61DAE94: test_c::test_c() (test.cpp:18)
==11615==    by 0x61DAEDB: test_create (test.cpp:28)
==11615==    by 0x400C1E: main_c::main_c(int, char**) (main.cpp:36)
==11615==    by 0x400C4C: main (main.cpp:48)
==11615==  Address 0x44820d0 is not stack'd, malloc'd or (recently) free'd
==11615== 
==11615== Invalid free() / delete / delete[]
==11615==    at 0x4C252AF: free (vg_replace_malloc.c:323)
==11615==    by 0x61DB1E8: dict_c::~dict_c() (dict.h:31)
==11615==    by 0x61DAE94: test_c::test_c() (test.cpp:18)
==11615==    by 0x61DAEDB: test_create (test.cpp:28)
==11615==    by 0x400C1E: main_c::main_c(int, char**) (main.cpp:36)
==11615==    by 0x400C4C: main (main.cpp:48)
==11615==  Address 0x44820e0 is not stack'd, malloc'd or (recently) free'd
src/tcmalloc.cc:592] Attempt to free invalid pointer: 0x63dc030
==11615== 
==11615== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 13 from 1)
==11615== malloc/free: in use at exit: 1 bytes in 1 blocks.
==11615== malloc/free: 2 allocs, 4 frees, 33 bytes allocated.
==11615== For counts of detected errors, rerun with: -v
==11615== searching for pointers to 1 not-freed blocks.
==11615== checked 5,180,096 bytes.
==11615== 
==11615== LEAK SUMMARY:
==11615==    definitely lost: 0 bytes in 0 blocks.
==11615==      possibly lost: 0 bytes in 0 blocks.
==11615==    still reachable: 1 bytes in 1 blocks.
==11615==         suppressed: 0 bytes in 0 blocks.
==11615== Rerun with --leak-check=full to see details of leaked memory.
Aborted

Original comment by wakath...@gmail.com on 15 Mar 2009 at 3:08

Attachments:

GoogleCodeExporter commented 9 years ago
Interesting -- the memory in question is being allocated by tcmalloc, but freed 
by
libc malloc.

I think I see what's happening.  The code that's dlopen'ed does not get 
tcmalloc --
all memory allocations it does go through libc malloc.  That's fine.  However, 
libc
has been (properly) set to go through tcmalloc.  This means that if you call
malloc + free in your dlopen'ed library, everything will work fine.  But if you
call <some libc routine that mallocs> + free, you'll get a mismatch: tcmalloc 
for
the allocation, and libc for the free.

I believe this is because of the DEEPBIND flag that you passed to dlopen.  If 
you
take that out, at least in my testing, the program runs fine.

I'm going to close this as NotABug -- reopen if you still have trouble -- but 
will
see if there's any good way to update the docs to make this clear, as well.

Original comment by csilv...@gmail.com on 16 Mar 2009 at 3:39