Bug 12959

Summary: /usr/bin/wc overflows at 2^32
Product: Base System Reporter: Nicholas Barnes <nb>
Component: binAssignee: Sheldon Hearn <sheldonh>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 2.2.8-RELEASE   
Hardware: Any   
OS: Any   

Description Nicholas Barnes 1999-08-04 12:50:00 UTC
	/usr/bin/wc overflows at 2^32, so passing it a big file
        (or stream) gives bogus results.

Fix: 

I'm sure a simple hack in the wc sources could make the
        counters 64-bit.
How-To-Repeat: 
	$ dd if=/dev/zero bs=1m count=4097 | wc
        4097+0 records in
        4097+0 records out
        4296015872 bytes transferred in 614.248991 secs (6993932 bytes/sec)
         1048576
        $
Comment 1 Sheldon Hearn freebsd_committer freebsd_triage 1999-08-04 14:52:38 UTC
State Changed
From-To: open->feedback

The internal counters are already u_long. Presumeably, you want them to  
be quad_t? Could you try it and see what the performance hit is like on  
an Intel machine? 


Comment 2 Sheldon Hearn freebsd_committer freebsd_triage 1999-08-04 14:52:38 UTC
Responsible Changed
From-To: freebsd-bugs->sheldonh

I'll take this one. 

Comment 3 Sheldon Hearn 1999-08-04 15:30:21 UTC
I've tested the following diff for performance and see no noticeable
loss. I will say that I think it's perverse to demand the use of a
quad_int to store the number of lines in a file and a little less
perverse to do the same for the number of words, but since it doesn't
seem to cost us much, it's probably okay.

Would you like to test this? Paticularly, I haven't checked that the
printf()'s all do the right thing in all cases.

Ciao,
Sheldon.

Index: wc.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/wc/wc.c,v
retrieving revision 1.8
diff -u -d -r1.8 wc.c
--- wc.c	1997/08/25 06:44:59	1.8
+++ wc.c	1999/08/04 14:24:53
@@ -58,7 +58,7 @@
 #include <string.h>
 #include <unistd.h>
 
-u_long tlinect, twordct, tcharct;
+quad_t tlinect, twordct, tcharct;
 int doline, doword, dochar;
 
 int cnt __P((char *));
@@ -70,7 +70,7 @@
 	char *argv[];
 {
 	register int ch;
-	int errors, total;
+	quad_t errors, total;
 
 	(void) setlocale(LC_CTYPE, "");
 
@@ -114,11 +114,11 @@
 
 	if (total > 1) {
 		if (doline)
-			(void)printf(" %7ld", tlinect);
+			(void)printf(" %7qu", tlinect);
 		if (doword)
-			(void)printf(" %7ld", twordct);
+			(void)printf(" %7qu", twordct);
 		if (dochar)
-			(void)printf(" %7ld", tcharct);
+			(void)printf(" %7qu", tcharct);
 		(void)printf(" total\n");
 	}
 	exit(errors == 0 ? 0 : 1);
@@ -131,7 +131,7 @@
 	register u_char *p, ch;
 	register short gotsp;
 	register int len;
-	register u_long linect, wordct, charct;
+	register quad_t linect, wordct, charct;
 	struct stat sb;
 	int fd;
 	u_char buf[MAXBSIZE];
@@ -165,10 +165,10 @@
 						++linect;
 			}
 			tlinect += linect;
-			(void)printf(" %7lu", linect);
+			(void)printf(" %7qu", linect);
 			if (dochar) {
 				tcharct += charct;
-				(void)printf(" %7lu", charct);
+				(void)printf(" %7qu", charct);
 			}
 			(void)close(fd);
 			return (0);
@@ -219,15 +219,15 @@
 	}
 	if (doline) {
 		tlinect += linect;
-		(void)printf(" %7lu", linect);
+		(void)printf(" %7qu", linect);
 	}
 	if (doword) {
 		twordct += wordct;
-		(void)printf(" %7lu", wordct);
+		(void)printf(" %7qu", wordct);
 	}
 	if (dochar) {
 		tcharct += charct;
-		(void)printf(" %7lu", charct);
+		(void)printf(" %7qu", charct);
 	}
 	(void)close(fd);
 	return (0);
Comment 4 Sheldon Hearn 1999-08-04 15:36:58 UTC
Nick pointed me at the NetBSD changes, which highlight a glaring error
in my 2 minute noodles diff (the printf conversion specifiers).

Ciao,
Sheldon.

Index: wc.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/wc/wc.c,v
retrieving revision 1.8
diff -u -d -r1.8 wc.c
--- wc.c	1997/08/25 06:44:59	1.8
+++ wc.c	1999/08/04 14:24:53
@@ -58,7 +58,7 @@
 #include <string.h>
 #include <unistd.h>
 
-u_long tlinect, twordct, tcharct;
+quad_t tlinect, twordct, tcharct;
 int doline, doword, dochar;
 
 int cnt __P((char *));
@@ -70,7 +70,7 @@
 	char *argv[];
 {
 	register int ch;
-	int errors, total;
+	quad_t errors, total;
 
 	(void) setlocale(LC_CTYPE, "");
 
@@ -114,11 +114,11 @@
 
 	if (total > 1) {
 		if (doline)
-			(void)printf(" %7ld", tlinect);
+			(void)printf(" %7qd", tlinect);
 		if (doword)
-			(void)printf(" %7ld", twordct);
+			(void)printf(" %7qd", twordct);
 		if (dochar)
-			(void)printf(" %7ld", tcharct);
+			(void)printf(" %7qd", tcharct);
 		(void)printf(" total\n");
 	}
 	exit(errors == 0 ? 0 : 1);
@@ -131,7 +131,7 @@
 	register u_char *p, ch;
 	register short gotsp;
 	register int len;
-	register u_long linect, wordct, charct;
+	register quad_t linect, wordct, charct;
 	struct stat sb;
 	int fd;
 	u_char buf[MAXBSIZE];
@@ -165,10 +165,10 @@
 						++linect;
 			}
 			tlinect += linect;
-			(void)printf(" %7lu", linect);
+			(void)printf(" %7qd", linect);
 			if (dochar) {
 				tcharct += charct;
-				(void)printf(" %7lu", charct);
+				(void)printf(" %7qd", charct);
 			}
 			(void)close(fd);
 			return (0);
@@ -219,15 +219,15 @@
 	}
 	if (doline) {
 		tlinect += linect;
-		(void)printf(" %7lu", linect);
+		(void)printf(" %7qd", linect);
 	}
 	if (doword) {
 		twordct += wordct;
-		(void)printf(" %7lu", wordct);
+		(void)printf(" %7qd", wordct);
 	}
 	if (dochar) {
 		tcharct += charct;
-		(void)printf(" %7lu", charct);
+		(void)printf(" %7qd", charct);
 	}
 	(void)close(fd);
 	return (0);
Comment 5 Sheldon Hearn 1999-08-04 15:39:24 UTC
*sigh*

Let me slow down, have a cup of coffee and then merge NetBSD's changes
properly -- NetBSD is a lot better at getting past bde than OpenBSD.

Ciao,
Sheldon.
Comment 6 Sheldon Hearn freebsd_committer freebsd_triage 1999-08-06 15:41:27 UTC
State Changed
From-To: feedback->closed

Fixed in rev 1.9 of wc.c .