Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 22 Apr 2011 00:32:17 +0000 (UTC)
From:      Xin LI <delphij@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r220934 - stable/7/lib/libutil
Message-ID:  <201104220032.p3M0WH3M018990@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: delphij
Date: Fri Apr 22 00:32:16 2011
New Revision: 220934
URL: http://svn.freebsd.org/changeset/base/220934

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/7/lib/libutil/humanize_number.c
Directory Properties:
  stable/7/lib/libutil/   (props changed)

Modified: stable/7/lib/libutil/humanize_number.c
==============================================================================
--- stable/7/lib/libutil/humanize_number.c	Fri Apr 22 00:31:07 2011	(r220933)
+++ stable/7/lib/libutil/humanize_number.c	Fri Apr 22 00:32:16 2011	(r220934)
@@ -50,11 +50,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;
 
@@ -62,6 +62,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;
@@ -93,13 +95,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)
@@ -116,7 +117,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;
 
 		/*
@@ -124,30 +125,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);
 }
+



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201104220032.p3M0WH3M018990>