stat: increase the size of base to avoid overflow
authorRichard Liu <liuhanche@pku.edu.cn>
Wed, 23 Aug 2017 10:49:58 +0000 (18:49 +0800)
committerRichard Liu <liuhanche@pku.edu.cn>
Wed, 23 Aug 2017 10:49:58 +0000 (18:49 +0800)
plat_idx_to_val() in stat.c has a variable base that is defined as an
unsigned int but it was designed to fit old settings where
FIO_IO_U_PLAT_GROUP_NR = 19.
With the alteration from usec to nsec in commit
d6bb626ef37d3905221ade2887b422717a07af09(nanosecond: update completion
latency recording and normal, json output to use nanoseconds)
FIO_IO_U_PLAT_GROUP_NR is now 29 and the range of latency changed from
uint32_t to uint64_t. This means in plat_idx_to_val(), variable base
can easily exceed a 32-bit range and overflow after error_bits reaches 26.

Eg.
Group MSB #discarded range of #buckets
error_bits value
27 32 26 [42949672968589934591]     64
base = 1 << (error_bits + FIO_IO_U_PLAT_BITS);
(1 << 32) will overflow
if change to:
base = ((unsigned long long) 1) << (error_bits + FIO_IO_U_PLAT_BITS);
base itself will still overflow
so base should be unsigned long long

stat.c

diff --git a/stat.c b/stat.c
index 4aa9cb8f3d80797fe59deec69dfdcadb29968530..91c74abef420f8fb0e8453e5a9be1fecff1e6f56 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -100,7 +100,8 @@ static unsigned int plat_val_to_idx(unsigned long long val)
  */
 static unsigned long long plat_idx_to_val(unsigned int idx)
 {
-       unsigned int error_bits, k, base;
+       unsigned int error_bits;
+       unsigned long long k, base;
 
        assert(idx < FIO_IO_U_PLAT_NR);
 
@@ -111,7 +112,7 @@ static unsigned long long plat_idx_to_val(unsigned int idx)
 
        /* Find the group and compute the minimum value of that group */
        error_bits = (idx >> FIO_IO_U_PLAT_BITS) - 1;
-       base = 1 << (error_bits + FIO_IO_U_PLAT_BITS);
+       base = ((unsigned long long) 1) << (error_bits + FIO_IO_U_PLAT_BITS);
 
        /* Find its bucket number of the group */
        k = idx % FIO_IO_U_PLAT_VAL;