-
-
Notifications
You must be signed in to change notification settings - Fork 473
Description
Problem: As part of testing rust cross-compilation on a variety of hosts, I've found that rand::rngs::SmallRng
returns the same output for different seeds on a armv7-unknown-linux-gnueabihf
host. I'm not sure if this applies to other ARM hosts, even of the same architecture version (I'm using an ASUS TinkerBoard in this example). Nor am I sure this applies to other architectures; x86_64
Windows and Linux seem fine.
Quick solution: Compile on hosts besides armv7-unknown-linux-gnueabihf
:).
Details: Consider the following program, with the small_rng
feature enabled. I've created a small repo for convenience:
use std::{
sync::atomic::{AtomicUsize, Ordering},
time::{SystemTime, UNIX_EPOCH},
};
use rand::{Rng, SeedableRng};
fn random_ident() -> (u64, u64, [u8; 16], String) {
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let count: u64 = CALL_COUNT.fetch_add(1, Ordering::SeqCst) as u64;
let mut seed: [u8; 16] = [0; 16];
for (i, v) in seed.iter_mut().take(8).enumerate() {
*v = ((secs >> (i * 8)) & 0xFF) as u8
}
for (i, v) in seed.iter_mut().skip(8).enumerate() {
*v = ((count >> (i * 8)) & 0xFF) as u8
}
let mut rng = rand::rngs::SmallRng::from_seed(seed);
(secs, count, seed, (0..16)
.map(|i| {
if i == 0 || rng.gen() {
('a' as u8 + rng.gen::<u8>() % 25) as char
} else {
('0' as u8 + rng.gen::<u8>() % 10) as char
}
})
.collect::<String>())
}
fn main() {
println!("{:?}", random_ident());
println!("{:?}", random_ident());
println!("{:?}", random_ident());
}
On x86_64-unknown-linux-gnu
(and Windows for that matter), this small program returns two different random identifiers for different seeds, as expected:
william@xubuntu-dtrain:~/Projects/debug/rand-bug$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/rand-bug`
(1598719239, 0, [7, 133, 74, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "puetn2yx9hil9580")
(1598719239, 1, [7, 133, 74, 95, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], "wdhp4fvs75a53km8")
(1598719239, 2, [7, 133, 74, 95, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0], "l1uu7f619wu97iu6")
william@xubuntu-dtrain:~/Projects/debug/rand-bug$ rustc -Vv
rustc 1.47.0-nightly (09f4c9f50 2020-08-07)
binary: rustc
commit-hash: 09f4c9f5082f78b0adcee83d3ab4337e000cd28e
commit-date: 2020-08-07
host: x86_64-unknown-linux-gnu
release: 1.47.0-nightly
LLVM version: 10.0
On the other hand, on an armv7-unknown-linux-gnueabihf
host, the same random identifier is emitted twice for different seeds, before emitting a new identifier when a third seed is used:
wjones@DietPi:~/src/debug/rand-bug$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
Running `target/debug/rand-bug`
(1598719307, 0, [75, 133, 74, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "v0go31yx18533ls1")
(1598719307, 1, [75, 133, 74, 95, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], "v0go31yx18533ls1")
(1598719307, 2, [75, 133, 74, 95, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0], "jmu731eti715bgc2")
wjones@DietPi:~/src/debug/rand-bug$ rustc -Vv
rustc 1.46.0-nightly (feb3536eb 2020-06-09)
binary: rustc
commit-hash: feb3536eba10c2e4585d066629598f03d5ddc7c6
commit-date: 2020-06-09
host: armv7-unknown-linux-gnueabihf
release: 1.46.0-nightly
LLVM version: 10.0
wjones@DietPi:~/src/debug/rand-bug$
While my use case will eventually be replaced with a more robust solution, this currently prevents me from compiling my safe Rust embedded code on ARM hosts; safe interrupts rely on being unable to call interrupt functions in application code, and random identifiers is one way to do this.