eta: fix previous line length calculation
authorSitsofe Wheeler <sitsofe@yahoo.com>
Sat, 23 Dec 2017 08:43:54 +0000 (08:43 +0000)
committerSitsofe Wheeler <sitsofe@yahoo.com>
Sun, 24 Dec 2017 23:34:39 +0000 (23:34 +0000)
We work out how many stale characters we haven't yet overprinted from
the previous run by comparing the number of characters that snprintf
added to the buffer in both cases. Unfortunately this doesn't account
for earlier characters that may (or may not) have already been in the
output buffer before snprintf was called...

Change the code to just use the current and previous output buffer
position to calculate the remainder of the line to be cleared.

When fio is compiled under clang with
./configure --extra-cflags="-fsanitize=address -fno-builtin" \
 --disable-optimizations

a buffer overrun is demonstrated by the following script

rw[0]='read'; rw[1]='write'; \
for i in {1..4096}; do \
  echo -e "[job$i]\nrw=${rw[$((i % 2))]}\n" \
  "ramp_time=$(((4096 - i) / 2049 * 10))\n" \
          "runtime=15"; \
done | \
./fio --group_reporting --ioengine=null --size=1g --time_based \
 --bs=512 --thread --rate_iops=2 -

Signed-off-by: Sitsofe Wheeler <sitsofe@yahoo.com>
eta.c

diff --git a/eta.c b/eta.c
index c16b6cf..d019747 100644 (file)
--- a/eta.c
+++ b/eta.c
@@ -565,6 +565,7 @@ void display_thread_status(struct jobs_eta *je)
                size_t left;
                int l;
                int ddir;
+               int linelen;
 
                if ((!je->eta_sec && !eta_good) || je->nr_ramp == je->nr_running ||
                    je->eta_sec == -1)
@@ -606,9 +607,10 @@ void display_thread_status(struct jobs_eta *je)
                if (l >= left)
                        l = left - 1;
                p += l;
-               if (l >= 0 && l < linelen_last)
-                       p += sprintf(p, "%*s", linelen_last - l, "");
-               linelen_last = l;
+               linelen = p - output;
+               if (l >= 0 && linelen < linelen_last)
+                       p += sprintf(p, "%*s", linelen_last - linelen, "");
+               linelen_last = linelen;
 
                for (ddir = 0; ddir < DDIR_RWDIR_CNT; ddir++) {
                        free(rate_str[ddir]);