From owner-freebsd-threads@FreeBSD.ORG Wed Dec 14 16:30:05 2005 Return-Path: X-Original-To: freebsd-threads@hub.freebsd.org Delivered-To: freebsd-threads@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 3E34016A41F for ; Wed, 14 Dec 2005 16:30:05 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 935A543D67 for ; Wed, 14 Dec 2005 16:30:04 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id jBEGU4LL074204 for ; Wed, 14 Dec 2005 16:30:04 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id jBEGU4kT074202; Wed, 14 Dec 2005 16:30:04 GMT (envelope-from gnats) Resent-Date: Wed, 14 Dec 2005 16:30:04 GMT Resent-Message-Id: <200512141630.jBEGU4kT074202@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-threads@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Daniel Hartmeier Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id A785316A41F; Wed, 14 Dec 2005 16:27:46 +0000 (GMT) (envelope-from dhartmei@insomnia.benzedrine.cx) Received: from insomnia.benzedrine.cx (insomnia.benzedrine.cx [62.65.145.30]) by mx1.FreeBSD.org (Postfix) with ESMTP id 65EB543D4C; Wed, 14 Dec 2005 16:27:45 +0000 (GMT) (envelope-from dhartmei@insomnia.benzedrine.cx) Received: from insomnia.benzedrine.cx (dhartmei@localhost [127.0.0.1]) by insomnia.benzedrine.cx (8.13.4/8.12.11) with ESMTP id jBEGRjac014476 (version=TLSv1/SSLv3 cipher=DHE-DSS-AES256-SHA bits=256 verify=NO); Wed, 14 Dec 2005 17:27:45 +0100 (MET) Received: (from dhartmei@localhost) by insomnia.benzedrine.cx (8.13.4/8.12.10/Submit) id jBEGRjp0024926; Wed, 14 Dec 2005 17:27:45 +0100 (MET) Message-Id: <20051214162744.GI17140@insomnia.benzedrine.cx> Date: Wed, 14 Dec 2005 17:27:44 +0100 From: Daniel Hartmeier To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Daniel Eischen Subject: threads/90392: libc stdio memory leak with pthread X-BeenThere: freebsd-threads@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Daniel Hartmeier List-Id: Threading on FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Dec 2005 16:30:05 -0000 >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 #include #include 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: