VOOZH about

URL: https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Resource_leaks

⇱ Linux Applications Debugging Techniques/Resource leaks - Wikibooks, open books for an open world


Jump to content
From Wikibooks, open books for an open world

Zombie threads

[edit | edit source]

Any thread that has terminated but has not been joined or detached will leak OS resources until the process terminates. Unfortunately, neither nor will show you these zombie threads, at least not on some kernels.

One way to get them is with a gdb canned command:

#
#
#
definetrace_call
b$arg0
commands
btfull
continue
end
end
documenttrace_call
Tracespecifiedcallwithcallstacktoscreen.Example:
setbreakpointpendingon
setpaginationoff
setloggingon
trace_call__pthread_create_2_1
end
Usinghostlibthread_dblibrary"/lib/i686/cmov/libthread_db.so.1".
(gdb)trace_call__pthread_create_2_1
Function"__pthread_create_2_1"notdefined.
Breakpoint1(__pthread_create_2_1)pending.
(gdb)trace_call__pthread_create_2_0
Function"__pthread_create_2_0"notdefined.
Breakpoint2(__pthread_create_2_0)pending.
(gdb)r
Startingprogram:/home/amelinte/projects/articole/wikibooks/debug/plockfoobarbax
[Threaddebuggingusinglibthread_dbenabled]
Breakpoint3at0xb7f9b746
Pendingbreakpoint"__pthread_create_2_1"resolved
Breakpoint4at0xb7f9c395
Pendingbreakpoint"__pthread_create_2_0"resolved
[NewThread0xb7e48ad0(LWP8635)]
[SwitchingtoThread0xb7e48ad0(LWP8635)]

Breakpoint3,0xb7f9b746inpthread_create@@GLIBC_2.1()from/lib/i686/cmov/libpthread.so.0
#0 0xb7f9b746 in pthread_create@@GLIBC_2.1 () from /lib/i686/cmov/libpthread.so.0
Nosymboltableinfoavailable.
#1 0x08048a7f in main (argc=4, argv=0xbfceb714) at plock.c:97
s=0
tnum=0
opt=-1
num_threads=3
tinfo=(structthread_info*)0x833b008
attr={__size='\0'<repeats13times>,"\020",'\0'<repeats21times>,__align=0}
stack_size=-1
res=(void*)0x0
[NewThread0xb7e47b90(LWP8638)]
Thread1:topofstacknear0xb7e473c8;argv_string=foo

Another way is to use (again) an interposition library:

/*
 * Hook library. Usage: 
 * gcc -c -g -Wall -fPIC libhook.c -o libhook.o 
 * ld -o libhook.so libhook.o -shared -ldl
 * LD_PRELOAD=./libhook.so program arguments
 * 
 * Copyright 2012 Aurelian Melinte. 
 * Released under GPL 3.0 or later. 
 */

#define _GNU_SOURCE
#include<dlfcn.h>

#include<signal.h>
#include<execinfo.h>

#include<errno.h>
#include<stdlib.h>
#include<stdio.h> /*printf*/
#include<unistd.h>

#include<pthread.h>

#include<assert.h>



typedefint(*lp_pthread_mutex_func)(pthread_mutex_t*mutex);
typedefint(*pthread_create_func)(pthread_t*thread,
constpthread_attr_t*attr,
void*(*start_routine)(void*),void*arg);
staticpthread_create_func_pthread_create_hook=NULL;


staticint
hook_one(pthread_create_func*fptr,constchar*fname)
{
char*msg=NULL;

assert(fname!=NULL);

if(*fptr==NULL){
printf("dlsym : wrapping %s\n",fname);
*fptr=dlsym(RTLD_NEXT,fname);
printf("next_%s = %p\n",fname,*fptr);
if((*fptr==NULL)||((msg=dlerror())!=NULL)){
printf("dlsym %s failed : %s\n",fname,msg);
return-1;
}else{
printf("dlsym: wrapping %s done\n",fname);
return0;
}
}else{
return0;
}
}


staticvoid
hook_funcs(void)
{
if(_pthread_create_hook==NULL){
intrc=hook_one(&_pthread_create_hook,"pthread_create");
if(NULL==_pthread_create_hook||rc!=0){
printf("Failed to hook.\n");
exit(EXIT_FAILURE);
}
}
}


/*
 *
 */


int
pthread_create(pthread_t*thread,
constpthread_attr_t*attr,
void*(*start_routine)(void*),void*arg)
{
#define SIZE 40
void*buffer[SIZE]={0};
intnptrs=0;

intrc=EINVAL;

rc=_pthread_create_hook(thread,attr,start_routine,arg);

printf("*** pthread_create:\n");
nptrs=backtrace(buffer,SIZE);
backtrace_symbols_fd(buffer,nptrs,STDOUT_FILENO);

returnrc;
}

/*
 *
 */

void_init()__attribute__((constructor));
void
_init()
{
printf("*** _init().\n");
hook_funcs();
}


void_fini()__attribute__((destructor));
void
_fini()
{
printf("*** _fini().\n");
}

The output is a bit rough but it can be refined down to file and line by replacing with appropriate code:

***pthread_create:
./libhook.so(pthread_create+0x8c)[0x400215d3]
./plock[0x8048a7f]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0x4006f450]
./plock[0x8048791]

File descriptors

[edit | edit source]

As just about anything is a file (folders, sockets, pipes, etc.), just about anything can result in a file descriptor that needs to be closed. can help:

# tree /proc/26041
/proc/26041
...
|--fd# Open files descriptors
||--0->/dev/pts/21
||--1->/dev/pts/21
||--2->/dev/pts/21
|`--3->socket:[113497835]
|--fdinfo
||--0
||--1
||--2
|`--3
...

The command for can help with the call stack.

If gdb is not available on the machine, an interposition library hooking , , , etc. can be built.

Other tools that can be used:

Ports

[edit | edit source]

Which process is using a port? As root:

# netstat -tlnp
ActiveInternetconnections(onlyservers)
ProtoRecv-QSend-QLocalAddressForeignAddressStatePID/Programname
tcp000.0.0.0:365100.0.0.0:*LISTEN-
tcp00127.0.0.1:22070.0.0.0:*LISTEN3438/python
...
# lsof
COMMANDPIDUSERFDTYPEDEVICESIZENODENAME
init1rootcwdDIR253,040962/
...
python3438root4uIPv411416TCPlocalhost.localdomain:2207(LISTEN)

# lsof -i :2207
COMMANDPIDUSERFDTYPEDEVICESIZENODENAME
python3438root4uIPv411416TCPlocalhost.localdomain:2207(LISTEN)

Other tools:

For semaphores, shared memory and message queues.

# ipcs -spt
------SemaphoreOperation/ChangeTimes--------
semidownerlast-oplast-changed
187826177aurelian_mFriFeb1009:37:262012FriFeb1009:33:392012
187858946aurelian_mFriFeb1009:52:112012FriFeb1009:50:442012

DYI: an interposition resource counter

[edit | edit source]

libmemleak can be easily modified to keep track of whatever resources are leaking. Hook the right API (e.g. ).