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