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

Use configuration flags to switch between backends #504

Merged
merged 12 commits into from
Oct 7, 2024
Merged
83 changes: 62 additions & 21 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ jobs:
toolchain: ${{ matrix.toolchain }}
- uses: Swatinem/rust-cache@v2
- run: cargo test
# Make sure enabling the std and custom features don't break anything
- run: cargo test --features=std,custom
- run: cargo test --features=linux_disable_fallback
# Make sure enabling the std feature doesn't break anything
- run: cargo test --features=std
- if: ${{ matrix.toolchain == 'nightly' }}
run: cargo test --benches

Expand Down Expand Up @@ -69,6 +68,12 @@ jobs:
sudo apt-get install --no-install-recommends ${{ matrix.packages }}
- uses: Swatinem/rust-cache@v2
- run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo test ${{ matrix.cargo_test_opts }} --target=${{ matrix.target }} --features=std
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
run: cargo test --features=std

ios-tests:
name: iOS Simulator Test
Expand Down Expand Up @@ -242,21 +247,27 @@ jobs:
wasm-pack --version
- uses: Swatinem/rust-cache@v2
- name: Test (Node)
run: wasm-pack test --node --features=js
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
run: wasm-pack test --node
- name: Test (Firefox)
run: wasm-pack test --headless --firefox --features=js,test-in-browser
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test
run: wasm-pack test --headless --firefox
- name: Test (Chrome)
run: wasm-pack test --headless --chrome --features=js,test-in-browser
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test
run: wasm-pack test --headless --chrome
- name: Test (Edge)
if: runner.os == 'Windows'
run: wasm-pack test --headless --chrome --chromedriver $Env:EDGEWEBDRIVER\msedgedriver.exe --features=js,test-in-browser
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test
run: wasm-pack test --headless --chrome --chromedriver $Env:EDGEWEBDRIVER\msedgedriver.exe
- name: Test (Safari)
if: runner.os == 'macOS'
run: wasm-pack test --headless --safari --features=js,test-in-browser
- name: Test (custom getrandom)
run: wasm-pack test --node --features=custom
- name: Test (JS overrides custom)
run: wasm-pack test --node --features=custom,js
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test
run: wasm-pack test --headless --safari

wasm64-tests:
name: wasm64 Build/Link
Expand All @@ -268,10 +279,12 @@ jobs:
components: rust-src
- uses: Swatinem/rust-cache@v2
- name: Build and Link tests (build-std)
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js" --cfg getrandom_browser_test
# This target is Tier 3, so we have to build libstd ourselves.
# We currently cannot run these tests because wasm-bindgen-test-runner
# does not yet support memory64.
run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown --features=js
run: cargo test --no-run -Z build-std=std,panic_abort --target=wasm64-unknown-unknown

wasi-tests:
name: WASI Tests
Expand Down Expand Up @@ -325,24 +338,18 @@ jobs:
aarch64-kmc-solid_asp3,
armv6k-nintendo-3ds,
armv7-sony-vita-newlibeabihf,
riscv32imc-esp-espidf,
aarch64-unknown-nto-qnx710,
]
# Supported tier 3 targets with libstd support
include:
- target: aarch64-unknown-nto-qnx710
features: ["std"]
# Supported tier 3 targets with libstd support
- target: x86_64-unknown-openbsd
features: ["std"]
- target: x86_64-unknown-dragonfly
features: ["std"]
- target: x86_64-unknown-haiku
features: ["std"]
# Unsupported tier 3 targets to test the rdrand feature
- target: x86_64-unknown-uefi
features: ["rdrand"]
- target: x86_64-unknown-l4re-uclibc
features: ["rdrand"]
- target: i686-unknown-hurd-gnu
features: ["std"]
steps:
Expand All @@ -353,6 +360,38 @@ jobs:
- uses: Swatinem/rust-cache@v2
- run: cargo build -Z build-std=${{ contains(matrix.features, 'std') && 'std' || 'core'}} --target=${{ matrix.target }} --features="${{ join(matrix.features, ',') }}"

build-rdrand:
name: RDRAND Build
runs-on: ubuntu-22.04
strategy:
matrix:
target: [
x86_64-unknown-uefi,
x86_64-unknown-l4re-uclibc,
]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly # Required to build libcore
with:
components: rust-src
- uses: Swatinem/rust-cache@v2
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="rdrand"
run: cargo build -Z build-std=core --target=${{ matrix.target }}

build-esp-idf:
name: ESP-IDF Build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly # Required to build libcore
with:
components: rust-src
- uses: Swatinem/rust-cache@v2
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf"
run: cargo build -Z build-std=core --target=riscv32imc-esp-espidf

build-no-atomics:
name: No Atomics Build
runs-on: ubuntu-22.04
Expand All @@ -362,4 +401,6 @@ jobs:
with:
targets: riscv32i-unknown-none-elf
- uses: Swatinem/rust-cache@v2
- run: cargo build --features custom --target riscv32i-unknown-none-elf
- env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom"
run: cargo build --target riscv32i-unknown-none-elf
18 changes: 13 additions & 5 deletions .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@ jobs:
components: clippy,rust-src
- name: std feature
run: cargo clippy --features std
- name: custom feature
run: cargo clippy -Zbuild-std=core --target riscv32i-unknown-none-elf --features custom
- name: custom backend
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="custom"
run: cargo clippy -Zbuild-std=core --target riscv32i-unknown-none-elf
- name: iOS (apple-other.rs)
run: cargo clippy -Zbuild-std=core --target x86_64-apple-ios
- name: ESP-IDF (espidf.rs)
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="esp_idf"
run: cargo clippy -Zbuild-std=core --target riscv32imc-esp-espidf
- name: Fuchsia (fuchsia.rs)
run: cargo clippy -Zbuild-std=core --target x86_64-unknown-fuchsia
Expand All @@ -42,9 +46,13 @@ jobs:
- name: Hermit (hermit.rs)
run: cargo clippy -Zbuild-std=core --target x86_64-unknown-hermit
- name: Web WASM (js.rs)
run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown --features js
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="wasm_js"
run: cargo clippy -Zbuild-std --target wasm32-unknown-unknown
- name: Linux (linux_android.rs)
run: cargo clippy --target x86_64-unknown-linux-gnu --features linux_disable_fallback
env:
RUSTFLAGS: -Dwarnings --cfg getrandom_backend="linux_getrandom"
run: cargo clippy --target x86_64-unknown-linux-gnu
- name: Linux (linux_android_with_fallback.rs)
run: cargo clippy --target x86_64-unknown-linux-gnu
- name: NetBSD (netbsd.rs)
Expand Down Expand Up @@ -93,4 +101,4 @@ jobs:
- name: Generate Docs
env:
RUSTDOCFLAGS: "-Dwarnings --cfg docsrs"
run: cargo doc --no-deps --features custom
run: cargo doc --no-deps --features std
30 changes: 11 additions & 19 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,27 @@ wasi = { version = "0.13", default-features = false }
[target.'cfg(all(windows, not(target_vendor = "win7")))'.dependencies]
windows-targets = "0.52"

[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.89", default-features = false, optional = true }
js-sys = { version = "0.3", optional = true }
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies]
[target.'cfg(all(getrandom_backend = "wasm_js", any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.89", default-features = false }
js-sys = "0.3"
[target.'cfg(all(getrandom_backend = "wasm_js", getrandom_browser_test, any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies]
wasm-bindgen-test = "0.3.39"

[features]
# Implement std-only traits for getrandom::Error
std = []
# Disable `/dev/urandom` fallback for Linux and Android targets.
# Bumps minimum supported Linux kernel version to 3.17 and Android API level to 23 (Marshmallow).
linux_disable_fallback = []
# Feature to enable fallback RDRAND-based implementation on x86/x86_64
rdrand = []
# Feature to enable JavaScript bindings on wasm*-unknown-unknown
js = ["wasm-bindgen", "js-sys"]
# Feature to enable custom RNG implementations
custom = []
# Unstable feature to support being a libstd dependency
rustc-dep-of-std = ["compiler_builtins", "core"]
# Unstable/test-only feature to run wasm-bindgen tests in a browser
test-in-browser = []

[[test]]
name = "custom"
required-features = ["custom"]
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
'cfg(getrandom_backend, values("custom", "rdrand", "linux_getrandom", "wasm_js", "esp_idf"))',
'cfg(getrandom_browser_test)',
]

[package.metadata.docs.rs]
features = ["std", "custom"]
features = ["std"]
rustdoc-args = ["--cfg", "docsrs"]

# workaround for https://github.com/cross-rs/cross/issues/1345
Expand Down
95 changes: 2 additions & 93 deletions src/custom.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,12 @@
//! An implementation which calls out to an externally defined function.
use crate::{util::uninit_slice_fill_zero, Error};
use crate::Error;
use core::{mem::MaybeUninit, num::NonZeroU32};

/// Register a function to be invoked by `getrandom` on unsupported targets.
///
/// ## Writing a custom `getrandom` implementation
///
/// The function to register must have the same signature as
/// [`getrandom::getrandom`](crate::getrandom). The function can be defined
/// wherever you want, either in root crate or a dependent crate.
///
/// For example, if we wanted a `failure-getrandom` crate containing an
/// implementation that always fails, we would first depend on `getrandom`
/// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`:
/// ```toml
/// [dependencies]
/// getrandom = "0.2"
/// ```
/// Note that the crate containing this function does **not** need to enable the
/// `"custom"` Cargo feature.
///
/// Next, in `failure-getrandom/src/lib.rs`, we define our function:
/// ```rust
/// use core::num::NonZeroU32;
/// use getrandom::Error;
///
/// // Some application-specific error code
/// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42;
/// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> {
/// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap();
/// Err(Error::from(code))
/// }
/// ```
///
/// ## Registering a custom `getrandom` implementation
///
/// Functions can only be registered in the root binary crate. Attempting to
/// register a function in a non-root crate will result in a linker error.
/// This is similar to
/// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
/// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
/// where helper crates define handlers/allocators but only the binary crate
/// actually _uses_ the functionality.
///
/// To register the function, we first depend on `failure-getrandom` _and_
/// `getrandom` in `Cargo.toml`:
/// ```toml
/// [dependencies]
/// failure-getrandom = "0.1"
/// getrandom = { version = "0.2", features = ["custom"] }
/// ```
///
/// Then, we register the function in `src/main.rs`:
/// ```rust
/// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } }
/// use failure_getrandom::always_fail;
/// use getrandom::register_custom_getrandom;
///
/// register_custom_getrandom!(always_fail);
/// ```
///
/// Now any user of `getrandom` (direct or indirect) on this target will use the
/// registered function. As noted in the
/// [top-level documentation](index.html#custom-implementations) this
/// registration only has an effect on unsupported targets.
#[macro_export]
macro_rules! register_custom_getrandom {
($path:path) => {
// TODO(MSRV 1.37): change to unnamed block
const __GETRANDOM_INTERNAL: () = {
// We use Rust ABI to be safe against potential panics in the passed function.
#[no_mangle]
unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
// Make sure the passed function has the type of getrandom::getrandom
type F = fn(&mut [u8]) -> ::core::result::Result<(), $crate::Error>;
let _: F = $crate::getrandom;
let f: F = $path;
let slice = ::core::slice::from_raw_parts_mut(dest, len);
match f(slice) {
Ok(()) => 0,
Err(e) => e.code().get(),
}
}
};
};
}

#[allow(dead_code)]
pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
extern "Rust" {
fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
}
// Previously we always passed a valid, initialized slice to
// `__getrandom_custom`. Ensure `dest` has been initialized for backward
// compatibility with implementations that rely on that (e.g. Rust
// implementations that construct a `&mut [u8]` slice from `dest` and
// `len`).
let dest = uninit_slice_fill_zero(dest);
let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
let ret = unsafe { __getrandom_custom(dest.as_mut_ptr().cast(), dest.len()) };
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in v0.3 we no longer need to zeroize the destination buffer since we can specify that uninitialized buffers may be passed to __getrandom_custom.

We also probably could use NonZeroUsize for len to improve code generation for __getrandom_custom provider.

match NonZeroU32::new(ret) {
None => Ok(()),
Some(code) => Err(Error::from(code)),
Expand Down
Loading
Loading