Skip to content

Commit 170cbc1

Browse files
authored
Merge pull request #11 from dhardy/master
Revise error types and codes
2 parents 679c52c + f2322f4 commit 170cbc1

22 files changed

+208
-60
lines changed

.travis.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ matrix:
3737
- rm -rf target/doc
3838
- cargo doc --no-deps --all --all-features
3939
- cargo deadlinks --dir target/doc
40+
# also test minimum dependency versions are usable
41+
- cargo generate-lockfile -Z minimal-versions
42+
- cargo test
4043

4144
- rust: nightly
4245
os: osx
@@ -52,6 +55,9 @@ matrix:
5255
- rm -rf target/doc
5356
- cargo doc --no-deps --all --all-features
5457
- cargo deadlinks --dir target/doc
58+
# also test minimum dependency versions are usable
59+
- cargo generate-lockfile -Z minimal-versions
60+
- cargo test
5561

5662
- rust: nightly
5763
env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen"
@@ -97,6 +103,14 @@ matrix:
97103
#- cargo build --target=x86_64-unknown-fuchsia --all-features
98104
- cargo build --target=x86_64-unknown-netbsd --all-features
99105
- cargo build --target=x86_64-unknown-redox --all-features
106+
# also test minimum dependency versions are usable
107+
- cargo generate-lockfile -Z minimal-versions
108+
- cargo build --target=x86_64-sun-solaris --all-features
109+
- cargo build --target=x86_64-unknown-cloudabi --all-features
110+
- cargo build --target=x86_64-unknown-freebsd --all-features
111+
#- cargo build --target=x86_64-unknown-fuchsia --all-features
112+
- cargo build --target=x86_64-unknown-netbsd --all-features
113+
- cargo build --target=x86_64-unknown-redox --all-features
100114

101115
# Trust cross-built/emulated targets. We must repeat all non-default values.
102116
- rust: stable

Cargo.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ members = [
1414
"tests/wasm_bindgen",
1515
]
1616

17+
[dependencies]
18+
log = { version = "0.4", optional = true }
19+
1720
[target.'cfg(unix)'.dependencies]
18-
libc = "0.2"
21+
# In general, we need at least 0.2.27. On Solaris, we need some unknown newer version.
22+
libc = "0.2.50"
1923

2024
[target.'cfg(windows)'.dependencies]
21-
winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] }
25+
winapi = { version = "0.3.6", features = ["minwindef", "ntsecapi", "winnt"] }
2226

2327
[target.'cfg(target_os = "cloudabi")'.dependencies]
2428
cloudabi = "0.0.3"
@@ -27,5 +31,5 @@ cloudabi = "0.0.3"
2731
fuchsia-cprng = "0.1"
2832

2933
[target.wasm32-unknown-unknown.dependencies]
30-
wasm-bindgen = { version = "0.2.12", optional = true }
31-
stdweb = { version = "0.4", optional = true }
34+
wasm-bindgen = { version = "0.2.29", optional = true }
35+
stdweb = { version = "0.4.9", optional = true }

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> {
3838

3939
This library is `no_std` compatible on SGX but requires `std` on most platforms.
4040

41+
The `log` library is supported as an optional dependency. If enabled, error
42+
reporting will be improved on some platforms.
43+
4144
For WebAssembly (`wasm32`), Enscripten targets are supported directly; otherwise
4245
one of the following features must be enabled:
4346

src/cloudabi.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
extern crate cloudabi;
1212

1313
use core::num::NonZeroU32;
14-
use error::Error;
14+
use Error;
1515

1616
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
1717
let errno = unsafe { cloudabi::random_get(dest) };
1818
if errno == cloudabi::errno::SUCCESS {
1919
Ok(())
2020
} else {
2121
let code = NonZeroU32::new(errno as u32).unwrap();
22+
error!("cloudabi::random_get syscall failed with code {}", code);
2223
Err(Error::from(code))
2324
}
2425
}
26+
27+
#[inline(always)]
28+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/dragonfly_haiku.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
// except according to those terms.
88

99
//! Implementation for DragonFly / Haiku
10-
use super::Error;
11-
use super::utils::use_init;
10+
use Error;
11+
use utils::use_init;
1212
use std::fs::File;
1313
use std::io::Read;
1414
use std::cell::RefCell;
15+
use std::num::NonZeroU32;
1516

1617
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
1718

@@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
2324
)
2425
})
2526
}
27+
28+
#[inline(always)]
29+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/dummy.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@
77
// except according to those terms.
88

99
//! A dummy implementation for unsupported targets which always returns
10-
//! `Err(UNAVAILABLE_ERROR)`
11-
use super::UNAVAILABLE_ERROR;
10+
//! `Err(ERROR_UNAVAILABLE)`
11+
use std::num::NonZeroU32;
12+
use {Error, ERROR_UNAVAILABLE};
1213

13-
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
14-
Err(UNAVAILABLE_ERROR)
14+
pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> {
15+
error!("no support for this platform");
16+
Err(ERROR_UNAVAILABLE)
1517
}
18+
19+
#[inline(always)]
20+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/emscripten.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
// except according to those terms.
88

99
//! Implementation for Emscripten
10-
use super::Error;
10+
use Error;
1111
use std::fs::File;
1212
use std::io::Read;
1313
use std::cell::RefCell;
14-
use super::utils::use_init;
14+
use std::num::NonZeroU32;
15+
use utils::use_init;
1516

1617
thread_local!(static RNG_FILE: RefCell<Option<File>> = RefCell::new(None));
1718

@@ -29,3 +30,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
2930
})
3031
})
3132
}
33+
34+
#[inline(always)]
35+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/error.rs

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,29 @@ use core::fmt;
1212
#[cfg(not(target_env = "sgx"))]
1313
use std::{io, error};
1414

15+
// A randomly-chosen 16-bit prefix for our codes
16+
pub(crate) const CODE_PREFIX: u32 = 0x57f40000;
17+
const CODE_UNKNOWN: u32 = CODE_PREFIX | 0;
18+
const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1;
19+
1520
/// An unknown error.
16-
pub const UNKNOWN_ERROR: Error = Error(unsafe {
17-
NonZeroU32::new_unchecked(0x756e6b6e) // "unkn"
21+
///
22+
/// This is the following constant: 57F40000 (hex) / 1475608576 (decimal).
23+
pub const ERROR_UNKNOWN: Error = Error(unsafe {
24+
NonZeroU32::new_unchecked(CODE_UNKNOWN)
1825
});
1926

2027
/// No generator is available.
21-
pub const UNAVAILABLE_ERROR: Error = Error(unsafe {
22-
NonZeroU32::new_unchecked(0x4e416e61) // "NAna"
28+
///
29+
/// This is the following constant: 57F40001 (hex) / 1475608577 (decimal).
30+
pub const ERROR_UNAVAILABLE: Error = Error(unsafe {
31+
NonZeroU32::new_unchecked(CODE_UNAVAILABLE)
2332
});
2433

2534
/// The error type.
2635
///
2736
/// This type is small and no-std compatible.
28-
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
37+
#[derive(Copy, Clone, Eq, PartialEq)]
2938
pub struct Error(NonZeroU32);
3039

3140
impl Error {
@@ -38,14 +47,34 @@ impl Error {
3847
pub fn code(&self) -> NonZeroU32 {
3948
self.0
4049
}
50+
51+
fn msg(&self) -> Option<&'static str> {
52+
if let Some(msg) = super::error_msg_inner(self.0) {
53+
Some(msg)
54+
} else {
55+
match *self {
56+
ERROR_UNKNOWN => Some("getrandom: unknown error"),
57+
ERROR_UNAVAILABLE => Some("getrandom: unavailable"),
58+
_ => None
59+
}
60+
}
61+
}
62+
}
63+
64+
impl fmt::Debug for Error {
65+
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
66+
match self.msg() {
67+
Some(msg) => write!(f, "Error(\"{}\")", msg),
68+
None => write!(f, "Error(0x{:08X})", self.0),
69+
}
70+
}
4171
}
4272

4373
impl fmt::Display for Error {
4474
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
45-
match *self {
46-
UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"),
47-
UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"),
48-
code => write!(f, "Getrandom Error: {}", code.0.get()),
75+
match self.msg() {
76+
Some(msg) => write!(f, "{}", msg),
77+
None => write!(f, "getrandom: unknown code 0x{:08X}", self.0),
4978
}
5079
}
5180
}
@@ -63,22 +92,31 @@ impl From<io::Error> for Error {
6392
.and_then(|code| NonZeroU32::new(code as u32))
6493
.map(|code| Error(code))
6594
// in practice this should never happen
66-
.unwrap_or(UNKNOWN_ERROR)
95+
.unwrap_or(ERROR_UNKNOWN)
6796
}
6897
}
6998

7099
#[cfg(not(target_env = "sgx"))]
71100
impl From<Error> for io::Error {
72101
fn from(err: Error) -> Self {
73-
match err {
74-
UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other,
75-
"getrandom error: unknown"),
76-
UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other,
77-
"getrandom error: entropy source is unavailable"),
78-
code => io::Error::from_raw_os_error(code.0.get() as i32),
102+
match err.msg() {
103+
Some(msg) => io::Error::new(io::ErrorKind::Other, msg),
104+
None => io::Error::from_raw_os_error(err.0.get() as i32),
79105
}
80106
}
81107
}
82108

83109
#[cfg(not(target_env = "sgx"))]
84110
impl error::Error for Error { }
111+
112+
#[cfg(test)]
113+
mod tests {
114+
use std::mem::size_of;
115+
use super::Error;
116+
117+
#[test]
118+
fn test_size() {
119+
assert_eq!(size_of::<Error>(), 4);
120+
assert_eq!(size_of::<Result<(), Error>>(), 4);
121+
}
122+
}

src/freebsd.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
//! Implementation for FreeBSD
1010
extern crate libc;
1111

12-
use super::Error;
12+
use Error;
1313
use core::ptr;
1414
use std::io;
15+
use std::num::NonZeroU32;
1516

1617
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
1718
let mib = [libc::CTL_KERN, libc::KERN_ARND];
@@ -25,8 +26,12 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
2526
)
2627
};
2728
if ret == -1 || len != chunk.len() {
29+
error!("freebsd: kern.arandom syscall failed");
2830
return Err(io::Error::last_os_error().into());
2931
}
3032
}
3133
Ok(())
3234
}
35+
36+
#[inline(always)]
37+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/fuchsia.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@
99
//! Implementation for Fuchsia Zircon
1010
extern crate fuchsia_cprng;
1111

12-
use super::Error;
12+
use std::num::NonZeroU32;
13+
use Error;
1314

1415
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
1516
fuchsia_cprng::cprng_draw(dest);
1617
Ok(())
1718
}
19+
20+
#[inline(always)]
21+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ extern crate wasm_bindgen;
111111
feature = "stdweb"))]
112112
#[macro_use] extern crate stdweb;
113113

114+
#[cfg(feature = "log")] #[macro_use] extern crate log;
115+
#[allow(unused)]
116+
#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () }
117+
114118
#[cfg(any(
115119
target_os = "android",
116120
target_os = "netbsd",
@@ -124,8 +128,7 @@ extern crate wasm_bindgen;
124128
))]
125129
mod utils;
126130
mod error;
127-
pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR};
128-
131+
pub use error::{Error, ERROR_UNKNOWN, ERROR_UNAVAILABLE};
129132

130133
// System-specific implementations.
131134
//
@@ -136,7 +139,7 @@ macro_rules! mod_use {
136139
#[$cond]
137140
mod $module;
138141
#[$cond]
139-
use $module::getrandom_inner;
142+
use $module::{getrandom_inner, error_msg_inner};
140143
}
141144
}
142145

@@ -221,7 +224,7 @@ mod_use!(
221224
/// In general, `getrandom` will be fast enough for interactive usage, though
222225
/// significantly slower than a user-space CSPRNG; for the latter consider
223226
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
224-
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
227+
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
225228
getrandom_inner(dest)
226229
}
227230

src/linux_android.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
//! Implementation for Linux / Android
1010
extern crate libc;
1111

12-
use super::Error;
13-
use super::utils::use_init;
12+
use Error;
13+
use utils::use_init;
1414
use std::fs::File;
1515
use std::io;
1616
use std::io::Read;
1717
use std::cell::RefCell;
18+
use std::num::NonZeroU32;
1819
use std::sync::atomic::{AtomicBool, Ordering};
1920

2021
static RNG_INIT: AtomicBool = AtomicBool::new(false);
@@ -33,6 +34,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> {
3334
libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0)
3435
};
3536
if ret < 0 || (ret as usize) != dest.len() {
37+
error!("Linux getrandom syscall failed with return value {}", ret);
3638
return Err(io::Error::last_os_error());
3739
}
3840
Ok(())
@@ -80,3 +82,6 @@ fn is_getrandom_available() -> bool {
8082

8183
AVAILABLE.load(Ordering::Relaxed)
8284
}
85+
86+
#[inline(always)]
87+
pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }

0 commit comments

Comments
 (0)