From 13a10ce7af9dd794ca710d63cd071ab94ca940dc Mon Sep 17 00:00:00 2001 From: Alex Lyon <arcterus@mail.com> Date: Thu, 25 Apr 2019 19:35:32 -0700 Subject: [PATCH] stdlib: implement rand_r() using XorShiftRng --- src/header/stdlib/mod.rs | 18 +++++++++++++--- tests/expected/stdlib/rand.stdout | 4 ++++ tests/stdlib/rand.c | 36 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 07125896..c69caa44 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -628,9 +628,21 @@ pub unsafe extern "C" fn rand() -> c_int { } } -// #[no_mangle] -pub extern "C" fn rand_r(seed: *mut c_uint) -> c_int { - unimplemented!(); +#[no_mangle] +pub unsafe extern "C" fn rand_r(seed: *mut c_uint) -> c_int { + if seed.is_null() { + errno::EINVAL + } else { + // set the type explicitly so this will fail if the array size for XorShiftRng changes + let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<c_uint>()]); + + let mut rng = XorShiftRng::from_seed(seed_arr); + let ret = rng.gen_range(0, RAND_MAX); + + *seed = ret as _; + + ret + } } // #[no_mangle] diff --git a/tests/expected/stdlib/rand.stdout b/tests/expected/stdlib/rand.stdout index 60210f3e..4e35003b 100644 --- a/tests/expected/stdlib/rand.stdout +++ b/tests/expected/stdlib/rand.stdout @@ -2,3 +2,7 @@ 201425341 201425341 67141780 +264204 +271585843 +264204 +271585843 diff --git a/tests/stdlib/rand.c b/tests/stdlib/rand.c index 52908fae..29791888 100644 --- a/tests/stdlib/rand.c +++ b/tests/stdlib/rand.c @@ -31,4 +31,40 @@ int main(void) { puts("srand(1) doesn't work"); exit(EXIT_FAILURE); } + + // Ensure rand_r() fails with NULL input + if (rand_r(NULL) != EINVAL) { + puts("rand_r(NULL) doesn't return EINVAL"); + exit(EXIT_FAILURE); + } + + // Ensure rand_r() produces unique values + int seed = 259; + int rand_r_seed259_1 = rand_r((unsigned *)&seed); + printf("%d\n", rand_r_seed259_1); + + int rand_r_seed259_2 = rand_r((unsigned *)&seed); + printf("%d\n", rand_r_seed259_2); + + if (rand_r_seed259_1 == rand_r_seed259_2) { + puts("rand_r() fails to produce unique values"); + exit(EXIT_FAILURE); + } + + // Ensure rand_r() returns reproducible values + seed = 259; + int rand_r_seed259_1_2 = rand_r((unsigned *)&seed); + printf("%d\n", rand_r_seed259_1_2); + + int rand_r_seed259_2_2 = rand_r((unsigned *)&seed); + printf("%d\n", rand_r_seed259_2_2); + + if (rand_r_seed259_1 != rand_r_seed259_1_2 + || rand_r_seed259_2 != rand_r_seed259_2_2) + { + puts("rand_r() is not reproducible"); + exit(EXIT_FAILURE); + } + + return 0; } -- GitLab