]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
shuf: improve randperm overflow checking
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 22 Oct 2019 19:58:07 +0000 (12:58 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 22 Oct 2019 22:04:43 +0000 (15:04 -0700)
* gl/lib/randperm.c: Include randperm.h first, since it’s the API.
Include stdint.h, count-leading-zeros.h, verify.h.
(floor_lg): Rename from ceil_log (which was not actually
implementing the ceiling!) and implement the floor using
count_leading_zeros.
(randperm_bound): Use floor_lg, not ceil_log.  Use uintmax_t
instead of size_t in case the size gets large on a 32-bit host.
* gl/modules/randperm (Depends-on): Add count-leading-zeros, stdint.

gl/lib/randperm.c
gl/modules/randperm

index ce69222e9e0064cc328dc0f5f5f7381476254366..b079aba3353ac5dbe62588701b1f4a3480dc589a 100644 (file)
 
 #include <config.h>
 
-#include "hash.h"
 #include "randperm.h"
 
 #include <limits.h>
+#include <stdint.h>
 #include <stdlib.h>
 
+#include "count-leading-zeros.h"
+#include "hash.h"
+#include "verify.h"
 #include "xalloc.h"
 
-/* Return the ceiling of the log base 2 of N.  If N is zero, return
-   an unspecified value.  */
+/* Return the floor of the log base 2 of N.  If N is zero, return -1.  */
 
-static size_t _GL_ATTRIBUTE_CONST
-ceil_lg (size_t n)
+static int _GL_ATTRIBUTE_CONST
+floor_lg (size_t n)
 {
-  size_t b = 0;
-  for (n--; n != 0; n /= 2)
-    b++;
-  return b;
+  verify (SIZE_WIDTH <= ULLONG_WIDTH);
+  return (n == 0 ? -1
+          : SIZE_WIDTH <= UINT_WIDTH
+          ? UINT_WIDTH - 1 - count_leading_zeros (n)
+          : SIZE_WIDTH <= ULONG_WIDTH
+          ? ULONG_WIDTH - 1 - count_leading_zeros_l (n)
+          : ULLONG_WIDTH - 1 - count_leading_zeros_ll (n));
 }
 
 /* Return an upper bound on the number of random bytes needed to
@@ -48,10 +53,10 @@ randperm_bound (size_t h, size_t n)
 {
   /* Upper bound on number of bits needed to generate the first number
      of the permutation.  */
-  size_t lg_n = ceil_lg (n);
+  uintmax_t lg_n = floor_lg (n) + 1;
 
   /* Upper bound on number of bits needed to generated the first H elements.  */
-  size_t ar = lg_n * h;
+  uintmax_t ar = lg_n * h;
 
   /* Convert the bit count to a byte count.  */
   size_t bound = (ar + CHAR_BIT - 1) / CHAR_BIT;
index 1fa26129080c0ff906d7d15be0ddb27a6dbc3f6e..e3b347140957d1273ced98e8a2d09f09df74e235 100644 (file)
@@ -6,7 +6,9 @@ lib/randperm.c
 lib/randperm.h
 
 Depends-on:
+count-leading-zeros
 randint
+stdint
 xalloc
 hash