improve how random seed state is determined

Added "STATIC bool blum_initialized = false" to zrandom.c to improve
how the code detects if the Blum-Blum-Shub pseudo-random number
generator is seeded or not, and how to free the state correctly.

NOTE: There is a very minor memory leak in zrandom.c that will be
fixed in a later release.
This commit is contained in:
Landon Curt Noll
2023-12-08 13:51:14 -08:00
parent c724227ef9
commit fbaff69c92
2 changed files with 63 additions and 22 deletions

View File

@@ -1,4 +1,5 @@
The following are the changes from calc version 2.15.0.2 to date:
Updated BUGS about MSYS2 on Windows compiling of calc.
Added more git related checks and sanity checks to chk_tree.
@@ -21,6 +22,13 @@ The following are the changes from calc version 2.15.0.2 to date:
Fixed the check for <sys/mount.h> when forming have_sys_mount.h.
Thanks goes to GitHub user @gromit1811 for their pull request.
Added "STATIC bool blum_initialized = false" to zrandom.c to improve
how the code detects if the Blum-Blum-Shub pseudo-random number
generator is seeded or not, and how to free the state correctly.
NOTE: There is a very minor memory leak in zrandom.c that will be
fixed in a later release.
The following are the changes from calc version 2.14.3.5 to 2.15.0.1:

View File

@@ -1107,6 +1107,7 @@
* current Blum generator state
*/
STATIC RANDOM blum;
STATIC bool blum_initialized = false; /* true ==> blum has a seeded and initialized state */
/*
@@ -2272,11 +2273,14 @@ zsrandom1(CONST ZVALUE seed, bool need_ret)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
/*
@@ -2342,6 +2346,9 @@ zsrandom1(CONST ZVALUE seed, bool need_ret)
* reserved seed
*/
} else {
if (ret != NULL) {
randomfree(ret);
}
math_error("srandom seed must be 0 or >= 2^32");
not_reached();
}
@@ -2384,11 +2391,14 @@ zsrandom2(CONST ZVALUE seed, CONST ZVALUE newn)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
/*
@@ -2409,11 +2419,13 @@ zsrandom2(CONST ZVALUE seed, CONST ZVALUE newn)
* preset moduli only if small newn
*/
if (ziszero(newn)) {
randomfree(ret);
math_error("srandom newn == 0 reserved for future use");
not_reached();
}
set = (HALF)z1tol(newn);
if (!zistiny(newn) || set > BLUM_PREGEN) {
randomfree(ret);
math_error("srandom small newn must be [1,20]");
not_reached();
}
@@ -2433,7 +2445,7 @@ zsrandom2(CONST ZVALUE seed, CONST ZVALUE newn)
* Otherwise non-zero seeds are processed as 1 arg calls
*/
} else {
zsrandom1(seed, false);
(void) zsrandom1(seed, false);
}
/*
@@ -2452,6 +2464,7 @@ zsrandom2(CONST ZVALUE seed, CONST ZVALUE newn)
* Blum modulus must be 1 mod 4
*/
if (newn.v[0] % 4 != 1) {
randomfree(ret);
math_error("srandom large newn must be 1 mod 4");
not_reached();
}
@@ -2498,6 +2511,7 @@ zsrandom2(CONST ZVALUE seed, CONST ZVALUE newn)
* reserved newn
*/
} else {
randomfree(ret);
math_error("srandom newn must be [1,20] or >= 2^32");
not_reached();
}
@@ -2543,11 +2557,14 @@ zsrandom4(CONST ZVALUE seed, CONST ZVALUE ip, CONST ZVALUE iq, long trials)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
/*
@@ -2559,10 +2576,12 @@ zsrandom4(CONST ZVALUE seed, CONST ZVALUE ip, CONST ZVALUE iq, long trials)
* search the 'p' and 'q' Blum prime (3 mod 4) candidates
*/
if (!znextcand(ip, trials, _zero_, _three_, _four_, &p)) {
randomfree(ret);
math_error("failed to find 1st Blum prime");
not_reached();
}
if (!znextcand(iq, trials, _zero_, _three_, _four_, &q)) {
randomfree(ret);
math_error("failed to find 2nd Blum prime");
not_reached();
}
@@ -2640,11 +2659,14 @@ zsetrandom(CONST RANDOM *state)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
/*
@@ -2684,11 +2706,14 @@ zrandomskip(long cnt)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
loglogn = (long)blum.loglogn;
new_r.len = 0; /* paranoia */
@@ -2798,11 +2823,14 @@ zrandom(long cnt, ZVALUE *res)
/*
* initialize state if first call
*/
if (!blum.seeded) {
if (blum_initialized == false || !blum.seeded) {
p_blum = randomcopy(&init_blum);
if (blum_initialized == true) {
randomfree(&blum);
}
blum = *p_blum;
free(p_blum);
blum_initialized = true;
}
loglogn = blum.loglogn;
mask = blum.mask;
@@ -3120,16 +3148,18 @@ randomfree(RANDOM *state)
not_reached();
}
/* free the values */
/* clear the seed */
state->seeded = 0;
state->bits = 0; /* paranoia */
state->loglogn = 0; /* paranoia */
state->buffer = 0; /* paranoia */
state->mask = 0; /* paranoia */
/* free the values - unless they are one of the default states */
zfree_random(state->n);
zfree_random(state->r);
/* free it if it is not pre-defined */
state->seeded = 0;
state->bits = 0; /* paranoia */
state->buffer = 0;
/* free it if it is not pre-defined */
/* free the RANDOM structure if it is NOT our static blum value */
if (state != &blum) {
free(state);
}
@@ -3223,8 +3253,10 @@ randomprint(CONST RANDOM *UNUSED(state), int UNUSED(flags))
void
random_libcalc_cleanup(void)
{
/* free our state - let zfree_random protect the default state */
/* free our state if seed was initialized - zfree_random protect default states */
if (blum_initialized == true && blum.seeded) {
randomfree(&blum);
}
return;
}
@@ -3238,6 +3270,7 @@ random_libcalc_cleanup(void)
S_FUNC void
zfree_random(ZVALUE z)
{
/* do not free if NULL or one of the default states */
if (z.v != NULL &&
z.v != h_ndefvec && z.v != h_rdefvec && z.v != h_rdefvec_2 &&
z.v != h_nvec01 && z.v != h_rvec01 &&