Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Mar 2011 00:29:55 +0000
From:      Alexander Best <arundel@freebsd.org>
To:        Xin LI <delphij@FreeBSD.org>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, src-committers@freebsd.org
Subject:   Re: svn commit: r219939 - head/lib/libutil
Message-ID:  <20110324002955.GA25594@freebsd.org>
In-Reply-To: <201103232208.p2NM818d008805@svn.freebsd.org>
References:  <201103232208.p2NM818d008805@svn.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--HlL+5n6rz5pIUxbD
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Wed Mar 23 11, Xin LI wrote:
> 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).

i think we should also change the humanize_number(3) manual page accordingly.
here's a rough draft (date not bumped, yet).

>   
>   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);
>  }
> +

-- 
a13x

--HlL+5n6rz5pIUxbD
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="humanize_number.3.diff"

diff --git a/lib/libutil/humanize_number.3 b/lib/libutil/humanize_number.3
index 82925ba..8741e23 100644
--- a/lib/libutil/humanize_number.3
+++ b/lib/libutil/humanize_number.3
@@ -40,14 +40,14 @@
 .In libutil.h
 .Ft int
 .Fo humanize_number
-.Fa "char *buf" "size_t len" "int64_t number" "const char *suffix"
+.Fa "char *buf" "size_t len" "int64_t quotient" "const char *suffix"
 .Fa "int scale" "int flags"
 .Fc
 .Sh DESCRIPTION
 The
 .Fn humanize_number
 function formats the signed 64-bit quantity given in
-.Fa number
+.Fa quotient
 into
 .Fa buf .
 A space and then
@@ -64,7 +64,7 @@ If the formatted number (including
 would be too long to fit into
 .Fa buf ,
 then divide
-.Fa number
+.Fa quotient
 by 1024 until it will.
 In this case, prefix
 .Fa suffix
@@ -106,7 +106,7 @@ The following flags may be passed in
 Format the buffer using the lowest multiplier possible.
 .It Dv HN_GETSCALE
 Return the prefix index number (the number of times
-.Fa number
+.Fa quotient
 must be divided to fit) instead of formatting it to the buffer.
 .El
 .Pp
@@ -117,7 +117,7 @@ The following flags may be passed in
 If the final result is less than 10, display it using one digit.
 .It Dv HN_NOSPACE
 Do not put a space between
-.Fa number
+.Fa quotient
 and the prefix.
 .It Dv HN_B
 Use
@@ -125,7 +125,7 @@ Use
 (bytes) as prefix if the original result does not have a prefix.
 .It Dv HN_DIVISOR_1000
 Divide
-.Fa number
+.Fa quotient
 with 1000 instead of 1024.
 .El
 .Sh RETURN VALUES
@@ -148,3 +148,7 @@ function first appeared in
 .Nx 2.0
 and then in
 .Fx 5.3 .
+.Sh CAVEATS
+A
+.Fa quotient
+argument greater than or equal to 16 Exabyte cannot be humanized.

--HlL+5n6rz5pIUxbD--



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