From: James Jones Date: Thu, 16 Jun 2022 13:59:58 +0000 (-0500) Subject: Add case that exercises fr_size_to_str() bug and correct the bug. (#4567) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f12c1ae7787707acad0e5bf4bcba8cd3ee44109;p=thirdparty%2Ffreeradius-server.git Add case that exercises fr_size_to_str() bug and correct the bug. (#4567) Unfortunately it really needs to know the number of trailing zeroes in the decimal form as well as binary, which will slow things to an extent. --- diff --git a/src/lib/util/size.c b/src/lib/util/size.c index cf37861a60c..f4fed21499d 100644 --- a/src/lib/util/size.c +++ b/src/lib/util/size.c @@ -173,28 +173,22 @@ fr_slen_t fr_size_to_str(fr_sbuff_t *out, size_t in) }; fr_size_unit_t const *unit = &base10_units[0]; - uint8_t pos = fr_low_bit_pos(in); + int8_t pos2 = fr_low_bit_pos(in) - 1; + int8_t pos10; + size_t temp; /* - * Fast path - Won't be divisible by 1000 + * Fast path - Won't be divisible by a power of 1000 or a power of 1024 */ - if (pos < 3) { - goto done; - } else if ((in % 1000) == 0) { - /* - * For powers of 10, exp equals the - * number of contiguous zero low order bits. - */ - unit = &base10_units[(pos - 1) / 3]; + if (pos2 < 3) goto done; /* - * Fast path - Won't be divisible by 1024 + * Get a count of trailing decimal zeroes. */ - } else if (pos < 10) { - goto done; - } else if ((in % 1024) == 0) { - unit = &base2_units[(pos - 1) / 10]; - } + for (temp = in, pos10 = 0; temp && temp % 10 == 0; pos10++) temp /= 10; + + if (pos10 >= 3) unit = &base10_units[(pos10) / 3]; + else if (pos2 >= 10) unit = &base2_units[pos2 / 10]; done: return fr_sbuff_in_sprintf(&our_out, "%zu%s", in / unit->mul, unit->suffix); diff --git a/src/lib/util/size_tests.c b/src/lib/util/size_tests.c index 5f64da4ff2f..96e5065cf9b 100644 --- a/src/lib/util/size_tests.c +++ b/src/lib/util/size_tests.c @@ -294,6 +294,9 @@ static void test_size_print_base10(void) TEST_CHECK_SLEN(fr_size_to_str(test_out(buff), (size_t)1000 * 1000), 3); TEST_CHECK_STRCMP(buff, "1MB"); + TEST_CHECK_SLEN(fr_size_to_str(test_out(buff), (size_t)1000 * 1000 + 64000), 6); + TEST_CHECK_STRCMP(buff, "1064KB"); + TEST_CHECK_SLEN(fr_size_to_str(test_out(buff), (size_t)1000 * 1000 * 1000), 3); TEST_CHECK_STRCMP(buff, "1GB");