# [tz] [PROPOSED 1/6] Don’t assume INT_MAX < UINT_FAST64_MAX

Paul Eggert eggert at cs.ucla.edu
Sun Nov 20 05:47:55 UTC 2022

```* zic.c (get_rand_u64): Avoid undefined behavior in getrandom
fallback, on theoretical platforms where UINT_FAST64_MAX <= INT_MAX
so a * b can have signed integer overflow even though A and B are
uint_fast64_t.
---
zic.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/zic.c b/zic.c
index 45dffea..26595c2 100644
--- a/zic.c
+++ b/zic.c
@@ -1230,13 +1230,21 @@ get_rand_u64(void)
the typical case where RAND_MAX is one less than a power of two.
In other cases this code yields a sort-of-random number.  */
{
-    uint_fast64_t
-      rand_max = RAND_MAX,
-      multiplier = rand_max + 1, /* It's OK if this overflows to 0.  */
+    uint_fast64_t rand_max = RAND_MAX,
+      nrand = rand_max < UINT_FAST64_MAX ? rand_max + 1 : 0,
+      rmod = INT_MAX < UINT_FAST64_MAX ? 0 : UINT_FAST64_MAX / nrand + 1,
r = 0, rmax = 0;
+
do {
-      uint_fast64_t rmax1 = rmax * multiplier + rand_max;
-      r = r * multiplier + rand();
+      uint_fast64_t rmax1 = rmax;
+      if (rmod) {
+	/* Avoid signed integer overflow on theoretical platforms
+	   where uint_fast64_t promotes to int.  */
+	rmax1 %= rmod;
+	r %= rmod;
+      }
+      rmax1 = nrand * rmax1 + rand_max;
+      r = nrand * r + rand();
rmax = rmax < rmax1 ? rmax1 : UINT_FAST64_MAX;
} while (rmax < UINT_FAST64_MAX);

--
2.38.1

```