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