Bug 71292

Summary: STL / Pthreads - memory leaks
Product: [Retired] Red Hat Linux Reporter: Need Real Name <desertcoder>
Component: libg++Assignee: Jakub Jelinek <jakub>
Status: CLOSED DUPLICATE QA Contact:
Severity: high Docs Contact:
Priority: medium    
Version: 7.3   
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2002-08-12 20:30:57 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Need Real Name 2002-08-12 04:45:09 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 Galeon/1.2.5 (X11; Linux i686; U;) Gecko/20020606

Description of problem:
Programs developed using STL strings, maps, vectors, etc. with pthreads causes
severe memory leaks.

Version-Release number of selected component (if applicable):


How reproducible:
Always

Steps to Reproduce:
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


Actual Results:  The followingis 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.

Expected Results:  No memory leaks should occur.

Additional info:

Thanks to anyone who helps this new programmer stay off the unemployment line.
:-( Any help greatly appreciated.

Ken

Comment 1 Need Real Name 2002-08-12 20:30:51 UTC
Sorry. My last post did not completely display the memory leak problem. Here is
a better example:

////////////////////////////////////////////////////////////////////
// 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 strMultiplier = 10;	

int main(int argc, char **argv) 
{
	int numThreads = 40;
	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");
	
	int r = 5  * strMultiplier;
	for ( int i = 0; i <= r; i++  ) {
		s5.assign(s1 + s2);
		s1.assign(s5);
	}		
	s6.assign(s3 + s2 + s1);
		
	return NULL; 
}

////////////////////////////////////////////////////////////////////
// END: stl_leaker.cpp                                            //
////////////////////////////////////////////////////////////////////


When strMultiplier = 10, Valgrind reports:

==11851== LEAK SUMMARY:
==11851==    definitely lost: 0 bytes in 0 blocks.
==11851==    possibly lost:   0 bytes in 0 blocks.
==11851==    still reachable: 9528 bytes in 4 blocks.


When strMultiplier = 100, Valgrind reports:

==18111== LEAK SUMMARY:
==18111==    definitely lost: 3544 bytes in 2 blocks.
==18111==    possibly lost:   125904 bytes in 37 blocks.
==18111==    still reachable: 45704 bytes in 14 blocks.


Can anyone make sense of this?

Ken




Comment 2 Jakub Jelinek 2002-08-16 09:51:23 UTC

*** This bug has been marked as a duplicate of 71354 ***