Bug 22965

Summary: [MFC] [PATCH] fix for minor bug in libc/gen/getcap.c
Product: Base System Reporter: Garance A Drosehn <gad>
Component: binAssignee: Garance A Drosehn <gad>
Status: Closed FIXED    
Severity: Affects Only Me CC: gad
Priority: Normal    
Version: 3.2-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description Garance A Drosehn 2000-11-20 00:00:01 UTC
	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.

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.
How-To-Repeat: 
	.na.
Comment 1 Garrett A. Wollman 2000-11-20 20:16:35 UTC
-*- 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
Comment 2 gad 2000-11-21 02:19:44 UTC
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
Comment 3 gad 2000-11-30 05:12:05 UTC
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
Comment 4 Garance A Drosehn freebsd_committer freebsd_triage 2000-12-02 00:12:12 UTC
State Changed
From-To: open->suspended

Patch has been applied, awaiting MFC. 


Comment 5 Garance A Drosehn freebsd_committer freebsd_triage 2000-12-02 00:12:12 UTC
Responsible Changed
From-To: freebsd-bugs->gad

I've written and committed the patch...
Comment 6 Garance A Drosehn freebsd_committer freebsd_triage 2001-01-15 23:10:07 UTC
State Changed
From-To: suspended->closed

The patch has been MFC'ed to RELENG_4