diff --git a/CHANGELOG.md b/CHANGELOG.md index 41d0861..5dc1bb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Bugfixes - Don't allow unsafe code in initialisation expression of `#[percore]` variables. +- Fixed undefined behaviour in `LinkedPerCore::get` due to pointer provenance. ## 0.2.5 diff --git a/src/derive.rs b/src/derive.rs index 5b1a813..09834a0 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -77,7 +77,7 @@ pub mod aarch64; use crate::lock::ExceptionLock; -use core::ptr::NonNull; +use core::ptr::with_exposed_provenance; pub use percore_derive::percore; #[allow(improper_ctypes)] @@ -181,9 +181,15 @@ impl LinkedPerCore { /// Returns a shared reference to the value for the current CPU core. #[inline(always)] pub fn get(&self) -> &T { - // SAFETY: PercoreLocalOffset guarantees a valid offset. - let percore_ptr = unsafe { NonNull::from_ref(&self.0).byte_offset(percore_local_offset()) }; + // We need to construct a new pointer with exposed provenance rather than just using + // `byte_offset` on the pointer to `self.0` because the per-core copy is not part of the + // same allocation. + let percore_ptr = with_exposed_provenance::( + ((&raw const self.0).expose_provenance().cast_signed() + percore_local_offset()) + .cast_unsigned(), + ); + debug_assert!(!percore_ptr.is_null()); debug_assert!(percore_ptr.is_aligned()); // SAFETY: @@ -191,13 +197,12 @@ impl LinkedPerCore { // and `&self.0` must be aligned as it comes from a reference, so adding the offset to it // must still be properly aligned. (In debug builds we also double-check with the // debug_assert above.) - // * The pointer is non-null because it is constructed from NonNull and the offset produces - // a valid address. + // * The pointer is non-null because the offset is guaranteed to produce a valid address. // * The PercoreLocalOffset implementation promises that the calculated pointer points into // * the percore memory area which is initialized and it is dereferenceable for the T type. // * Aliasing is prevented by each core having its own instance of the variable and by // requiring `ExceptionLock` for `Sync` implementation. - unsafe { percore_ptr.as_ref() } + unsafe { percore_ptr.as_ref_unchecked() } } }