fio: Fix (unsigned) integer overflow issues
authorSitsofe Wheeler <sitsofe@yahoo.com>
Sun, 20 Nov 2016 20:55:06 +0000 (20:55 +0000)
committerSitsofe Wheeler <sitsofe@yahoo.com>
Sun, 27 Nov 2016 21:30:15 +0000 (21:30 +0000)
This patch tries to address issues found when compiling fio with clang's
undefined behaviour sanitizer on 32 bit Linux. While this generated many
false positives it did identify a number of subtle issues when
rates/amounts/time calculations went above 32 bit values.

The following job was used:
[global]
time_based
runtime=180m
bs=256k
rw=randrw
norandommap
rate=512M
ioengine=null
direct=1
iodepth=8
thread
numjobs=10
ramp_time=20m

[null]
size=1P

It should fix https://github.com/axboe/fio/issues/270 because various 32
bit ETA variables were overflowing due to the microsecond arithmetic
being done on them (even on 64 bit systems).

This patch should also fix https://github.com/axboe/fio/issues/194 and
https://github.com/axboe/fio/issues/266 because 64 bit Windows is a
LLP64 platform so ints and longs still default to 32 bits.

Signed-off-by: Sitsofe Wheeler <sitsofe@yahoo.com>
backend.c
cconv.c
client.c
eta.c
fio.h
gettime.c
io_u.c
mutex.c
server.c
stat.h
thread_options.h

index 60cea3c682a8dc8c5c95a40f2a438ff06a054fbd..8616fc2a7b2df84b0b00509ad14f96fe4eea29d8 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1864,8 +1864,8 @@ static void dump_td_info(struct thread_data *td)
 /*
  * Run over the job map and reap the threads that have exited, if any.
  */
 /*
  * Run over the job map and reap the threads that have exited, if any.
  */
-static void reap_threads(unsigned int *nr_running, unsigned int *t_rate,
-                        unsigned int *m_rate)
+static void reap_threads(unsigned int *nr_running, uint64_t *t_rate,
+                        uint64_t *m_rate)
 {
        struct thread_data *td;
        unsigned int cputhreads, realthreads, pending;
 {
        struct thread_data *td;
        unsigned int cputhreads, realthreads, pending;
@@ -2103,7 +2103,8 @@ static bool waitee_running(struct thread_data *me)
 static void run_threads(struct sk_out *sk_out)
 {
        struct thread_data *td;
 static void run_threads(struct sk_out *sk_out)
 {
        struct thread_data *td;
-       unsigned int i, todo, nr_running, m_rate, t_rate, nr_started;
+       unsigned int i, todo, nr_running, nr_started;
+       uint64_t m_rate, t_rate;
        uint64_t spent;
 
        if (fio_gtod_offload && fio_start_gtod_thread())
        uint64_t spent;
 
        if (fio_gtod_offload && fio_start_gtod_thread())
diff --git a/cconv.c b/cconv.c
index 6e0f6094fa7d8d658f274ce4cf885f183cdb96f0..0032cc04ae06ba8cf14be26a82822db0d1ef10c7 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -131,8 +131,8 @@ void convert_thread_options_to_cpu(struct thread_options *o,
                }
 
                o->rwmix[i] = le32_to_cpu(top->rwmix[i]);
                }
 
                o->rwmix[i] = le32_to_cpu(top->rwmix[i]);
-               o->rate[i] = le32_to_cpu(top->rate[i]);
-               o->ratemin[i] = le32_to_cpu(top->ratemin[i]);
+               o->rate[i] = le64_to_cpu(top->rate[i]);
+               o->ratemin[i] = le64_to_cpu(top->ratemin[i]);
                o->rate_iops[i] = le32_to_cpu(top->rate_iops[i]);
                o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]);
 
                o->rate_iops[i] = le32_to_cpu(top->rate_iops[i]);
                o->rate_iops_min[i] = le32_to_cpu(top->rate_iops_min[i]);
 
@@ -505,8 +505,8 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
                }
 
                top->rwmix[i] = cpu_to_le32(o->rwmix[i]);
                }
 
                top->rwmix[i] = cpu_to_le32(o->rwmix[i]);
-               top->rate[i] = cpu_to_le32(o->rate[i]);
-               top->ratemin[i] = cpu_to_le32(o->ratemin[i]);
+               top->rate[i] = cpu_to_le64(o->rate[i]);
+               top->ratemin[i] = cpu_to_le64(o->ratemin[i]);
                top->rate_iops[i] = cpu_to_le32(o->rate_iops[i]);
                top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]);
 
                top->rate_iops[i] = cpu_to_le32(o->rate_iops[i]);
                top->rate_iops_min[i] = cpu_to_le32(o->rate_iops_min[i]);
 
index 9698122da8f522786b14482dd61e8771c8d2368c..9a8cf17e0619585d230186555a1d703096553b36 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1135,11 +1135,11 @@ static void convert_jobs_eta(struct jobs_eta *je)
        je->files_open          = le32_to_cpu(je->files_open);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
        je->files_open          = le32_to_cpu(je->files_open);
 
        for (i = 0; i < DDIR_RWDIR_CNT; i++) {
-               je->m_rate[i]   = le32_to_cpu(je->m_rate[i]);
-               je->t_rate[i]   = le32_to_cpu(je->t_rate[i]);
+               je->m_rate[i]   = le64_to_cpu(je->m_rate[i]);
+               je->t_rate[i]   = le64_to_cpu(je->t_rate[i]);
                je->m_iops[i]   = le32_to_cpu(je->m_iops[i]);
                je->t_iops[i]   = le32_to_cpu(je->t_iops[i]);
                je->m_iops[i]   = le32_to_cpu(je->m_iops[i]);
                je->t_iops[i]   = le32_to_cpu(je->t_iops[i]);
-               je->rate[i]     = le32_to_cpu(je->rate[i]);
+               je->rate[i]     = le64_to_cpu(je->rate[i]);
                je->iops[i]     = le32_to_cpu(je->iops[i]);
        }
 
                je->iops[i]     = le32_to_cpu(je->iops[i]);
        }
 
diff --git a/eta.c b/eta.c
index 3c1aeeee98cbd0cb0d3dcbe35f7c1287d7a39450..c2c9d4e8fb79bb9cc74abe0cad0294f30b426c5e 100644 (file)
--- a/eta.c
+++ b/eta.c
@@ -235,7 +235,7 @@ static unsigned long thread_eta(struct thread_data *td)
                        || td->runstate == TD_SETTING_UP
                        || td->runstate == TD_RAMP
                        || td->runstate == TD_PRE_READING) {
                        || td->runstate == TD_SETTING_UP
                        || td->runstate == TD_RAMP
                        || td->runstate == TD_PRE_READING) {
-               int t_eta = 0, r_eta = 0;
+               int64_t t_eta = 0, r_eta = 0;
                unsigned long long rate_bytes;
 
                /*
                unsigned long long rate_bytes;
 
                /*
@@ -285,7 +285,7 @@ static unsigned long thread_eta(struct thread_data *td)
 
 static void calc_rate(int unified_rw_rep, unsigned long mtime,
                      unsigned long long *io_bytes,
 
 static void calc_rate(int unified_rw_rep, unsigned long mtime,
                      unsigned long long *io_bytes,
-                     unsigned long long *prev_io_bytes, unsigned int *rate)
+                     unsigned long long *prev_io_bytes, uint64_t *rate)
 {
        int i;
 
 {
        int i;
 
@@ -341,7 +341,7 @@ bool calc_thread_status(struct jobs_eta *je, int force)
 {
        struct thread_data *td;
        int i, unified_rw_rep;
 {
        struct thread_data *td;
        int i, unified_rw_rep;
-       unsigned long rate_time, disp_time, bw_avg_time, *eta_secs;
+       uint64_t rate_time, disp_time, bw_avg_time, *eta_secs;
        unsigned long long io_bytes[DDIR_RWDIR_CNT];
        unsigned long long io_iops[DDIR_RWDIR_CNT];
        struct timeval now;
        unsigned long long io_bytes[DDIR_RWDIR_CNT];
        unsigned long long io_iops[DDIR_RWDIR_CNT];
        struct timeval now;
@@ -367,8 +367,8 @@ bool calc_thread_status(struct jobs_eta *je, int force)
        if (!ddir_rw_sum(disp_io_bytes))
                fill_start_time(&disp_prev_time);
 
        if (!ddir_rw_sum(disp_io_bytes))
                fill_start_time(&disp_prev_time);
 
-       eta_secs = malloc(thread_number * sizeof(unsigned long));
-       memset(eta_secs, 0, thread_number * sizeof(unsigned long));
+       eta_secs = malloc(thread_number * sizeof(uint64_t));
+       memset(eta_secs, 0, thread_number * sizeof(uint64_t));
 
        je->elapsed_sec = (mtime_since_genesis() + 999) / 1000;
 
 
        je->elapsed_sec = (mtime_since_genesis() + 999) / 1000;
 
diff --git a/fio.h b/fio.h
index 74c1b306af26d7d8e850664f81af2f94d48f3c1c..7e327887bfcc3bedc16110becb14b0a8c4dd02fd 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -269,10 +269,10 @@ struct thread_data {
         * Rate state
         */
        uint64_t rate_bps[DDIR_RWDIR_CNT];
         * Rate state
         */
        uint64_t rate_bps[DDIR_RWDIR_CNT];
-       unsigned long rate_next_io_time[DDIR_RWDIR_CNT];
+       uint64_t rate_next_io_time[DDIR_RWDIR_CNT];
        unsigned long rate_bytes[DDIR_RWDIR_CNT];
        unsigned long rate_blocks[DDIR_RWDIR_CNT];
        unsigned long rate_bytes[DDIR_RWDIR_CNT];
        unsigned long rate_blocks[DDIR_RWDIR_CNT];
-       unsigned long rate_io_issue_bytes[DDIR_RWDIR_CNT];
+       unsigned long long rate_io_issue_bytes[DDIR_RWDIR_CNT];
        struct timeval lastrate[DDIR_RWDIR_CNT];
        int64_t last_usec;
        struct frand_state poisson_state;
        struct timeval lastrate[DDIR_RWDIR_CNT];
        int64_t last_usec;
        struct frand_state poisson_state;
index 73b48b0463a0efb00144bae289d6de377b197dbf..85ba7cba8954aa3a70ae5e1faf9a76ab6ab22c72 100644 (file)
--- a/gettime.c
+++ b/gettime.c
@@ -381,7 +381,7 @@ void fio_clock_init(void)
 
 uint64_t utime_since(const struct timeval *s, const struct timeval *e)
 {
 
 uint64_t utime_since(const struct timeval *s, const struct timeval *e)
 {
-       long sec, usec;
+       int64_t sec, usec;
 
        sec = e->tv_sec - s->tv_sec;
        usec = e->tv_usec - s->tv_usec;
 
        sec = e->tv_sec - s->tv_sec;
        usec = e->tv_usec - s->tv_usec;
diff --git a/io_u.c b/io_u.c
index 7b51dd2ee19c3cd2e29a9bbcd4ac96a01ec1eba7..428d4b7ff42adc54a397cfa6ed810edb0a2850f4 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -659,7 +659,8 @@ int io_u_quiesce(struct thread_data *td)
 static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
 {
        enum fio_ddir odir = ddir ^ 1;
 static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir)
 {
        enum fio_ddir odir = ddir ^ 1;
-       long usec, now;
+       long usec;
+       uint64_t now;
 
        assert(ddir_rw(ddir));
        now = utime_since_now(&td->start);
 
        assert(ddir_rw(ddir));
        now = utime_since_now(&td->start);
diff --git a/mutex.c b/mutex.c
index e5b045ec91bc0348234eff8cf3f5ff265a9253cf..5e5a0648161de8767bbee98e42ac71d1bef94062 100644 (file)
--- a/mutex.c
+++ b/mutex.c
@@ -162,7 +162,7 @@ int fio_mutex_down_timeout(struct fio_mutex *mutex, unsigned int msecs)
        t.tv_nsec = tv_s.tv_usec * 1000;
 
        t.tv_sec += msecs / 1000;
        t.tv_nsec = tv_s.tv_usec * 1000;
 
        t.tv_sec += msecs / 1000;
-       t.tv_nsec += ((msecs * 1000000) % 1000000000);
+       t.tv_nsec += ((msecs * 1000000ULL) % 1000000000);
        if (t.tv_nsec >= 1000000000) {
                t.tv_nsec -= 1000000000;
                t.tv_sec++;
        if (t.tv_nsec >= 1000000000) {
                t.tv_nsec -= 1000000000;
                t.tv_sec++;
index 091c1613662f66b3eec6f609ab782304a4ecc097..c520b6bb5dbb8dd734de7fefd2955dc6cd9a132e 100644 (file)
--- a/server.c
+++ b/server.c
@@ -912,11 +912,11 @@ static int handle_send_eta_cmd(struct fio_net_cmd *cmd)
                je->files_open          = cpu_to_le32(je->files_open);
 
                for (i = 0; i < DDIR_RWDIR_CNT; i++) {
                je->files_open          = cpu_to_le32(je->files_open);
 
                for (i = 0; i < DDIR_RWDIR_CNT; i++) {
-                       je->m_rate[i]   = cpu_to_le32(je->m_rate[i]);
-                       je->t_rate[i]   = cpu_to_le32(je->t_rate[i]);
+                       je->m_rate[i]   = cpu_to_le64(je->m_rate[i]);
+                       je->t_rate[i]   = cpu_to_le64(je->t_rate[i]);
                        je->m_iops[i]   = cpu_to_le32(je->m_iops[i]);
                        je->t_iops[i]   = cpu_to_le32(je->t_iops[i]);
                        je->m_iops[i]   = cpu_to_le32(je->m_iops[i]);
                        je->t_iops[i]   = cpu_to_le32(je->t_iops[i]);
-                       je->rate[i]     = cpu_to_le32(je->rate[i]);
+                       je->rate[i]     = cpu_to_le64(je->rate[i]);
                        je->iops[i]     = cpu_to_le32(je->iops[i]);
                }
 
                        je->iops[i]     = cpu_to_le32(je->iops[i]);
                }
 
diff --git a/stat.h b/stat.h
index e6f77599310db55e996d55cfc9ad7f5513f11963..de5c12a5f6b9394d0de483d2ee04bc2d84a826dc 100644 (file)
--- a/stat.h
+++ b/stat.h
@@ -224,9 +224,9 @@ struct jobs_eta {
 
        uint32_t files_open;
 
 
        uint32_t files_open;
 
-       uint32_t m_rate[DDIR_RWDIR_CNT], t_rate[DDIR_RWDIR_CNT];
+       uint64_t m_rate[DDIR_RWDIR_CNT], t_rate[DDIR_RWDIR_CNT];
        uint32_t m_iops[DDIR_RWDIR_CNT], t_iops[DDIR_RWDIR_CNT];
        uint32_t m_iops[DDIR_RWDIR_CNT], t_iops[DDIR_RWDIR_CNT];
-       uint32_t rate[DDIR_RWDIR_CNT];
+       uint64_t rate[DDIR_RWDIR_CNT];
        uint32_t iops[DDIR_RWDIR_CNT];
        uint64_t elapsed_sec;
        uint64_t eta_sec;
        uint32_t iops[DDIR_RWDIR_CNT];
        uint64_t elapsed_sec;
        uint64_t eta_sec;
index 5e379e327785aa05c51178b0083d6bd4e23f8974..8ec6b971292a553f075527349f75314da65bf40d 100644 (file)
@@ -251,8 +251,8 @@ struct thread_options {
        char *exec_prerun;
        char *exec_postrun;
 
        char *exec_prerun;
        char *exec_postrun;
 
-       unsigned int rate[DDIR_RWDIR_CNT];
-       unsigned int ratemin[DDIR_RWDIR_CNT];
+       uint64_t rate[DDIR_RWDIR_CNT];
+       uint64_t ratemin[DDIR_RWDIR_CNT];
        unsigned int ratecycle;
        unsigned int io_submit_mode;
        unsigned int rate_iops[DDIR_RWDIR_CNT];
        unsigned int ratecycle;
        unsigned int io_submit_mode;
        unsigned int rate_iops[DDIR_RWDIR_CNT];
@@ -516,8 +516,8 @@ struct thread_options_pack {
        uint8_t exec_prerun[FIO_TOP_STR_MAX];
        uint8_t exec_postrun[FIO_TOP_STR_MAX];
 
        uint8_t exec_prerun[FIO_TOP_STR_MAX];
        uint8_t exec_postrun[FIO_TOP_STR_MAX];
 
-       uint32_t rate[DDIR_RWDIR_CNT];
-       uint32_t ratemin[DDIR_RWDIR_CNT];
+       uint64_t rate[DDIR_RWDIR_CNT];
+       uint64_t ratemin[DDIR_RWDIR_CNT];
        uint32_t ratecycle;
        uint32_t io_submit_mode;
        uint32_t rate_iops[DDIR_RWDIR_CNT];
        uint32_t ratecycle;
        uint32_t io_submit_mode;
        uint32_t rate_iops[DDIR_RWDIR_CNT];