svn commit: r219939 - head/lib/libutil
Alexander Best
arundel at freebsd.org
Thu Mar 24 00:29:56 UTC 2011
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
-------------- next part --------------
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.
More information about the svn-src-head
mailing list