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
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.
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to