Skip to content

Commit b7e5df8

Browse files
committed
Remove TLS by using lazy_static
1 parent ce4a089 commit b7e5df8

8 files changed

+91
-206
lines changed

Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ log = { version = "0.4", optional = true }
2222

2323
[target.'cfg(unix)'.dependencies]
2424
libc = "0.2.29"
25+
lazy_static = "1.3.0"
2526

2627
[target.'cfg(windows)'.dependencies]
2728
winapi = { version = "0.3.6", features = ["minwindef", "ntsecapi", "winnt"] }
@@ -32,9 +33,13 @@ cloudabi = "0.0.3"
3233
[target.'cfg(fuchsia)'.dependencies]
3334
fuchsia-cprng = "0.1"
3435

36+
[target.'cfg(target_os = "redox")'.dependencies]
37+
lazy_static = "1.3.0"
38+
3539
[target.wasm32-unknown-unknown.dependencies]
3640
wasm-bindgen = { version = "0.2.29", optional = true }
3741
stdweb = { version = "0.4.9", optional = true }
42+
lazy_static = "1.3.0"
3843

3944
[target.wasm32-wasi.dependencies]
4045
libc = "0.2.54"

src/lib.rs

+11-21
Original file line numberDiff line numberDiff line change
@@ -132,21 +132,6 @@ macro_rules! error { ($($x:tt)*) => () }
132132
#[cfg(target_arch = "wasm32")]
133133
extern crate std;
134134

135-
#[cfg(any(
136-
target_os = "android",
137-
target_os = "netbsd",
138-
target_os = "solaris",
139-
target_os = "illumos",
140-
target_os = "redox",
141-
target_os = "dragonfly",
142-
target_os = "haiku",
143-
target_os = "linux",
144-
all(
145-
target_arch = "wasm32",
146-
not(target_os = "wasi")
147-
),
148-
))]
149-
mod utils;
150135
mod error;
151136
pub use crate::error::Error;
152137

@@ -172,6 +157,15 @@ macro_rules! mod_use {
172157
))]
173158
mod error_impls;
174159

160+
// These targets read from a file as a fallback method.
161+
#[cfg(any(
162+
target_os = "android",
163+
target_os = "linux",
164+
target_os = "solaris",
165+
target_os = "illumos",
166+
))]
167+
mod use_file;
168+
175169
mod_use!(cfg(target_os = "android"), linux_android);
176170
mod_use!(cfg(target_os = "bitrig"), openbsd_bitrig);
177171
mod_use!(cfg(target_os = "cloudabi"), cloudabi);
@@ -231,16 +225,12 @@ mod_use!(
231225
target_os = "openbsd",
232226
target_os = "redox",
233227
target_os = "solaris",
228+
target_os = "wasi",
234229
target_env = "sgx",
235230
windows,
236231
all(
237232
target_arch = "wasm32",
238-
any(
239-
target_os = "emscripten",
240-
target_os = "wasi",
241-
feature = "wasm-bindgen",
242-
feature = "stdweb",
243-
),
233+
any(feature = "wasm-bindgen", feature = "stdweb"),
244234
),
245235
))),
246236
dummy

src/linux_android.rs

+13-52
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,13 @@
99
//! Implementation for Linux / Android
1010
extern crate std;
1111

12-
use crate::Error;
13-
use crate::utils::use_init;
14-
use std::{thread_local, io::{self, Read}, fs::File};
15-
use core::cell::RefCell;
12+
use crate::{use_file, Error};
1613
use core::num::NonZeroU32;
17-
use core::sync::atomic::{AtomicBool, Ordering};
14+
use lazy_static::lazy_static;
15+
use std::io;
1816

1917
// This flag tells getrandom() to return EAGAIN instead of blocking.
2018
const GRND_NONBLOCK: libc::c_uint = 0x0001;
21-
static RNG_INIT: AtomicBool = AtomicBool::new(false);
22-
23-
enum RngSource {
24-
GetRandom,
25-
Device(File),
26-
}
27-
28-
thread_local!(
29-
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
30-
);
3119

3220
fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result<(), io::Error> {
3321
let flags = if block { 0 } else { GRND_NONBLOCK };
@@ -42,46 +30,19 @@ fn syscall_getrandom(dest: &mut [u8], block: bool) -> Result<(), io::Error> {
4230
}
4331

4432
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
45-
RNG_SOURCE.with(|f| {
46-
use_init(f,
47-
|| {
48-
let s = if is_getrandom_available() {
49-
RngSource::GetRandom
50-
} else {
51-
// read one byte from "/dev/random" to ensure that
52-
// OS RNG has initialized
53-
if !RNG_INIT.load(Ordering::Relaxed) {
54-
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
55-
RNG_INIT.store(true, Ordering::Relaxed)
56-
}
57-
RngSource::Device(File::open("/dev/urandom")?)
58-
};
59-
Ok(s)
60-
}, |f| {
61-
match f {
62-
RngSource::GetRandom => syscall_getrandom(dest, true),
63-
RngSource::Device(f) => f.read_exact(dest),
64-
}.map_err(From::from)
65-
})
66-
})
33+
lazy_static! { static ref HAS_GETRANDOM: bool = is_getrandom_available(); }
34+
match *HAS_GETRANDOM {
35+
true => syscall_getrandom(dest, true).map_err(From::from),
36+
false => use_file::getrandom_inner(dest),
37+
}
6738
}
6839

6940
fn is_getrandom_available() -> bool {
70-
use std::sync::{Once, ONCE_INIT};
71-
72-
static CHECKER: Once = ONCE_INIT;
73-
static AVAILABLE: AtomicBool = AtomicBool::new(false);
74-
75-
CHECKER.call_once(|| {
76-
let mut buf: [u8; 0] = [];
77-
let available = match syscall_getrandom(&mut buf, false) {
78-
Ok(()) => true,
79-
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
80-
};
81-
AVAILABLE.store(available, Ordering::Relaxed);
82-
});
83-
84-
AVAILABLE.load(Ordering::Relaxed)
41+
let mut buf: [u8; 0] = [];
42+
match syscall_getrandom(&mut buf, false) {
43+
Ok(()) => true,
44+
Err(err) => err.raw_os_error() != Some(libc::ENOSYS),
45+
}
8546
}
8647

8748
#[inline(always)]

src/solaris_illumos.rs

+16-53
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,17 @@
1919
//! libc::dlsym.
2020
extern crate std;
2121

22-
use crate::Error;
23-
use crate::utils::use_init;
24-
use std::{thread_local, io::{self, Read}, fs::File};
25-
use core::cell::RefCell;
22+
use crate::{use_file, Error};
23+
use core::mem;
2624
use core::num::NonZeroU32;
25+
use lazy_static::lazy_static;
26+
use std::io;
2727

2828
#[cfg(target_os = "illumos")]
2929
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::ssize_t;
3030
#[cfg(target_os = "solaris")]
3131
type GetRandomFn = unsafe extern "C" fn(*mut u8, libc::size_t, libc::c_uint) -> libc::c_int;
3232

33-
enum RngSource {
34-
GetRandom(GetRandomFn),
35-
Device(File),
36-
}
37-
38-
thread_local!(
39-
static RNG_SOURCE: RefCell<Option<RngSource>> = RefCell::new(None);
40-
);
41-
4233
fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> {
4334
let ret = unsafe { rand(dest.as_mut_ptr(), dest.len(), 0) as libc::ssize_t };
4435

@@ -51,51 +42,23 @@ fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> {
5142
}
5243

5344
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
45+
lazy_static! { static ref GETRANDOM_FUNC: Option<GetRandomFn> = fetch_getrandom(); }
46+
5447
// 256 bytes is the lowest common denominator across all the Solaris
5548
// derived platforms for atomically obtaining random data.
56-
RNG_SOURCE.with(|f| {
57-
use_init(
58-
f,
59-
|| {
60-
let s = match fetch_getrandom() {
61-
Some(fptr) => RngSource::GetRandom(fptr),
62-
None => RngSource::Device(File::open("/dev/random")?),
63-
};
64-
Ok(s)
65-
},
66-
|f| {
67-
match f {
68-
RngSource::GetRandom(rp) => {
69-
for chunk in dest.chunks_mut(256) {
70-
libc_getrandom(*rp, chunk)?
71-
}
72-
}
73-
RngSource::Device(randf) => {
74-
for chunk in dest.chunks_mut(256) {
75-
randf.read_exact(chunk)?
76-
}
77-
}
78-
};
79-
Ok(())
80-
},
81-
)
82-
})
49+
for chunk in dest.chunks_mut(256) {
50+
match *GETRANDOM_FUNC {
51+
Some(fptr) => libc_getrandom(fptr, chunk)?,
52+
None => use_file::getrandom_inner(chunk)?,
53+
};
54+
}
55+
Ok(())
8356
}
8457

8558
fn fetch_getrandom() -> Option<GetRandomFn> {
86-
use std::mem;
87-
use std::sync::atomic::{AtomicUsize, Ordering};
88-
89-
static FPTR: AtomicUsize = AtomicUsize::new(1);
90-
91-
if FPTR.load(Ordering::SeqCst) == 1 {
92-
let name = "getrandom\0";
93-
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) as usize };
94-
FPTR.store(addr, Ordering::SeqCst);
95-
}
96-
97-
let ptr = FPTR.load(Ordering::SeqCst);
98-
unsafe { mem::transmute::<usize, Option<GetRandomFn>>(ptr) }
59+
let name = "getrandom\0";
60+
let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _) };
61+
unsafe { mem::transmute(addr) }
9962
}
10063

10164
#[inline(always)]

src/use_file.rs

+21-18
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,35 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
//! Implementation for DragonFly / Haiku
9+
//! Implementations that just need to read from a file
1010
extern crate std;
1111

1212
use crate::Error;
13-
use crate::utils::use_init;
14-
use std::{thread_local, io::Read, fs::File};
15-
use core::cell::RefCell;
1613
use core::num::NonZeroU32;
17-
18-
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
14+
use lazy_static::lazy_static;
15+
use std::{
16+
fs::File,
17+
io::Read,
18+
os::unix::io::{FromRawFd, IntoRawFd, RawFd},
19+
};
1920

2021
#[cfg(target_os = "redox")]
2122
const FILE_PATH: &str = "rand:";
22-
#[cfg(target_os = "netbsd")]
23+
#[cfg(any(target_os = "android", target_os = "linux", target_os = "netbsd"))]
2324
const FILE_PATH: &str = "/dev/urandom";
24-
#[cfg(any(target_os = "dragonfly", target_os = "emscripten", target_os = "haiku"))]
25+
#[cfg(any(
26+
target_os = "dragonfly",
27+
target_os = "emscripten",
28+
target_os = "haiku",
29+
target_os = "solaris",
30+
target_os = "illumos"
31+
))]
2532
const FILE_PATH: &str = "/dev/random";
2633

2734
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
28-
RNG_FILE.with(|f| {
29-
use_init(f, || init_file(), |f| use_file(f, dest))
30-
})
31-
}
35+
lazy_static! { static ref RNG_FD: Result<RawFd, Error> = init_file(); }
36+
let mut f = unsafe { File::from_raw_fd((*RNG_FD)?) };
3237

33-
fn use_file(f: &mut File, dest: &mut [u8]) -> Result<(), Error> {
3438
if cfg!(target_os = "emscripten") {
3539
// `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes.
3640
for chunk in dest.chunks_mut(65536) {
@@ -39,18 +43,17 @@ fn use_file(f: &mut File, dest: &mut [u8]) -> Result<(), Error> {
3943
} else {
4044
f.read_exact(dest)?;
4145
}
42-
core::mem::forget(f);
4346
Ok(())
4447
}
4548

46-
fn init_file() -> Result<File, Error> {
47-
if cfg!(target_os = "netbsd") {
49+
fn init_file() -> Result<RawFd, Error> {
50+
if FILE_PATH == "/dev/urandom" {
4851
// read one byte from "/dev/random" to ensure that OS RNG has initialized
4952
File::open("/dev/random")?.read_exact(&mut [0u8; 1])?;
5053
}
51-
let f = File::open(FILE_PATH)?;
52-
Ok(f)
54+
Ok(File::open(FILE_PATH)?.into_raw_fd())
5355
}
5456

5557
#[inline(always)]
58+
#[allow(dead_code)]
5659
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/utils.rs

-30
This file was deleted.

0 commit comments

Comments
 (0)