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 6787c11..e2211d5 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;