stl / pthreads leak, patch
Kenneth Murray
desertcoder@cox.net
Sun Aug 11 21:20:00 GMT 2002
Here is a sample program that will always leak memory. It has been
tested using both GCC-2.9.6 and GCC-3.1.1 on RedHat Linux versions 6.2,
7.2, and 7.3. It has been tested using single and multi-processor
machines:
////////////////////////////////////////////////////////////////////
// BEGIN: stl_leaker.cpp //
////////////////////////////////////////////////////////////////////
#define _GNU_SOURCE
#define _REENTRANT
#define _THREAD_SAFE
#include <pthread.h>
#include <iostream>
#include <string>
#include <unistd.h>
using namespace std;
void *processClient(void *clientArgs);
pthread_attr_t attrDetached;
int main(int argc, char **argv)
{
int numThreads = 20;
pthread_attr_init(&attrDetached);
pthread_attr_setdetachstate(&attrDetached, PTHREAD_CREATE_DETACHED);
pthread_t clientThread; //Threads are detached, don't care about
handle
for ( int threadCount = 0; threadCount <= numThreads; threadCount++ ) {
if ( (pthread_create(&clientThread, &attrDetached, processClient,
(void *)NULL)) != 0 ) {
cout << endl << "ERROR: Could not create client thread.";
break;
}
}
sleep(10); //Make sure all detached threads have a chance to return
pthread_attr_destroy(&attrDetached);
cout << endl << "DONE !" << endl;
return 0;
}
void *processClient(void *clientArgs)
{
string s1, s2, s3, s4, s5, s6;
s1.assign("blah123");
s2.assign("blah123blah123");
s3.assign("blah123blah123blah123");
s4.assign("blah123blah123blah123blah123");
s5.assign(s1 + s2);
s6.assign(s3 + s2 + s1);
return NULL;
}
////////////////////////////////////////////////////////////////////
// END: stl_leaker.cpp //
////////////////////////////////////////////////////////////////////
This compile statement provides good debug output:
# g++ -g -DDEBUG stl_leaker.cpp -o stl_leaker -lpthread
Valgrind is an excellent, open-source tool for detecting memory leaks.
You can find it here http://developer.kde.org/~sewardj/ .
Here is the command line for Valgrind that was used to detect the leak:
# valgrind --leak-check=yes --leak-resolution=high --num-callers=20
--show-reachable=yes --trace-children=yes -v ./stl_leaker
The following is sample Valgrind output using the compile line above. I
know for a fact these are not false positives. If configured to run a
long time, this program will keep snatching memory until there is none
left. Notice it always complains about line 490 in stl_alloc.h:
.
.
.
==4532== Reading suppressions file: /usr/local/lib/valgrind/default.supp
==4532== Reading syms from /home/sserv/stl_leaker
==4532== Reading syms from /lib/ld-2.2.4.so
==4532== Reading syms from /usr/local/lib/valgrind/valgrind.so
==4532== Reading syms from /usr/local/lib/valgrind/libpthread.so
==4532== Reading syms from /usr/lib/libstdc++-3-libc6.2-2-2.10.0.so
==4532== Reading syms from /lib/libm-2.2.4.so
==4532== Reading syms from /lib/libc-2.2.4.so
==4532== Estimated CPU clock rate is 300 MHz
==4532==
valgrind's libpthread.so: IGNORED call to: pthread_attr_destroy
DONE !
valgrind's libpthread.so: libc_internal_tsd_get: dubious key 2
valgrind's libpthread.so: libc_internal_tsd_set: dubious key 2
valgrind's libpthread.so: libc_internal_tsd_get: dubious key 2
==4532==
==4532== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
--4532--
--4497-- supp: 1 __pthread_mutex_unlock/__register_frame_info
==4497== malloc/free: in use at exit: 4560 bytes in 2 blocks.
==4497== malloc/free: 23 allocs, 21 frees, 4812 bytes allocated.
==4497==
==4497== searching for pointers to 2 not-freed blocks.
==4497== checked 4135240 bytes.
==4497==
==4497== definitely lost: 0 bytes in 0 blocks.
==4497== possibly lost: 0 bytes in 0 blocks.
==4497== still reachable: 4560 bytes in 2 blocks.
==4497==
==4497== 1280 bytes in 1 blocks are still reachable in loss record 1 of
2
==4497== at 0x400457C4: malloc (vg_clientfuncs.c:100)
==4497== by 0x804B147: ??? (/usr/include/g++-3/stl_alloc.h:490)
==4497== by 0x804AF58: ??? (/usr/include/g++-3/stl_alloc.h:531)
==4497== by 0x804AE82: ??? (/usr/include/g++-3/stl_alloc.h:419)
==4497== by 0x804AD1C: ??? (/usr/include/g++-3/std/bastring.cc:33)
==4497== by 0x804AAFE: ??? (/usr/include/g++-3/std/bastring.cc:60)
==4497== by 0x804A93C: ??? (/usr/include/g++-3/std/bastring.cc:164)
==4497== by 0x804A6CA: ??? (/usr/include/g++-3/std/bastring.h:223)
==4497== by 0x804A558: ??? (/usr/include/g++-3/std/bastring.h:225)
==4497== by 0x804A1B4: processClient(void *) (stl_leaker.cpp:37)
==4497== by 0x40241166: thread_wrapper (vg_libpthread.c:521)
==4497== by 0x4004A7FC: do__apply_in_new_thread_bogusRA
(vg_scheduler.c:2023)
==4497== by 0x804A0DE: main (stl_leaker.cpp:28)
==4497== by 0x402E5336: __libc_start_main
(../sysdeps/generic/libc-start.c:129)
==4497== by 0x8049F61: pthread_mutex_unlock@@GLIBC_2.0 (in
/home/sserv/stl_leaker)
==4497==
==4497== 3280 bytes in 1 blocks are still reachable in loss record 2 of
2
==4497== at 0x400457C4: malloc (vg_clientfuncs.c:100)
==4497== by 0x804B147: ??? (/usr/include/g++-3/stl_alloc.h:490)
==4497== by 0x804AF58: ??? (/usr/include/g++-3/stl_alloc.h:531)
==4497== by 0x804AE82: ??? (/usr/include/g++-3/stl_alloc.h:419)
==4497== by 0x804AD1C: ??? (/usr/include/g++-3/std/bastring.cc:33)
==4497== by 0x804AAFE: ??? (/usr/include/g++-3/std/bastring.cc:60)
==4497== by 0x804A93C: ??? (/usr/include/g++-3/std/bastring.cc:164)
==4497== by 0x804A7F5: ??? (/usr/include/g++-3/std/bastring.cc:131)
==4497== by 0x804A730: ??? (/usr/include/g++-3/std/bastring.h:201)
==4497== by 0x804A595: ??? (/usr/include/g++-3/std/bastring.h:480)
==4497== by 0x804A25A: processClient(void *) (stl_leaker.cpp:42)
==4497== by 0x40241166: thread_wrapper (vg_libpthread.c:521)
==4497== by 0x4004A7FC: do__apply_in_new_thread_bogusRA
(vg_scheduler.c:2023)
==4497== by 0x804A0DE: main (stl_leaker.cpp:28)
==4497== by 0x402E5336: __libc_start_main
(../sysdeps/generic/libc-start.c:129)
==4497== by 0x8049F61: pthread_mutex_unlock@@GLIBC_2.0 (in
/home/sserv/stl_leaker)
==4497==
==4497== LEAK SUMMARY:
==4497== definitely lost: 0 bytes in 0 blocks.
==4497== possibly lost: 0 bytes in 0 blocks.
==4497== still reachable: 4560 bytes in 2 blocks.
==4497==
--4497-- lru: 0 epochs, 0 clearings.
--4497-- translate: new 1507 (23331 -> 307279), discard 0 (0 -> 0).
--4497-- dispatch: 0 basic blocks, 327/4209 sched events, 1539 tt_fast
misses.
--4497-- reg-alloc: 543 t-req-spill, 58421+3382 orig+spill uis, 7905
total-reg-r.
--4497-- sanity: 25 cheap, 1 expensive checks.
Thanks to anyone who helps this new programmer stay off the unemployment
line. :-( Any help greatly appreciated.
Ken
On Fri, 2002-08-09 at 15:29, Loren James Rittle wrote:
> Hi Ken, [You have been properly anonymized to allow a public response.
> Please use the list.]
>
> > I am experiencing the stl/pthreads memory leak problem when
> > compiling using g++[2.96]
>
> I believe that this used the old libstdc++-v2 implementation. Either
> way, the FSF didn't release gcc 2.96; you could contact Red Hat.
>
> > and 3.1.1 on RedHat Linux 6.2. I read a posting from you that
> > mentioned you have a patch for this.
>
> URL or other context? Surely not written circa gcc 3.1.1 release time.
>
> > Can you please let me know where I can find it? I seem to be having trouble.
>
> > Any help much appreciated.
>
> All patches related to known memory leaks in the libstdc++-v3 STL/threaded
> implementation are already in the GCC Repository. I am fairly sure
> that no improvements/fixes in this area have been made post gcc 3.1.1
> release.
>
> Please post the *smallest* reasonable test case with a leak if you
> want me to look at something in depth. I do promise to look at such
> postings.
>
> Regards,
> Loren
More information about the Libstdc++
mailing list