From rfg@tristatelogic.com  Fri Sep 12 22:06:26 2008
Return-Path: <rfg@tristatelogic.com>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 4CD451065671
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 12 Sep 2008 22:06:26 +0000 (UTC)
	(envelope-from rfg@tristatelogic.com)
Received: from segfault-outgoing-helo.tristatelogic.com (112.171-60-66-fuji-dsl.static.surewest.net [66.60.171.112])
	by mx1.freebsd.org (Postfix) with ESMTP id 096348FC19
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 12 Sep 2008 22:06:25 +0000 (UTC)
	(envelope-from rfg@tristatelogic.com)
Received: by segfault.tristatelogic.com (Postfix, from userid 1237)
	id 0DE14BDC5A; Fri, 12 Sep 2008 15:06:24 -0700 (PDT)
Message-Id: <20080912220624.0DE14BDC5A@segfault.tristatelogic.com>
Date: Fri, 12 Sep 2008 15:06:24 -0700 (PDT)
From: Ronald F.Guilmette <rfg@tristatelogic.com>
Reply-To: Ronald F.Guilmette <rfg@tristatelogic.com>
To: FreeBSD-gnats-submit@freebsd.org
Cc: rfg@tristatelogic.com
Subject: fwrite fails to generate error when applied to a read-only file
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         127335
>Category:       bin
>Synopsis:       [libc] fwrite(3) fails to generate error when applied to a read-only file
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    das
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Sep 12 22:10:04 UTC 2008
>Closed-Date:    Wed Jan 28 05:19:49 UTC 2009
>Last-Modified:  Wed Jan 28 05:19:49 UTC 2009
>Originator:     Ronald F. Guilmette
>Release:        FreeBSD 7.0-RELEASE i386
>Organization:
Infinite Monkeys & Co. LLC
>Environment:
System: FreeBSD segfault.tristatelogic.com 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Tue Aug 5 02:38:40 PDT 2008 root@segfault.monkeys.com:/usr/src/sys/i386/compile/rfg20080805 i386

>Description:
	It the fwrite() stdio library function is called and passed a file
	which has been opened read-only, then a return value of zero will
	be generated, but the error flag for the file will NOT be properly
	set.  This affects subsequent calls to ferror(file) where `file'
	was the read-only file upon which an incorrect attempt was made to 
	write.

	The failure of fwrite() to properly set the error flag for the file
	causes fwrite() to arguably violate its own documentation.  The
	relevant quote from the man page is as follows:

		The function fwrite() returns a value less than nmemb only
		if a write error has occurred.

	Zero is returned, and a write error _does_ occur when fwrite is asked
	to write to a read-only file, but subsequent calls to ferror() do not
	properly reflect that fact.

>How-To-Repeat:

	Consider the two trivial programs below which test the effects of
	passing the Wrong Type of file to fread() and fwrite() respectively.
	The first one correctly prints "Error reading from stdout", but the
	second one prints "This shouldn't happen!" because of the failure
	to properly set the file's error flag when fwrite() is called on a
	read-only file.

	Prog #1:
	=====================================================================
	#include <stdio.h>
	
	int
	main (void)
	{
	  char buf[1024];
	
	  fread (buf, 1, 12, stdout);
	  if (ferror (stdout))
	    printf ("Error reading from stdout\n");
	  else if (feof (stdout))
	    printf ("EOF detected while reading from stdout\n");
	  else
	    printf ("This shouldn't happen!\n");
	
	  return 0;
	}
	=====================================================================

	Prog #2:
	=====================================================================
	#include <stdio.h>
	
	int
	main (void)
	{
	  fwrite ("Hello world!", 1, 12, stdin);
	  if (ferror (stdin))
	    printf ("Error writing to stdin\n");
	  else if (feof (stdin))
	    printf ("EOF detected while writing to stdin\n");
	  else
	    printf ("This shouldn't happen!\n");
	
	  return 0;
	}
	=====================================================================

>Fix:
	I don't know for sure how to fix this, but I do know it ought to be
	pretty trivial to do.  I looked at the relevant stdio library code
	for awhile, but some of these macros are just too too ugly to even
	make sense of.  I suspect that the problem is either in the definition
	of the macro "prepwrite(fp)" in /usr/src/lib/libc/stdio/local.h or
	else it is in the function called __swsetup(fp).

	The comment just before the definition of the prepwrite() macro sez:

	/*
	 * Prepare the given FILE for writing, and return 0 iff it
	 * can be written now.  Otherwise, return EOF and set errno.
	 */

	Well, apparently, it doesn't actually set errno when it should, let
	alone the file's error flag.
>Release-Note:
>Audit-Trail:

From: sean <seburke@rent.com>
To: bug-followup@FreeBSD.org, rfg@tristatelogic.com
Cc:  
Subject: Re: kern/127335: [libc] fwrite(3) fails to generate error when
	applied to a read-only file
Date: Fri, 26 Sep 2008 18:57:33 -0700

 fwrite does set errno correctly. I modified the demo code
 to call perror before and after, like so:
 
 #include <stdio.h>
 
 int
 main (void)
 {
     perror ("pre-fwrite");
     fwrite ("Hello world!", 1, 12, stdin);
     perror ("post-fwrite");
 
     if (ferror (stdin))
         printf ("Error writing to stdin\n");
     else if (feof (stdin))
         printf ("EOF detected while writing to stdin\n");
     else
         printf ("This shouldn't happen!\n");
 
     return 0;
 }
 
 Which produces this output:
 
 pre-fwrite: Unknown error: 0
 post-fwrite: Bad file descriptor
 This shouldn't happen!
 
 The relevant code is in wsetup.c, where is tests where the
 'WRite' or 'Read-Write' flags are set, and fails if not:
 
         if ((fp->_flags & __SWR) == 0) {
                 if ((fp->_flags & __SRW) == 0) {
                         errno = EBADF;
                         return (EOF);
                 }
 
 I believe that the fix is to set the error flag on failure,
 like so:
 
          if ((fp->_flags & __SWR) == 0) {
                 if ((fp->_flags & __SRW) == 0) {
                         fp->_flags |= __SERR;
                         errno = EBADF;
                         return (EOF);
                 }
  
 
 
State-Changed-From-To: open->patched 
State-Changed-By: das 
State-Changed-When: Thu Jan 8 06:38:25 UTC 2009 
State-Changed-Why:  
Thanks for the report! Fixed in r186887. 


Responsible-Changed-From-To: freebsd-bugs->das 
Responsible-Changed-By: das 
Responsible-Changed-When: Thu Jan 8 06:38:25 UTC 2009 
Responsible-Changed-Why:  
take 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/127335: commit references a PR
Date: Thu,  8 Jan 2009 06:38:21 +0000 (UTC)

 Author: das
 Date: Thu Jan  8 06:38:06 2009
 New Revision: 186887
 URL: http://svn.freebsd.org/changeset/base/186887
 
 Log:
   Set the error indicator on an attempt to write to a read-only stream.
   
   PR:		127335
   MFC after:	2 weeks
 
 Modified:
   head/lib/libc/stdio/wsetup.c
 
 Modified: head/lib/libc/stdio/wsetup.c
 ==============================================================================
 --- head/lib/libc/stdio/wsetup.c	Thu Jan  8 06:12:03 2009	(r186886)
 +++ head/lib/libc/stdio/wsetup.c	Thu Jan  8 06:38:06 2009	(r186887)
 @@ -60,6 +60,7 @@ __swsetup(fp)
  	if ((fp->_flags & __SWR) == 0) {
  		if ((fp->_flags & __SRW) == 0) {
  			errno = EBADF;
 +			fp->_flags |= __SERR;
  			return (EOF);
  		}
  		if (fp->_flags & __SRD) {
 _______________________________________________
 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: bin/127335: commit references a PR
Date: Wed, 28 Jan 2009 05:07:36 +0000 (UTC)

 Author: das
 Date: Wed Jan 28 05:07:16 2009
 New Revision: 187810
 URL: http://svn.freebsd.org/changeset/base/187810
 
 Log:
   MFC r186887:
   
     Set the error indicator on an attempt to write to a read-only stream.
   
     PR:		127335
 
 Modified:
   stable/7/lib/libc/   (props changed)
   stable/7/lib/libc/stdio/wsetup.c
   stable/7/lib/libc/string/ffsll.c   (props changed)
   stable/7/lib/libc/string/flsll.c   (props changed)
 
 Modified: stable/7/lib/libc/stdio/wsetup.c
 ==============================================================================
 --- stable/7/lib/libc/stdio/wsetup.c	Wed Jan 28 04:37:27 2009	(r187809)
 +++ stable/7/lib/libc/stdio/wsetup.c	Wed Jan 28 05:07:16 2009	(r187810)
 @@ -60,6 +60,7 @@ __swsetup(fp)
  	if ((fp->_flags & __SWR) == 0) {
  		if ((fp->_flags & __SRW) == 0) {
  			errno = EBADF;
 +			fp->_flags |= __SERR;
  			return (EOF);
  		}
  		if (fp->_flags & __SRD) {
 _______________________________________________
 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: patched->closed 
State-Changed-By: das 
State-Changed-When: Wed Jan 28 05:19:02 UTC 2009 
State-Changed-Why:  
Merged to stable/7 in r187810 

http://www.freebsd.org/cgi/query-pr.cgi?pr=127335 
>Unformatted:
