From 7de305510a07729be3cc80a0fb10561732ee4f31 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) (cherry picked from commit e9a5932d04f6b7dd25b39a8ff9dc162d64a78c22) --- test/build.info | 3 ++- test/testutil.h | 8 ++++++++ test/testutil/driver.c | 6 +++--- test/testutil/random.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/testutil/random.c diff --git a/test/build.info b/test/build.info index a2fb0e2e1e..1727f28626 100644 --- a/test/build.info +++ b/test/build.info @@ -12,7 +12,8 @@ IF[{- !$disabled{tests} -}] SOURCE[libtestutil.a]=testutil/basic_output.c testutil/output_helpers.c \ testutil/driver.c testutil/tests.c testutil/cb.c testutil/stanza.c \ testutil/format_output.c testutil/tap_bio.c \ - testutil/test_cleanup.c testutil/main.c testutil/init.c + testutil/test_cleanup.c testutil/main.c testutil/init.c \ + testutil/random.c INCLUDE[libtestutil.a]=../include DEPEND[libtestutil.a]=../libcrypto diff --git a/test/testutil.h b/test/testutil.h index 6391905647..db0c74ef88 100644 --- a/test/testutil.h +++ b/test/testutil.h @@ -454,4 +454,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 6e9914c48d..48f94aea1e 100644 --- a/test/testutil/driver.c +++ b/test/testutil/driver.c @@ -112,7 +112,7 @@ void setup_test_framework() seed = (int)time(NULL); test_printf_stdout("%*s# RAND SEED %d\n", subtest_level(), "", seed); test_flush_stdout(); - srand(seed); + test_random_seed(seed); } #ifndef OPENSSL_NO_CRYPTO_MDEBUG @@ -190,7 +190,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; @@ -228,7 +228,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(); +} -- 2.25.1