svn commit: r220933 - stable/8/lib/libutil

Xin LI delphij at FreeBSD.org
Fri Apr 22 00:31:07 UTC 2011


Author: delphij
Date: Fri Apr 22 00:31:07 2011
New Revision: 220933
URL: http://svn.freebsd.org/changeset/base/220933

Log:
  MFC r219939:
  
  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

Modified:
  stable/8/lib/libutil/humanize_number.c
Directory Properties:
  stable/8/lib/libutil/   (props changed)

Modified: stable/8/lib/libutil/humanize_number.c
==============================================================================
--- stable/8/lib/libutil/humanize_number.c	Thu Apr 21 23:06:00 2011	(r220932)
+++ stable/8/lib/libutil/humanize_number.c	Fri Apr 22 00:31:07 2011	(r220933)
@@ -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-stable-8 mailing list