26a7a5
From c6b79cbc990b3b4933730205f58812fb44b6fcd5 Mon Sep 17 00:00:00 2001
26a7a5
From: Petr Tesarik <ptesarik@suse.cz>
26a7a5
Date: Tue, 10 Apr 2018 20:39:00 +0900
26a7a5
Subject: [PATCH] [PATCH v2] makedumpfile: Use integer arithmetics for the
26a7a5
 progress bar
26a7a5
26a7a5
Essentially, the estimated remaining time is calculated as:
26a7a5
26a7a5
  elapsed * (100 - progress) / progress
26a7a5
26a7a5
Since the calculation is done with floating point numbers, it had
26a7a5
masked a division by zero (if progress is 0), producing a NaN or
26a7a5
infinity. The following conversion to int produces INT_MIN with GCC
26a7a5
on major platforms, which originally overflowed the eta buffer. This
26a7a5
bug was fixed by commit e5f96e79d69a1d295f19130da00ec6514d28a8ae,
26a7a5
but conversion of NaN and infinity is undefined behaviour in ISO C,
26a7a5
plus the corresponding output is still wrong, e.g.:
26a7a5
26a7a5
Copying data                                      : [  0.0 %] /  eta:
26a7a5
-9223372036854775808s
26a7a5
26a7a5
Most importantly, using the FPU for a progress bar is overkill.
26a7a5
Since the progress percentage is reported with one decimal digit
26a7a5
following the decimal point, it can be stored as an integer tenths
26a7a5
of a percent.
26a7a5
26a7a5
Second, the estimated time can be calculated in milliseconds. Up to
26a7a5
49 days can be represented this way even on 32-bit platforms. Note
26a7a5
that delta.tv_usec can be ignored in the subtraction, because the
26a7a5
resulting eta is printed as seconds, so elapsed microseconds are
26a7a5
irrelevant.
26a7a5
26a7a5
Last but not least, the original buffer overflow was probably caused
26a7a5
by the wrong assumption that integers < 100 can be interpreted with
26a7a5
less than 3 ASCII characters, but that's not true for signed
26a7a5
integers. To make eta_to_human_short() a bit safer, use an unsigned
26a7a5
integer type.
26a7a5
26a7a5
Signed-off-by: Petr Tesarik <ptesarik@suse.com>
26a7a5
---
26a7a5
 print_info.c | 43 ++++++++++++++++++++-----------------------
26a7a5
 1 file changed, 20 insertions(+), 23 deletions(-)
26a7a5
26a7a5
diff --git a/makedumpfile-1.6.2/print_info.c b/makedumpfile-1.6.2/print_info.c
26a7a5
index 09e215a..6bfcd11 100644
26a7a5
--- a/makedumpfile-1.6.2/print_info.c
26a7a5
+++ b/makedumpfile-1.6.2/print_info.c
26a7a5
@@ -16,8 +16,6 @@
26a7a5
 #include "print_info.h"
26a7a5
 #include <time.h>
26a7a5
 #include <string.h>
26a7a5
-#include <stdint.h>
26a7a5
-#include <inttypes.h>
26a7a5
 
26a7a5
 #define PROGRESS_MAXLEN		"50"
26a7a5
 
26a7a5
@@ -354,21 +352,18 @@ static void calc_delta(struct timeval *tv_start, struct timeval *delta)
26a7a5
 }
26a7a5
 
26a7a5
 /* produce less than 12 bytes on msg */
26a7a5
-static int eta_to_human_short (int64_t secs, char* msg, int maxsize)
26a7a5
+static int eta_to_human_short (unsigned long secs, char* msg)
26a7a5
 {
26a7a5
 	strcpy(msg, "eta: ");
26a7a5
 	msg += strlen("eta: ");
26a7a5
 	if (secs < 100)
26a7a5
-		snprintf(msg, maxsize, "%"PRId64"s", secs);
26a7a5
+		sprintf(msg, "%lus", secs);
26a7a5
 	else if (secs < 100 * 60)
26a7a5
-		snprintf(msg, maxsize, "%"PRId64"m""%"PRId64"s",
26a7a5
-			secs / 60, secs % 60);
26a7a5
+		sprintf(msg, "%lum%lus", secs / 60, secs % 60);
26a7a5
 	else if (secs < 48 * 3600)
26a7a5
-		snprintf(msg, maxsize, "%"PRId64"h""%"PRId64"m",
26a7a5
-			secs / 3600, (secs / 60) % 60);
26a7a5
+		sprintf(msg, "%luh%lum", secs / 3600, (secs / 60) % 60);
26a7a5
 	else if (secs < 100 * 86400)
26a7a5
-		snprintf(msg, maxsize, "%"PRId64"d""%"PRId64"h",
26a7a5
-			secs / 86400, (secs / 3600) % 24);
26a7a5
+		sprintf(msg, "%lud%luh", secs / 86400, (secs / 3600) % 24);
26a7a5
 	else
26a7a5
 		sprintf(msg, ">2day");
26a7a5
 	return 0;
26a7a5
@@ -378,37 +373,39 @@ static int eta_to_human_short (int64_t secs, char* msg, int maxsize)
26a7a5
 void
26a7a5
 print_progress(const char *msg, unsigned long current, unsigned long end, struct timeval *start)
26a7a5
 {
26a7a5
-	float progress;
26a7a5
+	unsigned progress;	/* in promilles (tenths of a percent) */
26a7a5
 	time_t tm;
26a7a5
 	static time_t last_time = 0;
26a7a5
 	static unsigned int lapse = 0;
26a7a5
 	static const char *spinner = "/|\\-";
26a7a5
 	struct timeval delta;
26a7a5
-	int64_t eta;
26a7a5
-	char eta_msg[32] = " ";
26a7a5
+	unsigned long eta;
26a7a5
+	char eta_msg[16] = " ";
26a7a5
 
26a7a5
 	if (current < end) {
26a7a5
 		tm = time(NULL);
26a7a5
 		if (tm - last_time < 1)
26a7a5
 			return;
26a7a5
 		last_time = tm;
26a7a5
-		progress = (float)current * 100 / end;
26a7a5
+		progress = current * 1000 / end;
26a7a5
 	} else
26a7a5
-		progress = 100;
26a7a5
+		progress = 1000;
26a7a5
 
26a7a5
-	if (start != NULL) {
26a7a5
+	if (start != NULL && progress != 0) {
26a7a5
 		calc_delta(start, &delta);
26a7a5
-		eta = delta.tv_sec + delta.tv_usec / 1e6;
26a7a5
-		eta = (100 - progress) * eta / progress;
26a7a5
-		eta_to_human_short(eta, eta_msg, sizeof(eta_msg));
26a7a5
+		eta = 1000 * delta.tv_sec + delta.tv_usec / 1000;
26a7a5
+		eta = eta / progress - delta.tv_sec;
26a7a5
+		eta_to_human_short(eta, eta_msg);
26a7a5
 	}
26a7a5
 	if (flag_ignore_r_char) {
26a7a5
-		PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%5.1f %%] %c  %16s\n",
26a7a5
-			     msg, progress, spinner[lapse % 4], eta_msg);
26a7a5
+		PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3u.%u %%] %c  %16s\n",
26a7a5
+			     msg, progress / 10, progress % 10,
26a7a5
+			     spinner[lapse % 4], eta_msg);
26a7a5
 	} else {
26a7a5
 		PROGRESS_MSG("\r");
26a7a5
-		PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%5.1f %%] %c  %16s",
26a7a5
-			     msg, progress, spinner[lapse % 4], eta_msg);
26a7a5
+		PROGRESS_MSG("%-" PROGRESS_MAXLEN "s: [%3u.%u %%] %c  %16s",
26a7a5
+			     msg, progress / 10, progress % 10,
26a7a5
+			     spinner[lapse % 4], eta_msg);
26a7a5
 	}
26a7a5
 	lapse++;
26a7a5
 }
26a7a5
-- 
26a7a5
2.9.5
26a7a5