]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
Unoptimize the higher part of the domain of csrand_uniform()
authorAlejandro Colomar <alx@kernel.org>
Mon, 30 Jan 2023 12:13:36 +0000 (13:13 +0100)
committerIker Pedrosa <ikerpedrosam@gmail.com>
Mon, 30 Jan 2023 17:24:15 +0000 (18:24 +0100)
__int128, which is needed for optimizing that part of the range, is not
always available.  We need the unoptimized version for portability
reasons.

Closes: <https://github.com/shadow-maint/shadow/issues/634>
Fixes: 1a0e13f94edc ("Optimize csrand_uniform()")
Reported-by: Adam Sampson <ats@offog.org>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
libmisc/csrand.c

index d4dabe54ed27a1fb104130081bc65f46690acbd7..2557fac8b3546e04bb37a98f7db600c72bca0b3b 100644 (file)
@@ -9,17 +9,23 @@
 #ident "$Id$"
 
 #include <limits.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #if HAVE_SYS_RANDOM_H
 #include <sys/random.h>
 #endif
+#include "bit.h"
 #include "defines.h"
 #include "prototypes.h"
 #include "shadowlog.h"
 
 
+static uint32_t csrand_uniform32(uint32_t n);
+static unsigned long csrand_uniform_slow(unsigned long n);
+
+
 /*
  * Return a uniformly-distributed CS random u_long value.
  */
@@ -69,16 +75,37 @@ fail:
 
 /*
  * Return a uniformly-distributed CS random value in the interval [0, n-1].
- *
+ */
+unsigned long
+csrand_uniform(unsigned long n)
+{
+       if (n == 0 || n > UINT32_MAX)
+               return csrand_uniform_slow(n);
+
+       return csrand_uniform32(n);
+}
+
+
+/*
+ * Return a uniformly-distributed CS random value in the interval [min, max].
+ */
+unsigned long
+csrand_interval(unsigned long min, unsigned long max)
+{
+       return csrand_uniform(max - min + 1) + min;
+}
+
+
+/*
  * Fast Random Integer Generation in an Interval
  * ACM Transactions on Modeling and Computer Simulation 29 (1), 2019
  * <https://arxiv.org/abs/1805.10941>
  */
-unsigned long
-csrand_uniform(unsigned long n)
+static uint32_t
+csrand_uniform32(uint32_t n)
 {
-       unsigned long      bound, rem;
-       unsigned __int128  r, mult;
+       uint32_t  bound, rem;
+       uint64_t  r, mult;
 
        if (n == 0)
                return csrand();
@@ -97,11 +124,18 @@ csrand_uniform(unsigned long n)
 }
 
 
-/*
- * Return a uniformly-distributed CS random value in the interval [min, max].
- */
-unsigned long
-csrand_interval(unsigned long min, unsigned long max)
+static unsigned long
+csrand_uniform_slow(unsigned long n)
 {
-       return csrand_uniform(max - min + 1) + min;
+       unsigned long  r, max, mask;
+
+       max = n - 1;
+       mask = bit_ceil_wrapul(n) - 1;
+
+       do {
+               r = csrand();
+               r &= mask;  // optimization
+       } while (r > max);  // p = ((mask+1) % n) / (mask+1);  W.C.: p=0.5
+
+       return r;
 }