1 //! An implementation which calls out to an externally defined function.
2 use crate::{util::uninit_slice_fill_zero, Error};
3 use core::{mem::MaybeUninit, num::NonZeroU32};
4
5 /// Register a function to be invoked by `getrandom` on unsupported targets.
6 ///
7 /// ## Writing a custom `getrandom` implementation
8 ///
9 /// The function to register must have the same signature as
10 /// [`getrandom::getrandom`](crate::getrandom). The function can be defined
11 /// wherever you want, either in root crate or a dependent crate.
12 ///
13 /// For example, if we wanted a `failure-getrandom` crate containing an
14 /// implementation that always fails, we would first depend on `getrandom`
15 /// (for the [`Error`] type) in `failure-getrandom/Cargo.toml`:
16 /// ```toml
17 /// [dependencies]
18 /// getrandom = "0.2"
19 /// ```
20 /// Note that the crate containing this function does **not** need to enable the
21 /// `"custom"` Cargo feature.
22 ///
23 /// Next, in `failure-getrandom/src/lib.rs`, we define our function:
24 /// ```rust
25 /// use core::num::NonZeroU32;
26 /// use getrandom::Error;
27 ///
28 /// // Some application-specific error code
29 /// const MY_CUSTOM_ERROR_CODE: u32 = Error::CUSTOM_START + 42;
30 /// pub fn always_fail(buf: &mut [u8]) -> Result<(), Error> {
31 /// let code = NonZeroU32::new(MY_CUSTOM_ERROR_CODE).unwrap();
32 /// Err(Error::from(code))
33 /// }
34 /// ```
35 ///
36 /// ## Registering a custom `getrandom` implementation
37 ///
38 /// Functions can only be registered in the root binary crate. Attempting to
39 /// register a function in a non-root crate will result in a linker error.
40 /// This is similar to
41 /// [`#[panic_handler]`](https://doc.rust-lang.org/nomicon/panic-handler.html) or
42 /// [`#[global_allocator]`](https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html),
43 /// where helper crates define handlers/allocators but only the binary crate
44 /// actually _uses_ the functionality.
45 ///
46 /// To register the function, we first depend on `failure-getrandom` _and_
47 /// `getrandom` in `Cargo.toml`:
48 /// ```toml
49 /// [dependencies]
50 /// failure-getrandom = "0.1"
51 /// getrandom = { version = "0.2", features = ["custom"] }
52 /// ```
53 ///
54 /// Then, we register the function in `src/main.rs`:
55 /// ```rust
56 /// # mod failure_getrandom { pub fn always_fail(_: &mut [u8]) -> Result<(), getrandom::Error> { unimplemented!() } }
57 /// use failure_getrandom::always_fail;
58 /// use getrandom::register_custom_getrandom;
59 ///
60 /// register_custom_getrandom!(always_fail);
61 /// ```
62 ///
63 /// Now any user of `getrandom` (direct or indirect) on this target will use the
64 /// registered function. As noted in the
65 /// [top-level documentation](index.html#custom-implementations) this
66 /// registration only has an effect on unsupported targets.
67 #[macro_export]
68 #[cfg_attr(docsrs, doc(cfg(feature = "custom")))]
69 macro_rules! register_custom_getrandom {
70 ($path:path) => {
71 // TODO(MSRV 1.37): change to unnamed block
72 const __GETRANDOM_INTERNAL: () = {
73 // We use Rust ABI to be safe against potential panics in the passed function.
74 #[no_mangle]
75 unsafe fn __getrandom_custom(dest: *mut u8, len: usize) -> u32 {
76 // Make sure the passed function has the type of getrandom::getrandom
77 type F = fn(&mut [u8]) -> ::core::result::Result<(), $crate::Error>;
78 let _: F = $crate::getrandom;
79 let f: F = $path;
80 let slice = ::core::slice::from_raw_parts_mut(dest, len);
81 match f(slice) {
82 Ok(()) => 0,
83 Err(e) => e.code().get(),
84 }
85 }
86 };
87 };
88 }
89
90 #[allow(dead_code)]
getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error>91 pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
92 extern "Rust" {
93 fn __getrandom_custom(dest: *mut u8, len: usize) -> u32;
94 }
95 // Previously we always passed a valid, initialized slice to
96 // `__getrandom_custom`. Ensure `dest` has been initialized for backward
97 // compatibility with implementations that rely on that (e.g. Rust
98 // implementations that construct a `&mut [u8]` slice from `dest` and
99 // `len`).
100 let dest = uninit_slice_fill_zero(dest);
101 let ret = unsafe { __getrandom_custom(dest.as_mut_ptr(), dest.len()) };
102 match NonZeroU32::new(ret) {
103 None => Ok(()),
104 Some(code) => Err(Error::from(code)),
105 }
106 }
107