From nobody@FreeBSD.org  Sun Aug 16 03:47:32 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 6085E106568B
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 16 Aug 2009 03:47:32 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 4FA258FC3F
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 16 Aug 2009 03:47:32 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n7G3lVSc081938
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 16 Aug 2009 03:47:31 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n7G3lVRs081937;
	Sun, 16 Aug 2009 03:47:31 GMT
	(envelope-from nobody)
Message-Id: <200908160347.n7G3lVRs081937@www.freebsd.org>
Date: Sun, 16 Aug 2009 03:47:31 GMT
From: Eric Blake <ebb9@byu.net>
To: freebsd-gnats-submit@FreeBSD.org
Subject: fpurge violates stdio invariant
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         137819
>Category:       kern
>Synopsis:       [libc] [patch] fpurge(3) violates stdio invariant
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    eadler
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Aug 16 03:50:00 UTC 2009
>Closed-Date:    Wed Jun 13 03:26:00 UTC 2012
>Last-Modified:  Wed Jun 13 03:40:15 UTC 2012
>Originator:     Eric Blake
>Release:        6.1
>Organization:
N/A
>Environment:
FreeBSD freebsd6 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Sun May  7 04:42:56 UTC 2006     root@opus.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP  i386

>Description:
According to the stdio source code, all streams must meet the invariant that if a stream is open for both reading and writing, then _w is 0 if the stream is not currently writing.  If this invariant is violated, then code like putc will misbehave, and fflush will not realize that there is data to be written.  Unfortunately, fpurge blindly sets _w to non-zero even on read-write file streams where pending read data was flushed.  This in turn requires the gnulib fpurge module to write a wrapper around fpurge and poke at FILE internals in a number of GNU projects.
>How-To-Repeat:
$ cat foo.c
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char **argv)
{
  FILE *f = fopen("bar", "w+");
  fputs ("abc", f);
  rewind (f);
  while (EOF != fgetc (f));
  fpurge (f); /* Nothing to purge, but stream state now corrupted.  */
  argc > 1 ? putc ('d', f) : fputc ('d', f);
  return 0;
}
$ ./foo
$ cat bar && echo
abc
$ ./foo 1
$ cat bar && echo
abc

Expected behavior - both './foo' and './foo 1' should set the contents of bar to "abcd".  However, fpurge mistakenly set the _w member to nonzero, while leaving the __SRD flag set (rather than setting the __SWR flag), such that subsequent putc use the buffer without kicking the stream over to write mode, and the implicit fflush/fclose at program exit see that the stream is in read mode and assume that nothing needs to be flushed.

>Fix:
In fpurge.c, replace this line:

		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;

with:

		fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->eadler 
Responsible-Changed-By: eadler 
Responsible-Changed-When: Thu May 10 18:25:20 UTC 2012 
Responsible-Changed-Why:  
I'll take it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=137819 
State-Changed-From-To: open->analyzed 
State-Changed-By: eadler 
State-Changed-When: Fri May 11 02:38:01 UTC 2012 
State-Changed-Why:  
awaiting approval 

http://www.freebsd.org/cgi/query-pr.cgi?pr=137819 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/137819: commit references a PR
Date: Wed, 30 May 2012 04:06:52 +0000 (UTC)

 Author: eadler
 Date: Wed May 30 04:06:38 2012
 New Revision: 236288
 URL: http://svn.freebsd.org/changeset/base/236288
 
 Log:
   Only set _w to 0 when the file stream is not currently reading. Without
   this fflush may fail to write data in the buffer.
   
   PR:		kern/137819
   Submitted by:	Eric Blake <ebb9@byu.net>
   Reviewed by:	theraven
   Approved by:	cperciva
   MFC after:	2 weeks
 
 Modified:
   head/lib/libc/stdio/fpurge.c
 
 Modified: head/lib/libc/stdio/fpurge.c
 ==============================================================================
 --- head/lib/libc/stdio/fpurge.c	Wed May 30 03:57:49 2012	(r236287)
 +++ head/lib/libc/stdio/fpurge.c	Wed May 30 04:06:38 2012	(r236288)
 @@ -62,7 +62,7 @@ fpurge(fp)
  			FREEUB(fp);
  		fp->_p = fp->_bf._base;
  		fp->_r = 0;
 -		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
 +		fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
  		retval = 0;
  	}
  	FUNLOCKFILE(fp);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: analyzed->patched 
State-Changed-By: eadler 
State-Changed-When: Wed May 30 04:17:28 UTC 2012 
State-Changed-Why:  
committed, awaiting MFC 

http://www.freebsd.org/cgi/query-pr.cgi?pr=137819 
State-Changed-From-To: patched->closed 
State-Changed-By: eadler 
State-Changed-When: Wed Jun 13 03:25:59 UTC 2012 
State-Changed-Why:  
Committed. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=137819 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/137819: commit references a PR
Date: Wed, 13 Jun 2012 03:30:22 +0000 (UTC)

 Author: eadler
 Date: Wed Jun 13 03:29:57 2012
 New Revision: 236981
 URL: http://svn.freebsd.org/changeset/base/236981
 
 Log:
   MFC r236288:
   	Only set _w to 0 when the file stream is not currently reading. Without this fflush may fail to write data in the buffer.
   
   PR:		kern/137819
   Approved by:	cperciva (implicit)
 
 Modified:
   stable/7/lib/libc/stdio/fpurge.c
 Directory Properties:
   stable/7/lib/libc/   (props changed)
 
 Modified: stable/7/lib/libc/stdio/fpurge.c
 ==============================================================================
 --- stable/7/lib/libc/stdio/fpurge.c	Wed Jun 13 03:19:11 2012	(r236980)
 +++ stable/7/lib/libc/stdio/fpurge.c	Wed Jun 13 03:29:57 2012	(r236981)
 @@ -62,7 +62,7 @@ fpurge(fp)
  			FREEUB(fp);
  		fp->_p = fp->_bf._base;
  		fp->_r = 0;
 -		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
 +		fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
  		retval = 0;
  	}
  	FUNLOCKFILE(fp);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/137819: commit references a PR
Date: Wed, 13 Jun 2012 03:30:37 +0000 (UTC)

 Author: eadler
 Date: Wed Jun 13 03:30:24 2012
 New Revision: 236982
 URL: http://svn.freebsd.org/changeset/base/236982
 
 Log:
   MFC r236288:
   	Only set _w to 0 when the file stream is not currently reading. Without this fflush may fail to write data in the buffer.
   
   PR:		kern/137819
   Approved by:	cperciva (implicit)
 
 Modified:
   stable/8/lib/libc/stdio/fpurge.c
 Directory Properties:
   stable/8/lib/libc/   (props changed)
 
 Modified: stable/8/lib/libc/stdio/fpurge.c
 ==============================================================================
 --- stable/8/lib/libc/stdio/fpurge.c	Wed Jun 13 03:29:57 2012	(r236981)
 +++ stable/8/lib/libc/stdio/fpurge.c	Wed Jun 13 03:30:24 2012	(r236982)
 @@ -62,7 +62,7 @@ fpurge(fp)
  			FREEUB(fp);
  		fp->_p = fp->_bf._base;
  		fp->_r = 0;
 -		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
 +		fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
  		retval = 0;
  	}
  	FUNLOCKFILE(fp);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/137819: commit references a PR
Date: Wed, 13 Jun 2012 03:34:51 +0000 (UTC)

 Author: eadler
 Date: Wed Jun 13 03:34:42 2012
 New Revision: 236983
 URL: http://svn.freebsd.org/changeset/base/236983
 
 Log:
   MFC r236288:
   	Only set _w to 0 when the file stream is not currently reading. Without this fflush may fail to write data in the buffer.
   
   PR:		kern/137819
   Approved by:	cperciva (implicit)
 
 Modified:
   stable/9/lib/libc/stdio/fpurge.c
 Directory Properties:
   stable/9/lib/libc/   (props changed)
 
 Modified: stable/9/lib/libc/stdio/fpurge.c
 ==============================================================================
 --- stable/9/lib/libc/stdio/fpurge.c	Wed Jun 13 03:30:24 2012	(r236982)
 +++ stable/9/lib/libc/stdio/fpurge.c	Wed Jun 13 03:34:42 2012	(r236983)
 @@ -62,7 +62,7 @@ fpurge(fp)
  			FREEUB(fp);
  		fp->_p = fp->_bf._base;
  		fp->_r = 0;
 -		fp->_w = fp->_flags & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
 +		fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
  		retval = 0;
  	}
  	FUNLOCKFILE(fp);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
