Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.2: Error and Testing improvements #120

Merged
merged 10 commits into from
Oct 28, 2019
42 changes: 16 additions & 26 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ matrix:
- rustup target add aarch64-apple-ios
script:
- cargo test
- cargo test --examples
- cargo build --target aarch64-apple-ios

- name: "Linux, beta"
Expand All @@ -40,11 +39,11 @@ matrix:
# Get latest geckodriver
- export VERSION=$(curl -s https://api.github.com/repos/mozilla/geckodriver/releases/latest | jq -r ".tag_name")
- wget -O geckodriver.tar.gz https://github.com/mozilla/geckodriver/releases/download/$VERSION/geckodriver-$VERSION-linux64.tar.gz
- tar -xzf geckodriver.tar.gz
- tar -xzf geckodriver.tar.gz -C $HOME
# Get latest chromedirver
- export VERSION=$(wget -q -O - https://chromedriver.storage.googleapis.com/LATEST_RELEASE)
- wget -O chromedriver.zip https://chromedriver.storage.googleapis.com/$VERSION/chromedriver_linux64.zip
- unzip chromedriver.zip
- unzip chromedriver.zip -d $HOME
# Get cargo-web
- export VERSION=0.6.26 # Pin version for stability
- wget -O cargo-web.gz https://github.com/koute/cargo-web/releases/download/$VERSION/cargo-web-x86_64-unknown-linux-gnu.gz
Expand Down Expand Up @@ -76,44 +75,34 @@ matrix:
- cargo web test --target=wasm32-unknown-unknown --features=stdweb
# wasm-bindgen tests (Node, Firefox, Chrome)
- cargo test --target wasm32-unknown-unknown --features=wasm-bindgen
- GECKODRIVER=$PWD/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
- CHROMEDRIVER=$PWD/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
- GECKODRIVER=$HOME/geckodriver cargo test --target wasm32-unknown-unknown --features=test-in-browser
- CHROMEDRIVER=$HOME/chromedriver cargo test --target wasm32-unknown-unknown --features=test-in-browser

- name: "Linux, nightly, docs"
- &nightly_and_docs
name: "Linux, nightly, docs"
rust: nightly
os: linux
install:
- cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks
- cargo deadlinks -V
script:
# Check that our tests pass in the default configuration
- cargo test
- cargo test --benches
- cargo test --examples
# Check that setting various features does not break the build
- cargo build --features=std
- cargo build --features=log
# remove cached documentation, otherwise files from previous PRs can get included
- rm -rf target/doc
- cargo doc --no-deps --all --features=std,log
- cargo doc --no-deps --features=std
- cargo deadlinks --dir target/doc
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
- cargo test
- cargo test --features=std,log

- name: "OSX, nightly, docs"
rust: nightly
- <<: *nightly_and_docs
name: "OSX, nightly, docs"
os: osx
install:
- cargo --list | egrep "^\s*deadlinks$" -q || cargo install cargo-deadlinks
- cargo deadlinks -V
script:
- cargo test
- cargo test --benches
- cargo test --examples
# remove cached documentation, otherwise files from previous PRs can get included
- rm -rf target/doc
- cargo doc --no-deps --all --features=std,log
- cargo deadlinks --dir target/doc
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
- cargo test

- name: "cross-platform build only"
rust: nightly
Expand All @@ -139,6 +128,7 @@ matrix:
- cargo xbuild --target=x86_64-unknown-uefi
- cargo xbuild --target=x86_64-unknown-hermit
- cargo xbuild --target=x86_64-unknown-l4re-uclibc
- cargo xbuild --target=x86_64-uwp-windows-gnu
- cargo xbuild --target=x86_64-wrs-vxworks
# also test minimum dependency versions are usable
- cargo generate-lockfile -Z minimal-versions
Expand All @@ -153,6 +143,7 @@ matrix:
- cargo xbuild --target=x86_64-unknown-hermit
- cargo xbuild --target=x86_64-unknown-l4re-uclibc
- cargo xbuild --target=x86_64-uwp-windows-gnu
- cargo xbuild --target=x86_64-wrs-vxworks

# Trust cross-built/emulated targets. We must repeat all non-default values.
- name: "Linux (MIPS, big-endian)"
Expand Down Expand Up @@ -199,7 +190,6 @@ before_script:

script:
- cargo test
- cargo test --examples

after_script: set +e

Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "getrandom"
version = "0.1.12"
version = "0.2.0"
edition = "2018"
authors = ["The Rand Project Developers"]
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -41,3 +41,6 @@ std = []
rustc-dep-of-std = ["compiler_builtins", "core"]
# Unstable feature for testing
test-in-browser = ["wasm-bindgen"]

[package.metadata.docs.rs]
features = ["std"]
86 changes: 46 additions & 40 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,38 @@ use core::num::NonZeroU32;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Error(NonZeroU32);

// TODO: Convert to a function when min_version >= 1.33
macro_rules! internal_error {
($n:expr) => {
Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) })
};
}

impl Error {
#[deprecated(since = "0.1.7")]
/// Unknown error.
pub const UNKNOWN: Error = UNSUPPORTED;
#[deprecated(since = "0.1.7")]
/// System entropy source is unavailable.
pub const UNAVAILABLE: Error = UNSUPPORTED;
/// This target/platform is not supported by `getrandom`.
pub const UNSUPPORTED: Error = internal_error!(0);
/// The platform-specific `errno` returned a non-positive value.
pub const ERRNO_NOT_POSITIVE: Error = internal_error!(1);
/// Invalid conversion from a non-standard [`std::io::Error`](https://doc.rust-lang.org/std/io/struct.Error.html)
pub const UNKNOWN_IO_ERROR: Error = internal_error!(2);
/// Call to [`SecRandomCopyBytes`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes) failed.
pub const SEC_RANDOM_FAILED: Error = internal_error!(3);
/// Call to [`RtlGenRandom`](https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom) failed.
pub const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4);
/// RDRAND instruction failed due to a hardware issue.
pub const FAILED_RDRAND: Error = internal_error!(5);
/// RDRAND instruction unsupported on this target.
pub const NO_RDRAND: Error = internal_error!(6);
/// Using `wasm-bindgen`, browser does not support `self.crypto`.
pub const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
/// Using `wasm-bindgen`, browser does not support `crypto.getRandomValues`.
pub const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
/// Using `stdweb`, no cryptographic RNG is available.
pub const STDWEB_NO_RNG: Error = internal_error!(9);
/// Using `stdweb`, invoking a cryptographic RNG failed.
pub const STDWEB_RNG_FAILED: Error = internal_error!(10);
/// On VxWorks, random number generator is not yet initialized.
pub const RAND_SECURE_FATAL: Error = internal_error!(11);

/// Codes below this point represent OS Errors (i.e. positive i32 values).
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
Expand All @@ -38,9 +63,11 @@ impl Error {

/// Extract the raw OS error code (if this error came from the OS)
///
/// This method is identical to `std::io::Error::raw_os_error()`, except
/// This method is identical to [`std::io::Error::raw_os_error()`][1], except
/// that it works in `no_std` contexts. If this method returns `None`, the
/// error value can still be formatted via the `Display` implementation.
///
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
#[inline]
pub fn raw_os_error(self) -> Option<i32> {
if self.0.get() < Self::INTERNAL_START {
Expand Down Expand Up @@ -126,41 +153,20 @@ impl From<NonZeroU32> for Error {
}
}

// TODO: Convert to a function when min_version >= 1.33
macro_rules! internal_error {
($n:expr) => {
Error(unsafe { NonZeroU32::new_unchecked(Error::INTERNAL_START + $n as u16 as u32) })
};
}

/// Internal Error constants
pub(crate) const UNSUPPORTED: Error = internal_error!(0);
pub(crate) const ERRNO_NOT_POSITIVE: Error = internal_error!(1);
pub(crate) const UNKNOWN_IO_ERROR: Error = internal_error!(2);
pub(crate) const SEC_RANDOM_FAILED: Error = internal_error!(3);
pub(crate) const RTL_GEN_RANDOM_FAILED: Error = internal_error!(4);
pub(crate) const FAILED_RDRAND: Error = internal_error!(5);
pub(crate) const NO_RDRAND: Error = internal_error!(6);
pub(crate) const BINDGEN_CRYPTO_UNDEF: Error = internal_error!(7);
pub(crate) const BINDGEN_GRV_UNDEF: Error = internal_error!(8);
pub(crate) const STDWEB_NO_RNG: Error = internal_error!(9);
pub(crate) const STDWEB_RNG_FAILED: Error = internal_error!(10);
pub(crate) const RAND_SECURE_FATAL: Error = internal_error!(11);

fn internal_desc(error: Error) -> Option<&'static str> {
match error {
UNSUPPORTED => Some("getrandom: this target is not supported"),
ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"),
SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"),
RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"),
FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
NO_RDRAND => Some("RDRAND: instruction not supported"),
BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"),
BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
RAND_SECURE_FATAL => Some("randSecure: random number generator module is not initialized"),
Error::UNSUPPORTED => Some("getrandom: this target is not supported"),
Error::ERRNO_NOT_POSITIVE => Some("errno: did not return a positive value"),
Error::UNKNOWN_IO_ERROR => Some("Unknown std::io::Error"),
Error::SEC_RANDOM_FAILED => Some("SecRandomCopyBytes: call failed"),
Error::RTL_GEN_RANDOM_FAILED => Some("RtlGenRandom: call failed"),
Error::FAILED_RDRAND => Some("RDRAND: failed multiple times: CPU issue likely"),
Error::NO_RDRAND => Some("RDRAND: instruction not supported"),
Error::BINDGEN_CRYPTO_UNDEF => Some("wasm-bindgen: self.crypto is undefined"),
Error::BINDGEN_GRV_UNDEF => Some("wasm-bindgen: crypto.getRandomValues is undefined"),
Error::STDWEB_NO_RNG => Some("stdweb: no randomness source available"),
Error::STDWEB_RNG_FAILED => Some("stdweb: failed to get randomness"),
Error::RAND_SECURE_FATAL => Some("randSecure: VxWorks RNG module is not initialized"),
_ => None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/error_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// except according to those terms.
extern crate std;

use crate::{error::UNKNOWN_IO_ERROR, Error};
use crate::Error;
use core::convert::From;
use core::num::NonZeroU32;
use std::io;
Expand All @@ -19,7 +19,7 @@ impl From<io::Error> for Error {
return Error::from(code);
}
}
UNKNOWN_IO_ERROR
Error::UNKNOWN_IO_ERROR
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// except according to those terms.

//! Implementation for iOS
use crate::{error::SEC_RANDOM_FAILED, Error};
use crate::Error;

// TODO: Make extern once extern_types feature is stabilized. See:
// https://github.com/rust-lang/rust/issues/43467
Expand All @@ -24,7 +24,7 @@ extern "C" {
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, dest.len(), dest.as_mut_ptr()) };
if ret == -1 {
Err(SEC_RANDOM_FAILED)
Err(Error::SEC_RANDOM_FAILED)
} else {
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ cfg_if! {
/// In general, `getrandom` will be fast enough for interactive usage, though
/// significantly slower than a user-space CSPRNG; for the latter consider
/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html).
pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> {
pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
if dest.is_empty() {
return Ok(());
}
Expand Down
5 changes: 2 additions & 3 deletions src/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
// except according to those terms.

//! Implementation for SGX using RDRAND instruction
use crate::error::{FAILED_RDRAND, NO_RDRAND};
#[cfg(not(target_feature = "rdrand"))]
use crate::util::LazyBool;
use crate::Error;
Expand Down Expand Up @@ -37,7 +36,7 @@ unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
// Keep looping in case this was a false positive.
}
}
Err(FAILED_RDRAND)
Err(Error::FAILED_RDRAND)
}

// "rdrand" target feature requires "+rdrnd" flag, see https://github.com/rust-lang/rust/issues/49653.
Expand All @@ -64,7 +63,7 @@ fn is_rdrand_supported() -> bool {

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
if !is_rdrand_supported() {
return Err(NO_RDRAND);
return Err(Error::NO_RDRAND);
}

// SAFETY: After this point, rdrand is supported, so calling the rdrand
Expand Down
3 changes: 1 addition & 2 deletions src/util_libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(dead_code)]
use crate::error::ERRNO_NOT_POSITIVE;
use crate::util::LazyUsize;
use crate::Error;
use core::num::NonZeroU32;
Expand Down Expand Up @@ -34,7 +33,7 @@ pub fn last_os_error() -> Error {
if errno > 0 {
Error::from(NonZeroU32::new(errno as u32).unwrap())
} else {
ERRNO_NOT_POSITIVE
Error::ERRNO_NOT_POSITIVE
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/vxworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
// except according to those terms.

//! Implementation for VxWorks
use crate::error::{Error, RAND_SECURE_FATAL};
use crate::util_libc::last_os_error;
use crate::Error;
use core::sync::atomic::{AtomicBool, Ordering::Relaxed};

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
while !RNG_INIT.load(Relaxed) {
let ret = unsafe { libc::randSecure() };
if ret < 0 {
return Err(RAND_SECURE_FATAL);
return Err(Error::RAND_SECURE_FATAL);
} else if ret > 0 {
RNG_INIT.store(true, Relaxed);
break;
Expand Down
5 changes: 2 additions & 3 deletions src/wasm32_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use std::thread_local;

use wasm_bindgen::prelude::*;

use crate::error::{BINDGEN_CRYPTO_UNDEF, BINDGEN_GRV_UNDEF};
use crate::Error;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -66,13 +65,13 @@ fn getrandom_init() -> Result<RngSource, Error> {

let crypto = self_.crypto();
if crypto.is_undefined() {
return Err(BINDGEN_CRYPTO_UNDEF);
return Err(Error::BINDGEN_CRYPTO_UNDEF);
}

// Test if `crypto.getRandomValues` is undefined as well
let crypto: BrowserCrypto = crypto.into();
if crypto.get_random_values_fn().is_undefined() {
return Err(BINDGEN_GRV_UNDEF);
return Err(Error::BINDGEN_GRV_UNDEF);
}

return Ok(RngSource::Browser(crypto));
Expand Down
7 changes: 3 additions & 4 deletions src/wasm32_stdweb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
extern crate std;

use core::mem;
use std::sync::Once;

use stdweb::js;
use stdweb::unstable::TryInto;
use stdweb::web::error::Error as WebError;

use crate::error::{STDWEB_NO_RNG, STDWEB_RNG_FAILED};
use crate::Error;
use std::sync::Once;

#[derive(Clone, Copy, Debug)]
enum RngSource {
Expand Down Expand Up @@ -71,7 +70,7 @@ fn getrandom_init() -> Result<RngSource, Error> {
} else {
let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
error!("getrandom unavailable: {}", _err);
Err(STDWEB_NO_RNG)
Err(Error::STDWEB_NO_RNG)
}
}

Expand Down Expand Up @@ -107,7 +106,7 @@ fn getrandom_fill(source: RngSource, dest: &mut [u8]) -> Result<(), Error> {
if js! { return @{ result.as_ref() }.success } != true {
let _err: WebError = js! { return @{ result }.error }.try_into().unwrap();
error!("getrandom failed: {}", _err);
return Err(STDWEB_RNG_FAILED);
return Err(Error::STDWEB_RNG_FAILED);
}
}
Ok(())
Expand Down
Loading