bin/146205: df(1) fails to display total space on a 100PB filesystem correctly

Xin LI delphij at delphij.net
Mon Mar 21 22:21:57 UTC 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

I think this is with the *= 100 clause.  100PB would use up to bit 57,
and the *= 100 would consume an additional >5 bits, causing an integer
overflow here.

Fixing this requires an overhaul on the humanize_number(3) function I
think.  I think, we would have to split the result into quotient and
reminder to deal with this.

I have put together the attached patch but there *MIGHT* be some
regressions which I didn't have time yet to write some test cases to
verify that.  Comments/test cases welcome.

Cheers,
- -- 
Xin LI <delphij at delphij.net>	http://www.delphij.net/
FreeBSD - The Power to Serve!	       Live free or die
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (FreeBSD)

iQEcBAEBCAAGBQJNh892AAoJEATO+BI/yjfBblYH/1ujN1ZD79Z1YKjSN+IgdZTq
skSeB6cUdJr93LSxSnhojr7drOM4kO/m1tchsZtnYJxIK/rbU7e9vVhLo7VJUKU5
6jJ3sw6alOBFsi6eYRSb1LQRRAznMZqOC5Sg/cnbPuMLC5JDPT/P6wdKvEpebsst
ffodPWHS3J3o0pbzt2C3IUlBEUby4wy5ZLerntT5SheuBc8HijCBk6XcTW1/7Iw8
bJxfJEKyp+ctvhoh4qINdLHkEnTEdLKm3Dqt/VlrbMh4JkHUbcql7diZ2LP4+5ce
vv9FL4alEc4lV/hX2HDuvhNKCC4vWx7iCeed0pwc8ui0KLB2UsG1Fj/E6saMYOE=
=qGsE
-----END PGP SIGNATURE-----
-------------- next part --------------
Index: humanize_number.c
===================================================================
--- humanize_number.c	(revision 219842)
+++ humanize_number.c	(working copy)
@@ -47,8 +47,9 @@
     const char *suffix, int scale, int flags)
 {
 	const char *prefixes, *sep;
-	int	b, i, r, maxscale, s1, s2, sign;
+	int	i, r, maxscale, s1, s2, sign;
 	int64_t	divisor, max;
+	int64_t quotient = bytes, reminder = 0;
 	size_t	baselen;
 
 	assert(buf != NULL);
@@ -88,11 +89,10 @@
 		buf[0] = '\0';
 	if (bytes < 0) {
 		sign = -1;
-		bytes *= -100;
+		quotient = -quotient;
 		baselen = 3;		/* sign, digit, prefix */
 	} else {
 		sign = 1;
-		bytes *= 100;
 		baselen = 2;		/* digit, prefix */
 	}
 	if (flags & HN_NOSPACE)
@@ -109,7 +109,7 @@
 
 	if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
 		/* See if there is additional columns can be used. */
-		for (max = 100, i = len - baselen; i-- > 0;)
+		for (max = 1, i = len - baselen; i-- > 0;)
 			max *= 10;
 
 		/*
@@ -117,29 +117,33 @@
 		 * If there will be an overflow by the rounding below,
 		 * divide once more.
 		 */
-		for (i = 0; bytes >= max - 50 && i < maxscale; i++)
-			bytes /= divisor;
+		for (i = 0; quotient > max && i < maxscale; i++) {
+			reminder = quotient % divisor;
+			quotient /= divisor;
+		}
 
 		if (scale & HN_GETSCALE)
 			return (i);
-	} else
-		for (i = 0; i < scale && i < maxscale; i++)
-			bytes /= divisor;
+	} else {
+		for (i = 0; i < scale && i < maxscale; i++) {
+			reminder = quotient % divisor;
+			quotient /= divisor;
+		}
+	}
 
 	/* If a value <= 9.9 after rounding and ... */
-	if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+	if (quotient == 0 && reminder < 995 && i > 0 && flags & HN_DECIMAL) {
 		/* baselen + \0 + .N */
 		if (len < baselen + 1 + 2)
 			return (-1);
-		b = ((int)bytes + 5) / 10;
-		s1 = b / 10;
-		s2 = b % 10;
+		s1 = (int)quotient + (((int)reminder + 5) / 100);
+		s2 = (((int)reminder + 5) / 10) % 10;
 		r = snprintf(buf, len, "%d%s%d%s%s%s",
 		    sign * s1, localeconv()->decimal_point, s2,
 		    sep, SCALE2PREFIX(i), suffix);
 	} else
 		r = snprintf(buf, len, "%" PRId64 "%s%s%s",
-		    sign * ((bytes + 50) / 100),
+		    sign * (quotient + (reminder + 5) / 100),
 		    sep, SCALE2PREFIX(i), suffix);
 
 	return (r);


More information about the freebsd-bugs mailing list