Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 26 Jan 2011 20:14:12 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r217900 - stable/7/lib/libc/stdio
Message-ID:  <201101262014.p0QKECiT088423@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Wed Jan 26 20:14:12 2011
New Revision: 217900
URL: http://svn.freebsd.org/changeset/base/217900

Log:
  MFC 216334:
  When reopening a stream backed by an open file descriptor, do not close
  the existing file descriptor.  Instead, let dup2() atomically close the
  old file descriptor when assigning the newly opened file to the same
  descriptor.  This closes a race in a multithreaded application where a
  concurrent open() could allocate the existing file descriptor in between
  the calls to close() and dup2().

Modified:
  stable/7/lib/libc/stdio/freopen.c
Directory Properties:
  stable/7/lib/libc/   (props changed)
  stable/7/lib/libc/stdtime/   (props changed)

Modified: stable/7/lib/libc/stdio/freopen.c
==============================================================================
--- stable/7/lib/libc/stdio/freopen.c	Wed Jan 26 20:14:03 2011	(r217899)
+++ stable/7/lib/libc/stdio/freopen.c	Wed Jan 26 20:14:12 2011	(r217900)
@@ -150,14 +150,6 @@ freopen(file, mode, fp)
 
 	/* Get a new descriptor to refer to the new file. */
 	f = _open(file, oflags, DEFFILEMODE);
-	if (f < 0 && isopen) {
-		/* If out of fd's close the old one and try again. */
-		if (errno == ENFILE || errno == EMFILE) {
-			(void) (*fp->_close)(fp->_cookie);
-			isopen = 0;
-			f = _open(file, oflags, DEFFILEMODE);
-		}
-	}
 	sverrno = errno;
 
 finish:
@@ -165,9 +157,11 @@ finish:
 	 * Finish closing fp.  Even if the open succeeded above, we cannot
 	 * keep fp->_base: it may be the wrong size.  This loses the effect
 	 * of any setbuffer calls, but stdio has always done this before.
+	 *
+	 * Leave the existing file descriptor open until dup2() is called
+	 * below to avoid races where a concurrent open() in another thread
+	 * could claim the existing descriptor.
 	 */
-	if (isopen)
-		(void) (*fp->_close)(fp->_cookie);
 	if (fp->_flags & __SMBF)
 		free((char *)fp->_bf._base);
 	fp->_w = 0;
@@ -186,6 +180,8 @@ finish:
 	memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t));
 
 	if (f < 0) {			/* did not get it after all */
+		if (isopen)
+			(void) (*fp->_close)(fp->_cookie);
 		fp->_flags = 0;		/* set it free */
 		FUNLOCKFILE(fp);
 		errno = sverrno;	/* restore in case _close clobbered */
@@ -197,11 +193,12 @@ finish:
 	 * to maintain the descriptor.  Various C library routines (perror)
 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
 	 */
-	if (wantfd >= 0 && f != wantfd) {
+	if (wantfd >= 0) {
 		if (_dup2(f, wantfd) >= 0) {
 			(void)_close(f);
 			f = wantfd;
-		}
+		} else
+			(void)_close(fp->_file);
 	}
 
 	/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101262014.p0QKECiT088423>