threads/112297: Memory leak in ld-elf.so with each thread
destruction
Spencer Minear
minear at securecomputing.com
Tue May 1 12:50:10 UTC 2007
>Number: 112297
>Category: threads
>Synopsis: Memory leak in ld-elf.so with each thread destruction
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-threads
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue May 01 12:50:09 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator: Spencer Minear
>Release: 6.0
>Organization:
Secure Computing Corp
>Environment:
Found on our modified secure version of 6.0, but present on a straight 6.0 and later systems
>Description:
The allocate_tls function in libexec/rtld-elf/rtld.c allocates two memory areas with each call. The free_tls function in the same file only free's one of them wich each call. I.E. there is a memory leak with each thread distruction. The problem gets rather serious for applications like a mail filter based on libmilter.
We found the problem with our modified 6.0 based system but it code has not changed even on current so I think it is present in all current released versions fo the code.
A static link does not leak, which lead us to the solution in that the code for the same functions in libc (gen/tls.c) does not have the problem. The problem was observed when we used both libpthread and libthr, thus pointin us to the ld-elf code.
>How-To-Repeat:
Run a program that creates and destorys threads at a high rate. The following simple test program does the job quite nicely.
#include <sys/types.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#define INFO_FILE "thread_test_file"
#define CREATE_THREAD(ret, func, arg) \
{ \
pthread_t tid; \
if ((ret = pthread_create(&tid, NULL, func, (void*)(arg))) == 0) \
ret = pthread_detach(tid); \
}
static void*
mem_thread(void *arg)
{
int fd;
FILE *fp;
pthread_t tid;
tid = pthread_self();
if ((fd = open(INFO_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644))
< 0) {
fprintf(stderr, "Error opening %s: %s\n", INFO_FILE, strerror(errno));
return(NULL);
}
printf("File %s created\n", INFO_FILE);
if ((fp = fdopen(fd, "w")) == NULL) {
printf("Can't fdopen fd %d, %s\n",
fd, strerror(errno));
close(fd);
return(NULL);
}
fprintf(fp, "TEST of writing to file");
fflush(fp);
fclose(fp);
close(fd);
return(NULL);
}
int
main(int argc, char **argv, char **envp)
{
int ret;
struct timespec rqtp;
int i = 0;
printf("Starting\n");
while (1) {
CREATE_THREAD(ret, &mem_thread, NULL);
if (ret) {
perror("Creating thread1");
return -1;
}
rqtp.tv_sec = 0;
rqtp.tv_nsec = 1000 * (i % 25);
nanosleep(&rqtp, NULL);
i++;
}
return 0;
}
>Fix:
Copy the logic in the libc/gen/tls.c code and add a call to free the dtv pointer in free_tls within rtld.c.
The Diff within in our code base CVS tree is as follows. This seems to fix the problem. I trust you will let us know if we are overlooking something and this fix is not safe.
--- rtld.c 3 Jan 2006 20:44:27 -0000 1.4
+++ rtld.c 1 May 2007 12:37:45 -0000
@@ -2733,6 +2733,7 @@
}
free((void*) tlsstart);
+ free(dtv);
}
#endif
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-threads
mailing list