threads/90392: libc stdio memory leak with pthread
Daniel Hartmeier
dhartmei at FreeBSD.org
Wed Dec 14 08:30:05 PST 2005
>Number: 90392
>Category: threads
>Synopsis: libc stdio memory leak with pthread
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: freebsd-threads
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Wed Dec 14 16:30:03 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Daniel Hartmeier
>Release: FreeBSD 6.0-STABLE i386
>Organization:
>Environment:
>Description:
Calling sscanf(3) with a '%c' conversion from a multi-threaded
(-lpthread) program leaks memory.
>How-To-Repeat:
Compile and run the following minimal example and observe the
leak, e.g. with top(1)
$ gcc -o test test.c -lpthread
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
static void *leak(void *p)
{
const char *s = "foo";
char t[4];
while (1) {
(void)sscanf(s, "%3c", t);
usleep(1000);
}
return (NULL);
}
int main()
{
pthread_t t;
int r;
if ((r = pthread_create(&t, NULL, &leak, NULL)))
return (1);
while (1)
usleep(1000);
return (0);
}
>Fix:
See /usr/src/lib/libc/stdio/
sscanf.c sscanf() sets up a private FILE object, initializes the
thread locking extra with INITEXTRA(), and passes it to
__svfscanf().
vfscanf.c __svfscanf() enters case CT_CHAR: with neither LONG
nor SUPPRESS flags set, and calls fread().
fread.c fread() uses FLOCKFILE() and FUNLOCKFILE(), which in this
case are _flockfile() and _funlockfile().
_flock_stub.c _flockfile() calls _pthread_mutex_lock(2) on the
mutex in the extra passed from sscanf().
The mutex was initialized using PTHREAD_MUTEX_INITIALIZER
through INITEXTRA(). While it appears to be valid to use the
mutex after such initialization (without a pthread_create(2)
call), that usage causes delayed initialization which requires
a call to pthread_mutex_destroy(2) afterwards.
The following patch fixes the leak for me:
--- sscanf.c.orig Wed Dec 14 17:16:18 2005
+++ sscanf.c Wed Dec 14 17:16:36 2005
@@ -78,5 +78,6 @@
va_start(ap, fmt);
ret = __svfscanf(&f, fmt, ap);
va_end(ap);
+ _pthread_mutex_destroy(&f._extra->fl_mutex);
return (ret);
}
If you grep for other INITEXTRA() calls, those might require a
similar fix, possibly justifying an additional macro like
FREEEXTRA().
I'm not familiar enough with libc's FILE extra structure nor
with pthread_mutex semantics to be perfectly sure.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-threads
mailing list