From e9a5932d04f6b7dd25b39a8ff9dc162d64a78c22 Mon Sep 17 00:00:00 2001 From: Pauli Date: Fri, 26 Jul 2019 12:56:01 +1000 Subject: [PATCH] Add weak platform independent PRNG to test framework. Implement the GNU C library's random(3) pseudorandom number generator. The algorithm is described: https://www.mscs.dal.ca/~selinger/random/ The rationale is to make the tests repeatable across differing platforms with different underlying implementations of the random(3) library call. More specifically: when executing tests with random ordering. [extended tests] Reviewed-by: Bernd Edlinger (Merged from https://github.com/openssl/openssl/pull/9463) --- test/build.info | 2 +- test/testutil.h | 8 ++++++++ test/testutil/driver.c | 6 +++--- test/testutil/random.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 test/testutil/random.c diff --git a/test/build.info b/test/build.info index f9d429eba8..595a0da2ae 100644 --- a/test/build.info +++ b/test/build.info @@ -22,7 +22,7 @@ IF[{- !$disabled{tests} -}] testutil/format_output.c testutil/tap_bio.c \ testutil/test_cleanup.c testutil/main.c testutil/init.c \ testutil/options.c testutil/test_options.c \ - testutil/apps_mem.c $LIBAPPSSRC + testutil/apps_mem.c testutil/random.c $LIBAPPSSRC INCLUDE[libtestutil.a]=../include ../apps/include .. DEPEND[libtestutil.a]=../libcrypto diff --git a/test/testutil.h b/test/testutil.h index 3a5c4866da..00e2d0aa81 100644 --- a/test/testutil.h +++ b/test/testutil.h @@ -537,4 +537,12 @@ void test_clearstanza(STANZA *s); */ char *glue_strings(const char *list[], size_t *out_len); +/* + * Pseudo random number generator of low quality but having repeatability + * across platforms. The two calls are replacements for random(3) and + * srandom(3). + */ +uint32_t test_random(void); +void test_random_seed(uint32_t sd); + #endif /* HEADER_TESTUTIL_H */ diff --git a/test/testutil/driver.c b/test/testutil/driver.c index 40ed3736c5..7a67a0587c 100644 --- a/test/testutil/driver.c +++ b/test/testutil/driver.c @@ -114,7 +114,7 @@ static void set_seed(int s) seed = (int)time(NULL); test_printf_stdout("%*s# RAND SEED %d\n", subtest_level(), "", seed); test_flush_stdout(); - srand(seed); + test_random_seed(seed); } @@ -326,7 +326,7 @@ int run_tests(const char *test_prog_name) permute[i] = i; if (seed != 0) for (i = num_tests - 1; i >= 1; i--) { - j = rand() % (1 + i); + j = test_random() % (1 + i); ii = permute[j]; permute[j] = permute[i]; permute[i] = ii; @@ -373,7 +373,7 @@ int run_tests(const char *test_prog_name) jstep = 1; else do - jstep = rand() % all_tests[i].num; + jstep = test_random() % all_tests[i].num; while (jstep == 0 || gcd(all_tests[i].num, jstep) != 1); for (jj = 0; jj < all_tests[i].num; jj++) { diff --git a/test/testutil/random.c b/test/testutil/random.c new file mode 100644 index 0000000000..45d0bb5f05 --- /dev/null +++ b/test/testutil/random.c @@ -0,0 +1,40 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "../testutil.h" + +/* + * This is an implementation of the algorithm used by the GNU C library's + * random(3) pseudorandom number generator as described: + * https://www.mscs.dal.ca/~selinger/random/ + */ +static uint32_t test_random_state[31]; + +uint32_t test_random(void) { + static unsigned int pos = 3; + + if (pos == 31) + pos = 0; + test_random_state[pos] += test_random_state[(pos + 28) % 31]; + return test_random_state[pos++] / 2; +} + +void test_random_seed(uint32_t sd) { + int i; + int32_t s; + const unsigned int mod = (1u << 31) - 1; + + test_random_state[0] = sd; + for (i = 1; i < 31; i++) { + s = (int32_t)test_random_state[i - 1]; + test_random_state[i] = (uint32_t)((16807 * (int64_t)s) % mod); + } + for (i = 34; i < 344; i++) + test_random(); +}