chiark / gitweb /
rand/rand.c (rand_getgood): Stretch the output buffer if necessary.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 23 Dec 2023 14:13:34 +0000 (14:13 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 23 Dec 2023 14:30:41 +0000 (14:30 +0000)
It's possible to have `r->o == RAND_BUFSZ' in the main loop, while
`r->obits' is larger than the requested size.  The following program
contrives this situation, though it can (and does) happen organically.

#include <stdio.h>
#include <stdlib.h>

#include "noise.h"
#include "rand.h"

int main(void)
{
  rand_pool pool;
  unsigned char buf[64];
  size_t n;

  rand_init(&pool);
  rand_noisesrc(&pool, &noise_source);
  rand_seed(&pool, 64);

  while (pool.obits < RAND_OBITS) rand_seed(&pool, RAND_IBITS);
  while (pool.o < RAND_BUFSZ) {
    n = RAND_BUFSZ - pool.o; if (n > sizeof(buf)) n = sizeof(buf);
    rand_getgood(&pool, buf, n);
  }
  rand_getgood(&pool, buf, 4);
  return (0);
}

When this happens, `rand_getgood' gets stuck in an infinite loop,
trimming the chunk size to zero because the output buffer is exhausted,
but not refilling it because there's still notional entropy remaining.
Detect this situation and stretch the output buffer when there's nothing
left, as in `rand_get'.

rand/rand.c

index 6787c11a45e4c708efddb8aa834c4c9c343cada9..e2211d5422966f4281e1361af10e43af055a11f5 100644 (file)
@@ -482,11 +482,15 @@ void rand_getgood(rand_pool *r, void *p, size_t sz)
        chunk = r->obits / 8;
     }
 
-    if (chunk + r->o > RAND_BUFSZ)
+    if (chunk + r->o <= RAND_BUFSZ) {
+      memcpy(o, r->buf + r->o, chunk);
+      r->o += chunk;
+    } else {
       chunk = RAND_BUFSZ - r->o;
+      memcpy(o, r->buf + r->o, chunk);
+      rand_stretch(r);
+    }
 
-    memcpy(o, r->buf + r->o, chunk);
-    r->o += chunk;
     r->obits -= chunk * 8;
     o += chunk;
     sz -= chunk;