From gad@freefour.acs.rpi.edu  Sun Nov 19 15:51:32 2000
Return-Path: <gad@freefour.acs.rpi.edu>
Received: from freefour.acs.rpi.edu (freefour.acs.rpi.edu [128.113.24.91])
	by hub.freebsd.org (Postfix) with ESMTP
	id A1C4737B479; Sun, 19 Nov 2000 15:51:31 -0800 (PST)
Received: (from gad@localhost)
	by freefour.acs.rpi.edu (8.9.3/8.9.3) id SAA30775;
	Sun, 19 Nov 2000 18:51:26 -0500 (EST)
	(envelope-from gad)
Message-Id: <200011192351.SAA30775@freefour.acs.rpi.edu>
Date: Sun, 19 Nov 2000 18:51:26 -0500 (EST)
From: Garance A Drosehn <gad@freefour.acs.rpi.edu>
Reply-To: gad@eclipse.acs.rpi.edu
To: FreeBSD-gnats-submit@freebsd.org
Cc: gad@eclipse.acs.rpi.edu, gad@freebsd.org
Subject: [PATCH] fix for minor bug in libc/gen/getcap.c
X-Send-Pr-Version: 3.2

>Number:         22965
>Category:       bin
>Synopsis:       [MFC] [PATCH] fix for minor bug in libc/gen/getcap.c
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    gad
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Nov 19 16:00:01 PST 2000
>Closed-Date:    Mon Jan 15 15:10:07 PST 2001
>Last-Modified:  Mon Jan 15 15:11:01 PST 2001
>Originator:     Garance A Drosehn
>Release:        FreeBSD 3.2-RELEASE i386
>Organization:
RPI ; Troy NY
>Environment:

	While compiling FreeBSD's lpr/lpd for use on some other platforms,
	I ran into a fairly nasty bug on redhat linux.  As near as I can
	tell, the bug has existed in FreeBSD's 'getcap' for several years
	without it causing any known problems, but I do believe the code
	is wrong and should be fixed anyway.

	(while this send-pr is coming from a 3.2 system, the patch is
	for the source in freebsd-current, ie, 5.x as of Nov 2000)

>Description:

	You probably don't want to know what the problem is under linux...
	However, the problem comes down to code which does:
	    (void)fclose(pfp);
	    if (ferror(pfp)) {  ...do stuff... }
	According to the "single unix spec", the behavior of calling
	ANY "f-routine" on a closed stream is undefined.  I take it to
	mean that's a bad idea.  Certainly on linux it can trigger some
	major headaches.

	Also, I don't see what is to be gained by calling ferror in the
	above case.  My change is just to USE the return code from fclose,
	instead of throwing it away, and have error-processing key off
	that instead of ferror.

>How-To-Repeat:

	.na.

>Fix:
	
	Here is the patch I propose.  If no one objects to this, I can
	commit this patch sometime after thanksgiving.  Or I would be
	more than happy if someone else wants to claim ownership of
	getcap, and they generate their own patch for it...   :-)

	This also initializes global (static) variables to appropriate
	values, although that probably doesn't effect anything.

Index: getcap.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/gen/getcap.c,v
retrieving revision 1.12
diff -u -r1.12 getcap.c
--- getcap.c	2000/05/21 02:55:09	1.12
+++ getcap.c	2000/11/19 23:09:15
@@ -62,9 +62,9 @@
 #define TCERR	(char)1
 #define	SHADOW	(char)2
 
-static size_t	 topreclen;	/* toprec length */
-static char	*toprec;	/* Additional record specified by cgetset() */
-static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
+static size_t	 topreclen = 0;	/* toprec length */
+static char	*toprec = NULL;	/* Additional record specified by cgetset() */
+static int	 gottoprec = 0;	/* Flag indicating retrieval of toprecord */
 
 static int	cdbget __P((DB *, char **, char *));
 static int 	getent __P((char **, u_int *, char **, int, char *, int, char *));
@@ -619,9 +619,9 @@
 	return (cgetnext(buf, db_array));
 }
 
-static FILE *pfp;
-static int slash;
-static char **dbp;
+static FILE *pfp = NULL;
+static int slash = 0;		/* on if last line read-in ended with a '/' */
+static char **dbp = NULL;
 
 int
 cgetclose()
@@ -647,7 +647,7 @@
 	char **db_array;
 {
 	size_t len;
-	int status, i, done;
+	int done, fcloseres, i, status;
 	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
 	u_int dummy;
 
@@ -665,8 +665,9 @@
 		} else {
 			line = fgetln(pfp, &len);
 			if (line == NULL && pfp) {
-				(void)fclose(pfp);
-				if (ferror(pfp)) {
+				fcloseres = fclose(pfp);
+				pfp = NULL;
+				if (fcloseres != 0) {
 					(void)cgetclose();
 					return (-1);
 				} else {
@@ -724,8 +725,9 @@
 			} else { /* name field extends beyond the line */
 				line = fgetln(pfp, &len);
 				if (line == NULL && pfp) {
-					(void)fclose(pfp);
-					if (ferror(pfp)) {
+					fcloseres = fclose(pfp);
+					pfp = NULL;
+					if (fcloseres != 0) {
 						(void)cgetclose();
 						return (-1);
 					}




>Release-Note:
>Audit-Trail:

From: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
To: gad@eclipse.acs.rpi.edu
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: bin/22965: [PATCH] fix for minor bug in libc/gen/getcap.c
Date: Mon, 20 Nov 2000 15:16:35 -0500 (EST)

 -*- Mode: BDE -*-
 
 <<On Sun, 19 Nov 2000 18:51:26 -0500 (EST), Garance A Drosehn <gad@freefour.acs.rpi.edu> said:
 
 > -static size_t	 topreclen;	/* toprec length */
 > -static char	*toprec;	/* Additional record specified by cgetset() */
 > -static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
 > +static size_t	 topreclen = 0;	/* toprec length */
 > +static char	*toprec = NULL;	/* Additional record specified by cgetset() */
 > +static int	 gottoprec = 0;	/* Flag indicating retrieval of toprecord */
 
 These changes are erroneous, and have the sole effect of moving these
 variables from .bss, where they occupy only virtual space, to .data
 where they waste space on disk.
 
 > -				(void)fclose(pfp);
 > -				if (ferror(pfp)) {
 > +				fcloseres = fclose(pfp);
 > +				pfp = NULL;
 > +				if (fcloseres != 0) {
 
 This also appears to be the Wrong Thing.  The intent of the code seems
 to be to detect whether *reading* failed.  As implemented in FreeBSD,
 fclose() of a read-only file can never fail.  The correct emendation
 would be:
 	
 				haderror = ferror(pfp);
 				fclose(pfp);
 				if (haderror) {
 
 Even thus, this still could clobber errno (although fgetln() does not
 necessarily set it usefully); an even better version might be:
 
 	int savederrno, haderror;
 
 	savederrno = errno;
 	/* ... */
 				haderror = ferror(pfp);
 				if (haderror)
 					savederrno = errno;
 				fclose(pfp);
 				if (haderror) {
 					cgetclose();
 					errno = savederrno;
 					return (-1);
 				}
 
 -GAWollman
 
 --
 Garrett A. Wollman   | O Siem / We are all family / O Siem / We're all the same
 wollman@lcs.mit.edu  | O Siem / The fires of freedom 
 Opinions not those of| Dance in the burning flame
 MIT, LCS, CRS, or NSA|                     - Susan Aglukark and Chad Irschick
 

From: Garance A Drosehn <gad@eclipse.acs.rpi.edu>
To: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>
Cc: FreeBSD-gnats-submit@FreeBSD.ORG
Subject: Re: bin/22965: [PATCH] fix for minor bug in libc/gen/getcap.c
Date: Mon, 20 Nov 2000 21:19:44 -0500

 Here is an improved version of the patch.  Note that I have tested
 this on a private copy of 'getcap.c' that I use in a project of
 mine (which is compiled on multiple platforms), so I know it compiles
 and it works fine in that project.  However, I haven't figured out
 how to build a new libc on freebsd, so I can't say I've tested this
 patch installed into freebsd's libc...
 
 Index: getcap.c
 ===================================================================
 RCS file: /home/ncvs/src/lib/libc/gen/getcap.c,v
 retrieving revision 1.12
 diff -u -r1.12 getcap.c
 --- getcap.c	2000/05/21 02:55:09	1.12
 +++ getcap.c	2000/11/21 02:14:10
 @@ -647,7 +647,7 @@
  	char **db_array;
  {
  	size_t len;
 -	int status, i, done;
 +	int done, hadreaderr, i, savederrno, status;
  	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
  	u_int dummy;
 
 @@ -665,9 +665,14 @@
  		} else {
  			line = fgetln(pfp, &len);
  			if (line == NULL && pfp) {
 -				(void)fclose(pfp);
 -				if (ferror(pfp)) {
 -					(void)cgetclose();
 +				hadreaderr = ferror(pfp);
 +				if (hadreaderr)
 +					savederrno = errno;
 +				fclose(pfp);
 +				pfp = NULL;
 +				if (hadreaderr) {
 +					cgetclose();
 +					errno = savederrno;
  					return (-1);
  				} else {
  					if (*++dbp == NULL) {
 @@ -724,9 +729,18 @@
  			} else { /* name field extends beyond the line */
  				line = fgetln(pfp, &len);
  				if (line == NULL && pfp) {
 -					(void)fclose(pfp);
 -					if (ferror(pfp)) {
 -						(void)cgetclose();
 +					/* Name extends beyond the EOF! */
 +					hadreaderr = ferror(pfp);
 +					if (hadreaderr)
 +						savederrno = errno;
 +					fclose(pfp);
 +					pfp = NULL;
 +					if (hadreaderr) {
 +						cgetclose();
 +						errno = savederrno;
 +						return (-1);
 +					} else {
 +						cgetclose();
  						return (-1);
  					}
  				} else
 
 
 ---
 Garance Alistair Drosehn     =     gad@eclipse.acs.rpi.edu
 Senior Systems Programmer        (MIME & NeXTmail capable)
 Rensselaer Polytechnic Institute;           Troy NY    USA
 

From: Garance A Drosehn <gad@eclipse.acs.rpi.edu>
To: Garrett Wollman <wollman@khavrinen.lcs.mit.edu>,
	FreeBSD-gnats-submit@FreeBSD.ORG
Cc:  
Subject: Re: bin/22965: [PATCH] fix for minor bug in libc/gen/getcap.c
Date: Thu, 30 Nov 2000 00:12:05 -0500

 On Nov 20th, I (Garance) wrote:
 > Here is an improved version of the patch.  Note that I have tested
 > this on a private copy of 'getcap.c' that I use in a project of
 > mine [...].  However, I haven't figured out how to build a new
 > libc on freebsd, so I can't say I've tested this patch installed
 > into freebsd's libc...
 
 Well, back then I was trying to compile just libc without doing a
 buildworld, because I didn't have the time to do a buildworld last
 week (for various reasons I won't go into here...).  I couldn't
 figure out a good trick for that.
 
 I did do a buildworld Monday night, with this revised update
 included, and it compiled OK and I haven't had any problems with
 it.  Should I commit the change to current now?  Or should I, uh,
 do something else with it?  (what?)
 
 ---
 Garance Alistair Drosehn     =     gad@eclipse.acs.rpi.edu
 Senior Systems Programmer        (MIME & NeXTmail capable)
 Rensselaer Polytechnic Institute;           Troy NY    USA
 
State-Changed-From-To: open->suspended 
State-Changed-By: gad 
State-Changed-When: Fri Dec 1 16:12:12 PST 2000 
State-Changed-Why:  
Patch has been applied, awaiting MFC. 


Responsible-Changed-From-To: freebsd-bugs->gad 
Responsible-Changed-By: gad 
Responsible-Changed-When: Fri Dec 1 16:12:12 PST 2000 
Responsible-Changed-Why:  
I've written and committed the patch... 

http://www.freebsd.org/cgi/query-pr.cgi?pr=22965 
State-Changed-From-To: suspended->closed 
State-Changed-By: gad 
State-Changed-When: Mon Jan 15 15:10:07 PST 2001 
State-Changed-Why:  
The patch has been MFC'ed to RELENG_4 

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