1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! An implementation which calls out to an externally defined function.
use crate::{util::uninit_slice_fill_zero, 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]
#[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
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()) };
match NonZeroU32::new(ret) {
None => Ok(()),
Some(code) => Err(Error::from(code)),
}
}
|