Skip to content

Commit 82b925e

Browse files
authored
Rollup merge of #158125 - joboet:getrandom-fallback-test, r=jhpratt
add a test for the `getrandom` fallback Now that the randomness API is nearing stabilisation, I think it'd be quite good to have a test for our `getrandom` fallback code to rule out any issues with the polling logic. This test uses symbol interposition to control the `getrandom` return value; I tried to make it as resilient to changes to the `SystemRng`-internals as possible.
2 parents b98c554 + ac3bada commit 82b925e

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//@ only-linux
2+
//@ run-pass
3+
4+
#![feature(random)]
5+
#![feature(rustc_private)]
6+
7+
extern crate libc;
8+
9+
use std::ffi::{c_void, c_uint, c_int};
10+
use std::random::{SystemRng, Rng};
11+
use std::cell::Cell;
12+
use std::panic::catch_unwind;
13+
14+
thread_local! {
15+
static GETRANDOM_ERROR: Cell<c_int> = const { Cell::new(libc::ENOMEM) };
16+
}
17+
18+
// This interposes the symbol defined in the libc to return an error when we
19+
// want it to.
20+
#[unsafe(no_mangle)]
21+
fn getrandom(_buf: *const c_void, _size: usize, _flags: c_uint) -> isize {
22+
let errno = GETRANDOM_ERROR.get();
23+
unsafe { libc::__errno_location().write(errno) };
24+
-1
25+
}
26+
27+
fn main() {
28+
// Step one:
29+
// Test that the interposed symbol actually gets used by having it return an
30+
// error that makes `SystemRng` panic.
31+
GETRANDOM_ERROR.set(libc::ENOMEM);
32+
catch_unwind(|| {
33+
let mut buf = [0; 16];
34+
SystemRng.fill_bytes(&mut buf);
35+
}).expect_err("SystemRng should panic upon receiving ENOMEM from the interposed getrandom");
36+
37+
// Step two:
38+
// Emulate a missing `getrandom` by returning `ENOSYS`. This should excercise
39+
// the fallback code.
40+
GETRANDOM_ERROR.set(libc::ENOSYS);
41+
let mut buf = [0; 16];
42+
SystemRng.fill_bytes(&mut buf);
43+
44+
// Smoke check that the buffer was actually filled. It is possible for this
45+
// to spuriously fail, but the likelyhood of that happening is 1 in 2^256.
46+
assert_ne!(buf, [0; 16]);
47+
48+
// And lastly, check that the random pool has been initialized by manually
49+
// calling the getrandom syscall and checking that it does not block. This
50+
// is unlikely to catch any issues since the randomness pool is nearly always
51+
// initialized, but who knows.
52+
let r = unsafe {
53+
libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
54+
};
55+
assert_ne!(r, -1);
56+
}

0 commit comments

Comments
 (0)