Date: Tue, 1 May 2007 13:01:01 GMT From: Spencer Minear<minear@securecomputing.com> To: freebsd-gnats-submit@FreeBSD.org Subject: threads/112300: Memory leak in free_tls within ld-elf.so Message-ID: <200705011301.l41D11kJ077800@www.freebsd.org> Resent-Message-ID: <200705011310.l41DA5k0016828@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 112300 >Category: threads >Synopsis: Memory leak in free_tls within ld-elf.so >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 13:10:05 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Spencer Minear >Release: 6.0 >Organization: Secure Computing Corp >Environment: Found running our modified 6.0 code, but observed on 6.0 and code inspection suggests it is present on Current. >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 many short lived threads. Following test program shows the problem very quickly. #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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200705011301.l41D11kJ077800>