aboutsummaryrefslogtreecommitdiff
path: root/lib/libutil
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2011-03-23 22:08:01 +0000
committerXin LI <delphij@FreeBSD.org>2011-03-23 22:08:01 +0000
commita699e14f45bce95043f32955578d3190f9f90ce0 (patch)
treef7277fe9ba7302c849010cbfe0797d26a5561479 /lib/libutil
parent784ae1fdd1a31b442efdb37abcc45373911e7576 (diff)
downloadsrc-a699e14f45bce95043f32955578d3190f9f90ce0.tar.gz
src-a699e14f45bce95043f32955578d3190f9f90ce0.zip
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 MFC after: 1 month
Notes
Notes: svn path=/head/; revision=219939
Diffstat (limited to 'lib/libutil')
-rw-r--r--lib/libutil/humanize_number.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/lib/libutil/humanize_number.c b/lib/libutil/humanize_number.c
index de985870ff37..75bcb460b5d6 100644
--- a/lib/libutil/humanize_number.c
+++ b/lib/libutil/humanize_number.c
@@ -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, int64_t bytes,
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, int64_t bytes,
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, int64_t bytes,
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, int64_t bytes,
* 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);
}
+