From 04ab35666997fbb3cd5d72497415fb3dfd62dcc5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tim=20R=C3=BChsen?= <tim.ruehsen@gmx.de>
Date: Thu, 3 Aug 2023 11:19:35 +0200
Subject: [PATCH] Fix crash when printing download rate

If the download rate is TB/s, a read buffer overflow happended
that either caused a crash or printed whatever string was pointed to.

* src/retr.c (retr_rate): Add missing array entrie for TB/s and Tb/s,
  (test_retr_rate): New test function.
* tests/unit-tests.c (all_tests): Run test 'test_retr_rate'.
* tests/unit-tests.h: Add prototype for test_retr_rate.

Reported-by: Wiebe Cazemier <wiebe@halfgaar.net>
---
 src/retr.c         | 34 ++++++++++++++++++++++++++++++++--
 tests/unit-tests.c |  1 +
 tests/unit-tests.h |  1 +
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/src/retr.c b/src/retr.c
index 38c9fcfe..fffacb91 100644
--- a/src/retr.c
+++ b/src/retr.c
@@ -776,8 +776,8 @@ const char *
 retr_rate (wgint bytes, double secs)
 {
   static char res[20];
-  static const char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s" };
-  static const char *rate_names_bits[] = {"b/s", "Kb/s", "Mb/s", "Gb/s" };
+  static const char *rate_names[] = {"B/s", "KB/s", "MB/s", "GB/s", "TB/s" };
+  static const char *rate_names_bits[] = {"b/s", "Kb/s", "Mb/s", "Gb/s", "Tb/s" };
   int units;
 
   double dlrate = calc_rate (bytes, secs, &units);
@@ -1555,3 +1555,33 @@ input_file_url (const char *input_file)
   else
     return false;
 }
+
+#ifdef TESTING
+
+#include <stdint.h>
+#include "../tests/unit-tests.h"
+
+const char *
+test_retr_rate(void)
+{
+  static const struct test {
+    wgint bytes;
+    double secs;
+    const char *expected;
+  } tests[] = {
+    { 0, 1, "0.00 B/s" },
+    { INT64_MAX, 1, "100 TB/s" },
+  };
+
+  for (struct test *t = tests; t < tests+countof(tests); t++)
+    {
+      const char *result = retr_rate (t->bytes, t->secs);
+
+      if (strcmp(result,t->expected))
+        return aprintf("%s: Expected '%s', got '%s'", __func__, t->expected, result);
+    }
+
+  return NULL;
+}
+
+#endif /* TESTING */
\ No newline at end of file
diff --git a/tests/unit-tests.c b/tests/unit-tests.c
index 12c8f013..b440e0d5 100644
--- a/tests/unit-tests.c
+++ b/tests/unit-tests.c
@@ -67,6 +67,7 @@ all_tests(void)
   mu_run_test (test_hsts_read_database);
 #endif
   mu_run_test (test_parse_netrc);
+  mu_run_test (test_retr_rate);
 
   return NULL;
 }
diff --git a/tests/unit-tests.h b/tests/unit-tests.h
index ea4108be..53161a30 100644
--- a/tests/unit-tests.h
+++ b/tests/unit-tests.h
@@ -63,6 +63,7 @@ const char *test_hsts_url_rewrite_superdomain(void);
 const char *test_hsts_url_rewrite_congruent(void);
 const char *test_hsts_read_database(void);
 const char *test_parse_netrc(void);
+const char *test_retr_rate(void);
 
 #endif /* TEST_H */
 
-- 
2.25.1

