svn commit: r219939 - head/lib/libutil

Xin LI delphij at FreeBSD.org
Wed Mar 23 22:08:01 UTC 2011


Author: delphij
Date: Wed Mar 23 22:08:01 2011
New Revision: 219939
URL: http://svn.freebsd.org/changeset/base/219939

Log:
  humanize_number(3) multiply the input number by 100, which could cause an
  integer overflow when the input is very large (for example, 100 Pi would
  become about 10 Ei which exceeded signed int64_t).
  
  Solve this issue by splitting the division into two parts and avoid the
  multiplication.
  
  PR:		bin/146205
  Reviewed by:	arundel
  MFC after:	1 month

Modified:
  head/lib/libutil/humanize_number.c

Modified: head/lib/libutil/humanize_number.c
==============================================================================
--- head/lib/libutil/humanize_number.c	Wed Mar 23 22:06:09 2011	(r219938)
+++ head/lib/libutil/humanize_number.c	Wed Mar 23 22:08:01 2011	(r219939)
@@ -43,11 +43,11 @@ __FBSDID("$FreeBSD$");
 #include <libutil.h>
 
 int
-humanize_number(char *buf, size_t len, int64_t bytes,
+humanize_number(char *buf, size_t len, int64_t quotient,
     const char *suffix, int scale, int flags)
 {
 	const char *prefixes, *sep;
-	int	b, i, r, maxscale, s1, s2, sign;
+	int	i, r, remainder, maxscale, s1, s2, sign;
 	int64_t	divisor, max;
 	size_t	baselen;
 
@@ -55,6 +55,8 @@ humanize_number(char *buf, size_t len, i
 	assert(suffix != NULL);
 	assert(scale >= 0);
 
+	remainder = 0;
+
 	if (flags & HN_DIVISOR_1000) {
 		/* SI for decimal multiplies */
 		divisor = 1000;
@@ -86,13 +88,12 @@ humanize_number(char *buf, size_t len, i
 
 	if (len > 0)
 		buf[0] = '\0';
-	if (bytes < 0) {
+	if (quotient < 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 +110,7 @@ humanize_number(char *buf, size_t len, i
 
 	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,30 +118,37 @@ humanize_number(char *buf, size_t len, i
 		 * 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 || (quotient == max - 1 && remainder >= 950)) &&
+		    i < maxscale; i++) {
+			remainder = 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++) {
+			remainder = quotient % divisor;
+			quotient /= divisor;
+		}
+	}
 
 	/* If a value <= 9.9 after rounding and ... */
-	if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+	if (quotient <= 9 && remainder < 950 && 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 + ((remainder + 50) / 1000);
+		s2 = ((remainder + 50) / 100) % 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 + (remainder + 50) / 1000),
 		    sep, SCALE2PREFIX(i), suffix);
 
 	return (r);
 }
+


More information about the svn-src-head mailing list