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>