summaryrefslogtreecommitdiffstats
path: root/lib/libutil
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2011-03-23 22:08:01 +0000
committerdelphij <delphij@FreeBSD.org>2011-03-23 22:08:01 +0000
commit0ad5e9d9f01929efc397a27954f0991b4daac53e (patch)
treef7277fe9ba7302c849010cbfe0797d26a5561479 /lib/libutil
parenteb3b2f6984e44178fe44659cc64118f0000434c3 (diff)
downloadFreeBSD-src-0ad5e9d9f01929efc397a27954f0991b4daac53e.zip
FreeBSD-src-0ad5e9d9f01929efc397a27954f0991b4daac53e.tar.gz
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
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 de98587..75bcb46 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);
}
+
OpenPOWER on IntegriCloud