From d2cd70bf53710a8f7feaeb5f22dedb10b2df993f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 4 Nov 2022 21:22:31 +0800 Subject: [PATCH] Minor stylistic fixes. --- CHANGELOG.md | 6 +-- build.template | 3 +- src/config/hashing.rs | 104 ++++++++++++++++++++++++++------------ src/config/hashing_env.rs | 3 +- src/config/mod.rs | 2 +- 5 files changed, 79 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6f6d5c7..f73ee408 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,11 @@ New features * Normal loops return `()` as the value. * Loop expressions can be enabled/disabled via `Engine::set_allow_loop_expressions` -### Stable hashing +### Static hashing -* It is now possible to specify a fixed _seed_ for use with the `ahash` hasher, via an environment variable, in order to force stable (i.e. deterministic) hashes for function signatures. +* It is now possible to specify a fixed _seed_ for use with the `ahash` hasher, via a static function `rhai::config::hashing::set_ahash_seed` or an environment variable, in order to force static (i.e. deterministic) hashes for function signatures. * This is necessary when using Rhai across shared-library boundaries. -* A build script is used to extract the environment variable (`RHAI_AHASH_SEED`) and splice it into the source code before compilation. +* A build script is used to extract the environment variable (`RHAI_AHASH_SEED`, if any) and splice it into the source code before compilation. ### No Timestamps diff --git a/build.template b/build.template index a165e5ed..bce322e8 100644 --- a/build.template +++ b/build.template @@ -1,2 +1,3 @@ -// This file is automatically set during build time by build.rs and build.template. +//! This file is automatically recreated during build time by `build.rs` from `build.template`. + pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; diff --git a/src/config/hashing.rs b/src/config/hashing.rs index 2355a405..58374d21 100644 --- a/src/config/hashing.rs +++ b/src/config/hashing.rs @@ -2,18 +2,30 @@ //! //! Set to [`None`] to disable stable hashing. //! -//! See [`set_rhai_ahash_seed`] for more. +//! See [`set_rhai_ahash_seed`]. //! -//! Alternatively, You can also set this at compile time by setting the `RHAI_AHASH_SEED` -//! environment variable instead. +//! # Example //! -//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +//! ```rust +//! // Set the hashing seed to [1, 2, 3, 4] +//! rhai::config::hashing::set_ahash_seed(Some([1, 2, 3, 4])).unwrap(); +//! ``` +//! Alternatively, set this at compile time via the `RHAI_AHASH_SEED` environment variable. +//! +//! # Example +//! +//! ```sh +//! env RHAI_AHASH_SEED ="[236,800,954,213]" +//! ``` // [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 use crate::config::hashing_env; -use core::{ +#[cfg(feature = "no_std")] +use std::prelude::v1::*; +use std::{ cell::UnsafeCell, marker::PhantomData, + mem, mem::MaybeUninit, panic::{RefUnwindSafe, UnwindSafe}, sync::atomic::{AtomicBool, AtomicUsize, Ordering}, @@ -23,23 +35,25 @@ use core::{ // what does this do? // so what this does is keep track of a global address in memory that acts as a global lock // i stole this from crossbeam so read their docs for more +#[must_use] struct HokmaLock { lock: AtomicUsize, } impl HokmaLock { + #[inline(always)] pub const fn new() -> Self { Self { lock: AtomicUsize::new(0), } } - pub fn write(&'static self) -> WhenTheHokmaSupression { + pub fn write(&'static self) -> WhenTheHokmaSuppression { loop { let previous = self.lock.swap(1, Ordering::SeqCst); if previous != 1 { - return WhenTheHokmaSupression { + return WhenTheHokmaSuppression { hokma: self, state: previous, }; @@ -48,21 +62,21 @@ impl HokmaLock { } } -struct WhenTheHokmaSupression { +struct WhenTheHokmaSuppression { hokma: &'static HokmaLock, - state: usize, } -impl WhenTheHokmaSupression { +impl WhenTheHokmaSuppression { + #[inline] pub fn the_price_of_silence(self) { self.hokma.lock.store(self.state, Ordering::SeqCst); - - core::mem::forget(self) + mem::forget(self) } } -impl Drop for WhenTheHokmaSupression { +impl Drop for WhenTheHokmaSuppression { + #[inline] fn drop(&mut self) { self.hokma .lock @@ -70,6 +84,8 @@ impl Drop for WhenTheHokmaSupression { } } +#[inline(always)] +#[must_use] fn hokmalock(address: usize) -> &'static HokmaLock { const LEN: usize = 787; const LCK: HokmaLock = HokmaLock::new(); @@ -79,11 +95,12 @@ fn hokmalock(address: usize) -> &'static HokmaLock { } // Safety: lol, there is a reason its called "SusLock" +#[must_use] struct SusLock where T: 'static + Copy, { - initalized: AtomicBool, + initialized: AtomicBool, data: UnsafeCell>, _marker: PhantomData, } @@ -92,17 +109,19 @@ impl SusLock where T: 'static + Copy, { + #[inline] pub const fn new() -> SusLock { SusLock { - initalized: AtomicBool::new(false), + initialized: AtomicBool::new(false), data: UnsafeCell::new(MaybeUninit::uninit()), _marker: PhantomData, } } + #[must_use] pub fn get(&self) -> Option { - if self.initalized.load(Ordering::SeqCst) { - let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); + if self.initialized.load(Ordering::SeqCst) { + let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) }); // we forgo the optimistic read, because we don't really care let guard = hokma.write(); let val = { @@ -116,11 +135,12 @@ where } } + #[must_use] pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option { let value = f(); - if !self.initalized.load(Ordering::SeqCst) { - self.initalized.store(true, Ordering::SeqCst); - let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); + if !self.initialized.load(Ordering::SeqCst) { + self.initialized.store(true, Ordering::SeqCst); + let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) }); hokma.write(); unsafe { self.data.get().write(MaybeUninit::new(value)); @@ -131,7 +151,7 @@ where } pub fn set(&self, value: T) -> Result<(), T> { - if self.initalized.load(Ordering::SeqCst) { + if self.initialized.load(Ordering::SeqCst) { Err(value) } else { let _ = self.get_or_init(|| value); @@ -148,8 +168,9 @@ impl Drop for SusLock where T: 'static + Copy, { + #[inline] fn drop(&mut self) { - if self.initalized.load(Ordering::SeqCst) { + if self.initialized.load(Ordering::SeqCst) { unsafe { (&mut *self.data.get()).assume_init_drop() }; } } @@ -157,27 +178,44 @@ where static AHASH_SEED: SusLock> = SusLock::new(); -// #[doc(cfg(feature = "stable_hash"))] -/// Sets the Rhai Ahash seed. This is used to hash functions and the like. +/// Set the hashing seed. This is used to hash functions etc. /// -/// This is a global variable, and thus will affect every Rhai instance. +/// This is a static global value and affects every Rhai instance. /// This should not be used _unless_ you know you need it. /// -/// # Warnings -/// - You can only call this function **ONCE** for the whole of your program execution. -/// - You should gracefully handle the `Err(())`. -/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +/// # Warning /// -/// # Errors -/// This will error if the AHashSeed is already set. +/// * You can only call this function **ONCE** for the entire duration of program execution. +/// * You **MUST** call this before performing **ANY** Rhai operation (e.g. creating an [`Engine`]). +/// +/// # Error +/// +/// Returns an error containing the existing hashing seed if already set. +/// +/// # Example +/// +/// ```rust +/// # use rhai::Engine; +/// // Set the hashing seed to [1, 2, 3, 4] +/// rhai::config::hashing::set_ahash_seed(Some([1, 2, 3, 4])).unwrap(); +/// +/// // Use Rhai AFTER setting the hashing seed +/// let engine = Engine::new(); +/// ``` +#[inline(always)] pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { AHASH_SEED.set(new_seed) } -/// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. -/// The default seed is not stable and may change between versions. +/// Get the current hashing Seed. +/// +/// If the seed is not yet defined, the `RHAI_AHASH_SEED` environment variable (if any) is used. +/// +/// Otherwise, the hashing seed is randomized to protect against DOS attacks. /// /// See [`set_rhai_ahash_seed`] for more. +#[inline] +#[must_use] pub fn get_ahash_seed() -> Option<[u64; 4]> { AHASH_SEED.get_or_init(|| hashing_env::AHASH_SEED).flatten() } diff --git a/src/config/hashing_env.rs b/src/config/hashing_env.rs index ee2b35db..59930ad8 100644 --- a/src/config/hashing_env.rs +++ b/src/config/hashing_env.rs @@ -1,2 +1,3 @@ -// This file is automatically set during build time by build.rs and build.template. +//! This file is automatically recreated during build time by `build.rs` from `build.template`. + pub(crate) const AHASH_SEED: Option<[u64; 4]> = None; diff --git a/src/config/mod.rs b/src/config/mod.rs index db5448f6..35aac0af 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,4 +1,4 @@ -//! Contains Configuration for Rhai. +//! Configuration for Rhai. pub mod hashing; mod hashing_env;