├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── README.md └── src ├── func.rs ├── int.rs └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | rust: 20 | - 1.31.0 21 | - stable 22 | - beta 23 | - nightly 24 | 25 | steps: 26 | - uses: actions/checkout@v3 27 | - uses: actions-rs/toolchain@v1 28 | with: 29 | toolchain: ${{ matrix.rust }} 30 | override: true 31 | - name: Build 32 | run: cargo build --verbose 33 | - name: Run tests 34 | run: cargo test --verbose 35 | 36 | miri: 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v3 40 | - name: Install Miri 41 | run: | 42 | rustup toolchain install nightly --component miri 43 | rustup override set nightly 44 | cargo miri setup 45 | - name: Test with Miri 46 | run: cargo miri test 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sptr" 3 | version = "0.3.2" 4 | edition = "2018" 5 | license = "MIT OR Apache-2.0" 6 | description = "sptr: The Strict Provenance Polyfill" 7 | repository = "https://github.com/Gankra/sptr" 8 | 9 | [package.metadata.docs.rs] 10 | all-features = true 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | 16 | [features] 17 | default = [] 18 | uptr = [] 19 | opaque_fn = [] 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sptr: The Strict Provenance Polyfill 2 | 3 | [![crates.io](https://img.shields.io/crates/v/sptr.svg)](https://crates.io/crates/sptr) [![](https://docs.rs/sptr/badge.svg)](https://docs.rs/sptr) ![Rust CI](https://github.com/Gankra/sptr/workflows/Rust/badge.svg?branch=main) 4 | 5 | 6 | 7 | 8 | This library provides a stable polyfill for Rust's [Strict Provenance] experiment. 9 | 10 | # Mapping to STD APIs: 11 | 12 | This crate "overlays" a bunch of unstable std apis, here are the mappings: 13 | 14 | ## core::ptr (sptr) 15 | 16 | * `pub fn `[`invalid`]`(addr: usize) -> *const T;` 17 | * `pub fn `[`invalid_mut`]`(addr: usize) -> *mut T;` 18 | * `pub fn `[`from_exposed_addr`]`(addr: usize) -> *const T;` 19 | * `pub fn `[`from_exposed_addr_mut`]`(addr: usize) -> *mut T;` 20 | 21 | 22 | ## core::pointer (sptr::Strict) 23 | 24 | * `pub fn `[`addr`]`(self) -> usize;` 25 | * `pub fn `[`expose_addr`]`(self) -> usize;` 26 | * `pub fn `[`with_addr`]`(self, addr: usize) -> Self;` 27 | * `pub fn `[`map_addr`]`(self, f: impl FnOnce(usize) -> usize) -> Self;` 28 | 29 | 30 | ## NON-STANDARD EXTENSIONS (disabled by default, use at your own risk) 31 | 32 | * `sptr::`[`uptr`] (feature = uptr) 33 | * `sptr::`[`iptr`] (feature = uptr) 34 | * `sptr::`[`OpaqueFnPtr`] (feature = opaque_fn) 35 | 36 | 37 | 38 | 39 | # Applying The Overlay 40 | 41 | Swapping between sptr and core::ptr should be as simple as switching between `sptr::` and `ptr::` 42 | for static functions. For methods, you must import `sptr::Strict` into your module for 43 | the extension trait's methods to overlay std. The compiler will (understandably) 44 | complain that you are overlaying std, so you will need to also silence that as 45 | seen in the following example: 46 | 47 | ```rust 48 | #![allow(unstable_name_collisions)] 49 | use sptr::Strict; 50 | 51 | let ptr = sptr::invalid_mut::(1); 52 | println!("{}", ptr.addr()); 53 | ``` 54 | 55 | By default, this crate will also mark methods on pointers as "deprecated" if they are 56 | incompatible with strict_provenance. If you don't want this, set `default-features = false` 57 | in your Cargo.toml. 58 | 59 | Rust is the canonical source of definitions for these APIs and semantics, but the docs 60 | here will vaguely try to mirror the docs checked into Rust. 61 | 62 | 63 | [`invalid`]: https://docs.rs/sptr/latest/sptr/fn.invalid.html 64 | [`invalid_mut`]: https://docs.rs/sptr/latest/sptr/fn.invalid_mut.html 65 | [`from_exposed_addr`]: https://docs.rs/sptr/latest/sptr/fn.from_exposed_addr.html 66 | [`from_exposed_addr_mut`]: https://docs.rs/sptr/latest/sptr/fn.from_exposed_addr_mut.html 67 | [`addr`]: https://docs.rs/sptr/latest/sptr/trait.Strict.html#tymethod.addr 68 | [`expose_addr`]: https://docs.rs/sptr/latest/sptr/trait.Strict.html#tymethod.expose_addr 69 | [`with_addr`]: https://docs.rs/sptr/latest/sptr/trait.Strict.html#tymethod.with_addr 70 | [`map_addr`]: https://docs.rs/sptr/latest/sptr/trait.Strict.html#tymethod.map_addr 71 | [`uptr`]: https://docs.rs/sptr/latest/sptr/int/struct.uptr.html 72 | [`iptr`]: https://docs.rs/sptr/latest/sptr/int/struct.iptr.html 73 | [`OpaqueFnPtr`]: https://docs.rs/sptr/latest/sptr/func/struct.OpaqueFnPtr.html 74 | -------------------------------------------------------------------------------- /src/func.rs: -------------------------------------------------------------------------------- 1 | //! Tools for making it easier to use function pointers. 2 | 3 | /// The `void*` equivalent for a function pointer, for when you need to handle "some fn". 4 | /// 5 | /// Some platforms (WASM, AVR) have non-uniform representations for "code" and "data" pointers. 6 | /// Such platforms are referred to as "Harvard Architectures". 7 | /// 8 | /// Rust does not have a good way for talking about "some" function pointer, so it's pretty 9 | /// common to cast to a usize or a raw pointer to make it easier. The entire point of strict 10 | /// provenance is to make you not do usize casts, so obviously we're not a fan of that. But the 11 | /// other approach *also* isn't great because 12 | /// [Oxford Casts Are A Mess](https://github.com/rust-lang/rust/issues/95489). 13 | /// 14 | /// So really you *want* to stay in "definitely doing function pointers", which means you want 15 | /// a proper opaque function pointer type. This type *attempts* to be that but is honestly 16 | /// not very good at it, because it immediately runs into the exact problem it's trying to solve: 17 | /// Rust makes it really hard to talk about "some" function pointer, so we can't actually 18 | /// describe its interface! 19 | /// 20 | /// This really needs proper language support. 21 | /// 22 | /// (In the meantime, `func as usize` and `usize as func` are genuinely the less evil casts 23 | /// here! Don't do Oxford Casts if you want your code to be maximally portable!) 24 | #[repr(transparent)] 25 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 26 | pub struct OpaqueFnPtr(fn() -> ()); 27 | 28 | impl OpaqueFnPtr { 29 | /// Create an OpaqueFnPtr from some `fn`. 30 | /// 31 | /// Rust doesn't have a good way to express, so this just takes "anything" and it's 32 | /// up to you to make sure you're actually feeding in a function pointer. 33 | /// 34 | /// **If you feed in anything else, it is Undefined Behaviour.** 35 | #[inline] 36 | #[must_use] 37 | pub unsafe fn from_fn(func: T) -> Self { 38 | assert_eq!( 39 | core::mem::size_of::(), 40 | core::mem::size_of::() 41 | ); 42 | assert_eq!( 43 | core::mem::align_of::(), 44 | core::mem::align_of::() 45 | ); 46 | 47 | OpaqueFnPtr(core::mem::transmute_copy(&func)) 48 | } 49 | 50 | /// Create a `fn` from an OpaqueFnPtr. 51 | /// 52 | /// Rust doesn't have a good way to express, so this just takes "anything" and it's 53 | /// up to you to make sure you're actually feeding in a function pointer type. 54 | /// 55 | /// **If you feed in anything else, it is Undefined Behaviour.** 56 | #[inline] 57 | #[must_use] 58 | pub unsafe fn to_fn(self) -> T { 59 | assert_eq!( 60 | core::mem::size_of::(), 61 | core::mem::size_of::() 62 | ); 63 | assert_eq!( 64 | core::mem::align_of::(), 65 | core::mem::align_of::() 66 | ); 67 | 68 | core::mem::transmute_copy(&self.0) 69 | } 70 | 71 | /// Get the address of the function pointer. 72 | /// 73 | /// Note that while you *can* compare this to a data pointer, the result will 74 | /// almost certainly be meaningless, especially on platforms like WASM and AVR 75 | /// where function pointers are in a separate address-space from data pointers. 76 | /// 77 | /// See [`pointer::addr`][crate::Strict::addr] for details. 78 | #[inline] 79 | #[must_use] 80 | pub fn addr(self) -> usize { 81 | self.0 as usize 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/int.rs: -------------------------------------------------------------------------------- 1 | //! Pointers Pretending To Be Integers For Crimes -- [uptr][] and [iptr][]. 2 | 3 | #![allow(unstable_name_collisions)] 4 | use crate::Strict; 5 | 6 | /// A pointer that pretends to be an integer, for API Crimes. 7 | /// 8 | /// **Please don't use this type.** 9 | /// 10 | /// If you can't possibly satisfy strict provenance for whatever reason, you can at least 11 | /// use this type to make sure the compiler still understands that Pointers Are Happening. 12 | /// 13 | /// All operations on this type will derive provenance from the left-hand-size (lhs). 14 | /// So `x + y` has `x`'s provenance. *Many* operations are nonsensical if the pointer 15 | /// inside is a real pointer, but hey, you've reached for the "I Know What I'm Doing" 16 | /// lever, so we'll let you *say* whatever gibberish you want. 17 | /// 18 | /// Please submit a PR if you need some operation defined on usize to be exposed here. 19 | 20 | #[repr(transparent)] 21 | #[allow(non_camel_case_types)] 22 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 23 | pub struct uptr(*mut ()); 24 | 25 | /// A pointer that pretends to be an integer, for API Crimes. 26 | /// 27 | /// **Please don't use this type.** 28 | /// 29 | /// If you can't possibly satisfy strict provenance for whatever reason, you can at least 30 | /// use this type to make sure the compiler still understands that Pointers Are Happening. 31 | /// 32 | /// All operations on this type will derive provenance from the left-hand-size (lhs). 33 | /// So `x + y` has `x`'s provenance. *Many* operations are nonsensical if the pointer 34 | /// inside is a real pointer, but hey, you've reached for the "I Know What I'm Doing" 35 | /// lever, so we'll let you *say* whatever gibberish you want. 36 | /// 37 | /// Please submit a PR if you need some operation defined on isize to be exposed here. 38 | #[repr(transparent)] 39 | #[allow(non_camel_case_types)] 40 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 41 | pub struct iptr(*mut ()); 42 | 43 | macro_rules! int_impls { 44 | ($self_ty: ident, $int_ty: ident) => { 45 | impl $self_ty { 46 | // Inherent MIN/MAX requires 1.43 47 | // pub const MIN: $self_ty = Self::from_int(<$int_ty>::MIN); 48 | // pub const MAX: $self_ty = Self::from_int(<$int_ty>::MAX); 49 | pub const MIN: $self_ty = Self::from_int(core::$int_ty::MIN); 50 | pub const MAX: $self_ty = Self::from_int(core::$int_ty::MAX); 51 | 52 | // Inherent BITS requires 1.53 53 | // pub const BITS: u32 = <$int_ty>::BITS; 54 | pub const BITS: u32 = core::mem::size_of::<$int_ty>() as u32 * 8; 55 | 56 | #[inline] 57 | #[must_use] 58 | pub const fn from_int(val: $int_ty) -> Self { 59 | $self_ty(crate::invalid_mut(val as usize)) 60 | } 61 | 62 | #[inline] 63 | #[must_use] 64 | pub const fn from_ptr_mut(val: *mut T) -> Self { 65 | $self_ty(val as *mut ()) 66 | } 67 | 68 | #[inline] 69 | #[must_use] 70 | pub const fn from_ptr(val: *const T) -> Self { 71 | $self_ty(val as *const () as *mut ()) 72 | } 73 | 74 | pub const fn to_ptr(self) -> *mut () { 75 | self.0 76 | } 77 | 78 | #[inline] 79 | #[must_use] 80 | pub fn wrapping_add(self, rhs: Self) -> Self { 81 | $self_ty( 82 | self.0.map_addr(|a| { 83 | ((a as $int_ty).wrapping_add(rhs.0.addr() as $int_ty)) as usize 84 | }), 85 | ) 86 | } 87 | #[inline] 88 | #[must_use] 89 | pub fn wrapping_sub(self, rhs: Self) -> Self { 90 | $self_ty( 91 | self.0.map_addr(|a| { 92 | ((a as $int_ty).wrapping_sub(rhs.0.addr() as $int_ty)) as usize 93 | }), 94 | ) 95 | } 96 | #[inline] 97 | #[must_use] 98 | pub fn wrapping_mul(self, rhs: Self) -> Self { 99 | $self_ty( 100 | self.0.map_addr(|a| { 101 | ((a as $int_ty).wrapping_mul(rhs.0.addr() as $int_ty)) as usize 102 | }), 103 | ) 104 | } 105 | #[inline] 106 | #[must_use] 107 | pub fn wrapping_div(self, rhs: Self) -> Self { 108 | $self_ty( 109 | self.0.map_addr(|a| { 110 | ((a as $int_ty).wrapping_div(rhs.0.addr() as $int_ty)) as usize 111 | }), 112 | ) 113 | } 114 | } 115 | 116 | impl From<$int_ty> for $self_ty { 117 | #[inline] 118 | #[must_use] 119 | fn from(val: $int_ty) -> Self { 120 | $self_ty(crate::invalid_mut(val as usize)) 121 | } 122 | } 123 | impl From<*mut T> for $self_ty { 124 | #[inline] 125 | #[must_use] 126 | fn from(val: *mut T) -> Self { 127 | $self_ty(val as *mut ()) 128 | } 129 | } 130 | impl From<*const T> for $self_ty { 131 | #[inline] 132 | #[must_use] 133 | fn from(val: *const T) -> Self { 134 | $self_ty(val as *const () as *mut ()) 135 | } 136 | } 137 | 138 | impl core::ops::Add for $self_ty { 139 | type Output = Self; 140 | #[inline] 141 | #[must_use] 142 | fn add(self, rhs: Self) -> Self::Output { 143 | $self_ty( 144 | self.0 145 | .map_addr(|a| ((a as $int_ty) + (rhs.0.addr() as $int_ty)) as usize), 146 | ) 147 | } 148 | } 149 | impl core::ops::Sub for $self_ty { 150 | type Output = Self; 151 | #[inline] 152 | #[must_use] 153 | fn sub(self, rhs: Self) -> Self::Output { 154 | $self_ty( 155 | self.0 156 | .map_addr(|a| ((a as $int_ty) - (rhs.0.addr() as $int_ty)) as usize), 157 | ) 158 | } 159 | } 160 | impl core::ops::Mul for $self_ty { 161 | type Output = Self; 162 | #[inline] 163 | #[must_use] 164 | fn mul(self, rhs: Self) -> Self::Output { 165 | $self_ty( 166 | self.0 167 | .map_addr(|a| ((a as $int_ty) * (rhs.0.addr() as $int_ty)) as usize), 168 | ) 169 | } 170 | } 171 | impl core::ops::Div for $self_ty { 172 | type Output = Self; 173 | #[inline] 174 | #[must_use] 175 | fn div(self, rhs: Self) -> Self::Output { 176 | $self_ty( 177 | self.0 178 | .map_addr(|a| ((a as $int_ty) / (rhs.0.addr() as $int_ty)) as usize), 179 | ) 180 | } 181 | } 182 | impl core::ops::Rem for $self_ty { 183 | type Output = Self; 184 | #[inline] 185 | #[must_use] 186 | fn rem(self, rhs: Self) -> Self::Output { 187 | $self_ty( 188 | self.0 189 | .map_addr(|a| ((a as $int_ty) % (rhs.0.addr() as $int_ty)) as usize), 190 | ) 191 | } 192 | } 193 | impl core::ops::BitAnd for $self_ty { 194 | type Output = Self; 195 | #[inline] 196 | #[must_use] 197 | fn bitand(self, rhs: Self) -> Self::Output { 198 | $self_ty( 199 | self.0 200 | .map_addr(|a| ((a as $int_ty) & (rhs.0.addr() as $int_ty)) as usize), 201 | ) 202 | } 203 | } 204 | impl core::ops::BitOr for $self_ty { 205 | type Output = Self; 206 | #[inline] 207 | #[must_use] 208 | fn bitor(self, rhs: Self) -> Self::Output { 209 | $self_ty( 210 | self.0 211 | .map_addr(|a| ((a as $int_ty) | (rhs.0.addr() as $int_ty)) as usize), 212 | ) 213 | } 214 | } 215 | impl core::ops::BitXor for $self_ty { 216 | type Output = Self; 217 | #[inline] 218 | #[must_use] 219 | fn bitxor(self, rhs: Self) -> Self::Output { 220 | $self_ty( 221 | self.0 222 | .map_addr(|a| ((a as $int_ty) ^ (rhs.0.addr() as $int_ty)) as usize), 223 | ) 224 | } 225 | } 226 | impl core::ops::Shl for $self_ty { 227 | type Output = Self; 228 | #[inline] 229 | #[must_use] 230 | fn shl(self, rhs: usize) -> Self::Output { 231 | $self_ty(self.0.map_addr(|a| ((a as $int_ty) << rhs) as usize)) 232 | } 233 | } 234 | impl core::ops::Shr for $self_ty { 235 | type Output = Self; 236 | #[inline] 237 | #[must_use] 238 | fn shr(self, rhs: usize) -> Self::Output { 239 | $self_ty(self.0.map_addr(|a| ((a as $int_ty) >> rhs) as usize)) 240 | } 241 | } 242 | 243 | impl core::ops::Not for $self_ty { 244 | type Output = Self; 245 | #[inline] 246 | #[must_use] 247 | fn not(self) -> Self::Output { 248 | $self_ty(self.0.map_addr(|a| (!(a as $int_ty)) as usize)) 249 | } 250 | } 251 | 252 | impl core::ops::AddAssign for $self_ty { 253 | #[inline] 254 | #[must_use] 255 | fn add_assign(&mut self, rhs: Self) { 256 | self.0 = self 257 | .0 258 | .map_addr(|a| ((a as $int_ty) + (rhs.0.addr() as $int_ty)) as usize); 259 | } 260 | } 261 | impl core::ops::SubAssign for $self_ty { 262 | #[inline] 263 | #[must_use] 264 | fn sub_assign(&mut self, rhs: Self) { 265 | self.0 = self 266 | .0 267 | .map_addr(|a| ((a as $int_ty) - (rhs.0.addr() as $int_ty)) as usize); 268 | } 269 | } 270 | impl core::ops::MulAssign for $self_ty { 271 | #[inline] 272 | #[must_use] 273 | fn mul_assign(&mut self, rhs: Self) { 274 | self.0 = self 275 | .0 276 | .map_addr(|a| ((a as $int_ty) * (rhs.0.addr() as $int_ty)) as usize); 277 | } 278 | } 279 | impl core::ops::DivAssign for $self_ty { 280 | #[inline] 281 | #[must_use] 282 | fn div_assign(&mut self, rhs: Self) { 283 | self.0 = self 284 | .0 285 | .map_addr(|a| ((a as $int_ty) / (rhs.0.addr() as $int_ty)) as usize); 286 | } 287 | } 288 | impl core::ops::RemAssign for $self_ty { 289 | #[inline] 290 | #[must_use] 291 | fn rem_assign(&mut self, rhs: Self) { 292 | self.0 = self 293 | .0 294 | .map_addr(|a| ((a as $int_ty) % (rhs.0.addr() as $int_ty)) as usize); 295 | } 296 | } 297 | impl core::ops::BitAndAssign for $self_ty { 298 | #[inline] 299 | #[must_use] 300 | fn bitand_assign(&mut self, rhs: Self) { 301 | self.0 = self 302 | .0 303 | .map_addr(|a| ((a as $int_ty) & (rhs.0.addr() as $int_ty)) as usize); 304 | } 305 | } 306 | impl core::ops::BitOrAssign for $self_ty { 307 | #[inline] 308 | #[must_use] 309 | fn bitor_assign(&mut self, rhs: Self) { 310 | self.0 = self 311 | .0 312 | .map_addr(|a| ((a as $int_ty) | (rhs.0.addr() as $int_ty)) as usize); 313 | } 314 | } 315 | impl core::ops::BitXorAssign for $self_ty { 316 | #[inline] 317 | #[must_use] 318 | fn bitxor_assign(&mut self, rhs: Self) { 319 | self.0 = self 320 | .0 321 | .map_addr(|a| ((a as $int_ty) ^ (rhs.0.addr() as $int_ty)) as usize); 322 | } 323 | } 324 | impl core::ops::ShlAssign for $self_ty { 325 | #[inline] 326 | #[must_use] 327 | fn shl_assign(&mut self, rhs: usize) { 328 | self.0 = self.0.map_addr(|a| ((a as $int_ty) << rhs) as usize); 329 | } 330 | } 331 | impl core::ops::ShrAssign for $self_ty { 332 | #[inline] 333 | #[must_use] 334 | fn shr_assign(&mut self, rhs: usize) { 335 | self.0 = self.0.map_addr(|a| ((a as $int_ty) >> rhs) as usize); 336 | } 337 | } 338 | 339 | impl core::fmt::Display for $self_ty { 340 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 341 | write!(f, "{}", self.0.addr() as $int_ty) 342 | } 343 | } 344 | 345 | impl core::fmt::Debug for $self_ty { 346 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 347 | write!(f, "{:?}", self.0.addr() as $int_ty) 348 | } 349 | } 350 | }; 351 | } 352 | 353 | int_impls!(uptr, usize); 354 | int_impls!(iptr, isize); 355 | 356 | // usize can't be negated 357 | impl core::ops::Neg for iptr { 358 | type Output = Self; 359 | #[inline] 360 | #[must_use] 361 | fn neg(self) -> Self::Output { 362 | iptr(self.0.map_addr(|a| (-(a as isize)) as usize)) 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unstable_name_collisions)] 2 | #![no_std] 3 | 4 | //! This library provides a stable polyfill for Rust's [Strict Provenance] experiment. 5 | //! 6 | //! # Mapping to STD APIs: 7 | //! 8 | //! This crate "overlays" a bunch of unstable std apis, here are the mappings: 9 | //! 10 | //! ## core::ptr (sptr) 11 | //! 12 | //! * `pub fn `[`invalid`]`(addr: usize) -> *const T;` 13 | //! * `pub fn `[`invalid_mut`]`(addr: usize) -> *mut T;` 14 | //! * `pub fn `[`from_exposed_addr`]`(addr: usize) -> *const T;` 15 | //! * `pub fn `[`from_exposed_addr_mut`]`(addr: usize) -> *mut T;` 16 | //! 17 | //! 18 | //! ## core::pointer (sptr::Strict) 19 | //! 20 | //! * `pub fn `[`addr`]`(self) -> usize;` 21 | //! * `pub fn `[`expose_addr`]`(self) -> usize;` 22 | //! * `pub fn `[`with_addr`]`(self, addr: usize) -> Self;` 23 | //! * `pub fn `[`map_addr`]`(self, f: impl FnOnce(usize) -> usize) -> Self;` 24 | //! 25 | //! 26 | //! ## NON-STANDARD EXTENSIONS (disabled by default, use at your own risk) 27 | //! 28 | //! * `sptr::`[`uptr`] (feature = uptr) 29 | //! * `sptr::`[`iptr`] (feature = uptr) 30 | //! * `sptr::`[`OpaqueFnPtr`] (feature = opaque_fn) 31 | //! 32 | //! 33 | //! 34 | //! 35 | //! # Applying The Overlay 36 | //! 37 | //! Swapping between sptr and core::ptr should be as simple as switching between `sptr::` and `ptr::` 38 | //! for static functions. For methods, you must import `sptr::Strict` into your module for 39 | //! the extension trait's methods to overlay std. The compiler will (understandably) 40 | //! complain that you are overlaying std, so you will need to also silence that as 41 | //! seen in the following example: 42 | //! 43 | //! ```rust 44 | //! #![allow(unstable_name_collisions)] 45 | //! use sptr::Strict; 46 | //! 47 | //! let ptr = sptr::invalid_mut::(1); 48 | //! println!("{}", ptr.addr()); 49 | //! ``` 50 | //! 51 | //! By default, this crate will also mark methods on pointers as "deprecated" if they are 52 | //! incompatible with strict_provenance. If you don't want this, set `default-features = false` 53 | //! in your Cargo.toml. 54 | //! 55 | //! Rust is the canonical source of definitions for these APIs and semantics, but the docs 56 | //! here will vaguely try to mirror the docs checked into Rust. 57 | //! 58 | //! The following explanation of the model should also appear at the top of `core::ptr`: 59 | //! 60 | //! # Strict Provenance 61 | //! 62 | //! **The following text is non-normative, insufficiently formal, and is an extremely strict 63 | //! interpretation of provenance. It's ok if your code doesn't strictly conform to it.** 64 | //! 65 | //! [Strict Provenance][] is an experimental set of APIs that help tools that try 66 | //! to validate the memory-safety of your program's execution. Notably this includes [Miri][] 67 | //! and [CHERI][], which can detect when you access out of bounds memory or otherwise violate 68 | //! Rust's memory model. 69 | //! 70 | //! Provenance must exist in some form for any programming 71 | //! language compiled for modern computer architectures, but specifying a model for provenance 72 | //! in a way that is useful to both compilers and programmers is an ongoing challenge. 73 | //! The [Strict Provenance][] experiment seeks to explore the question: *what if we just said you 74 | //! couldn't do all the nasty operations that make provenance so messy?* 75 | //! 76 | //! What APIs would have to be removed? What APIs would have to be added? How much would code 77 | //! have to change, and is it worse or better now? Would any patterns become truly inexpressible? 78 | //! Could we carve out special exceptions for those patterns? Should we? 79 | //! 80 | //! A secondary goal of this project is to see if we can disamiguate the many functions of 81 | //! pointer<->integer casts enough for the definition of `usize` to be loosened so that it 82 | //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue 83 | //! to conflate these notions). This would potentially make it possible to more efficiently 84 | //! target platforms where pointers are larger than offsets, such as CHERI and maybe some 85 | //! segmented architecures. 86 | //! 87 | //! ## Provenance 88 | //! 89 | //! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.** 90 | //! 91 | //! Pointers are not *simply* an "integer" or "address". For instance, it's uncontroversial 92 | //! to say that a Use After Free is clearly Undefined Behaviour, even if you "get lucky" 93 | //! and the freed memory gets reallocated before your read/write (in fact this is the 94 | //! worst-case scenario, UAFs would be much less concerning if this didn't happen!). 95 | //! To rationalize this claim, pointers need to somehow be *more* than just their addresses: 96 | //! they must have provenance. 97 | //! 98 | //! When an allocation is created, that allocation has a unique Original Pointer. For alloc 99 | //! APIs this is literally the pointer the call returns, and for local variables and statics, 100 | //! this is the name of the variable/static. This is mildly overloading the term "pointer" 101 | //! for the sake of brevity/exposition. 102 | //! 103 | //! The Original Pointer for an allocation is guaranteed to have unique access to the entire 104 | //! allocation and *only* that allocation. In this sense, an allocation can be thought of 105 | //! as a "sandbox" that cannot be broken into or out of. *Provenance* is the permission 106 | //! to access an allocation's sandbox and has both a *spatial* and *temporal* component: 107 | //! 108 | //! * Spatial: A range of bytes that the pointer is allowed to access. 109 | //! * Temporal: The lifetime (of the allocation) that access to these bytes is tied to. 110 | //! 111 | //! Spatial provenance makes sure you don't go beyond your sandbox, while temporal provenance 112 | //! makes sure that you can't "get lucky" after your permission to access some memory 113 | //! has been revoked (either through deallocations or borrows expiring). 114 | //! 115 | //! Provenance is implicitly shared with all pointers transitively derived from 116 | //! The Original Pointer through operations like [`offset`], borrowing, and pointer casts. 117 | //! Some operations may *shrink* the derived provenance, limiting how much memory it can 118 | //! access or how long it's valid for (i.e. borrowing a subfield and subslicing). 119 | //! 120 | //! Shrinking provenance cannot be undone: even if you "know" there is a larger allocation, you 121 | //! can't derive a pointer with a larger provenance. Similarly, you cannot "recombine" 122 | //! two contiguous provenances back into one (i.e. with a `fn merge(&[T], &[T]) -> &[T]`). 123 | //! 124 | //! A reference to a value always has provenance over exactly the memory that field occupies. 125 | //! A reference to a slice always has provenance over exactly the range that slice describes. 126 | //! 127 | //! If an allocation is deallocated, all pointers with provenance to that allocation become 128 | //! invalidated, and effectively lose their provenance. 129 | //! 130 | //! The strict provenance experiment is mostly only interested in exploring stricter *spatial* 131 | //! provenance. In this sense it can be thought of as a subset of the more ambitious and 132 | //! formal [Stacked Borrows][] research project, which is what tools like [Miri][] are based on. 133 | //! In particular, Stacked Borrows is necessary to properly describe what borrows are allowed 134 | //! to do and when they become invalidated. This necessarily involves much more complex 135 | //! *temporal* reasoning than simply identifying allocations. Adjusting APIs and code 136 | //! for the strict provenance experiment will also greatly help Stacked Borrows. 137 | //! 138 | //! 139 | //! ## Pointer Vs Addresses 140 | //! 141 | //! **This section is *non-normative* and is part of the [Strict Provenance][] experiment.** 142 | //! 143 | //! One of the largest historical issues with trying to define provenance is that programmers 144 | //! freely convert between pointers and integers. Once you allow for this, it generally becomes 145 | //! impossible to accurately track and preserve provenance information, and you need to appeal 146 | //! to very complex and unreliable heuristics. But of course, converting between pointers and 147 | //! integers is very useful, so what can we do? 148 | //! 149 | //! Also did you know WASM is actually a "Harvard Architecture"? As in function pointers are 150 | //! handled completely differently from data pointers? And we kind of just shipped Rust on WASM 151 | //! without really addressing the fact that we let you freely convert between function pointers 152 | //! and data pointers, because it mostly Just Works? Let's just put that on the "pointer casts 153 | //! are dubious" pile. 154 | //! 155 | //! Strict Provenance attempts to square these circles by decoupling Rust's traditional conflation 156 | //! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the 157 | //! following information: 158 | //! 159 | //! * The **address-space** it is part of. 160 | //! * The **address** it points to, which can be represented by a `usize`. 161 | //! * The **provenance** it has, defining the memory it has permission to access. 162 | //! 163 | //! Under Strict Provenance, a usize *cannot* accurately represent a pointer, and converting from 164 | //! a pointer to a usize is generally an operation which *only* extracts the address. It is 165 | //! therefore *impossible* to construct a valid pointer from a usize because there is no way 166 | //! to restore the address-space and provenance. In other words, pointer-integer-pointer 167 | //! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable). 168 | //! 169 | //! The key insight to making this model *at all* viable is the [`with_addr`][] method: 170 | //! 171 | //! ```text 172 | //! /// Creates a new pointer with the given address. 173 | //! /// 174 | //! /// This performs the same operation as an `addr as ptr` cast, but copies 175 | //! /// the *address-space* and *provenance* of `self` to the new pointer. 176 | //! /// This allows us to dynamically preserve and propagate this important 177 | //! /// information in a way that is otherwise impossible with a unary cast. 178 | //! /// 179 | //! /// This is equivalent to using `wrapping_offset` to offset `self` to the 180 | //! /// given address, and therefore has all the same capabilities and restrictions. 181 | //! pub fn with_addr(self, addr: usize) -> Self; 182 | //! ``` 183 | //! 184 | //! So you're still able to drop down to the address representation and do whatever 185 | //! clever bit tricks you want *as long as* you're able to keep around a pointer 186 | //! into the allocation you care about that can "reconstitute" the other parts of the pointer. 187 | //! Usually this is very easy, because you only are taking a pointer, messing with the address, 188 | //! and then immediately converting back to a pointer. To make this use case more ergonomic, 189 | //! we provide the [`map_addr`][] method. 190 | //! 191 | //! To help make it clear that code is "following" Strict Provenance semantics, we also provide an 192 | //! [`addr`][] method which promises that the returned address is not part of a 193 | //! pointer-usize-pointer roundtrip. In the future we may provide a lint for pointer<->integer 194 | //! casts to help you audit if your code conforms to strict provenance. 195 | //! 196 | //! 197 | //! ## Using Strict Provenance 198 | //! 199 | //! Most code needs no changes to conform to strict provenance, as the only really concerning 200 | //! operation that *wasn't* obviously already Undefined Behaviour is casts from usize to a 201 | //! pointer. For code which *does* cast a usize to a pointer, the scope of the change depends 202 | //! on exactly what you're doing. 203 | //! 204 | //! In general you just need to make sure that if you want to convert a usize address to a 205 | //! pointer and then use that pointer to read/write memory, you need to keep around a pointer 206 | //! that has sufficient provenance to perform that read/write itself. In this way all of your 207 | //! casts from an address to a pointer are essentially just applying offsets/indexing. 208 | //! 209 | //! This is generally trivial to do for simple cases like tagged pointers *as long as you 210 | //! represent the tagged pointer as an actual pointer and not a usize*. For instance: 211 | //! 212 | //! ``` 213 | //! // #![feature(strict_provenance)] 214 | //! #![allow(unstable_name_collisions)] 215 | //! use sptr::Strict; 216 | //! 217 | //! unsafe { 218 | //! // A flag we want to pack into our pointer 219 | //! static HAS_DATA: usize = 0x1; 220 | //! static FLAG_MASK: usize = !HAS_DATA; 221 | //! 222 | //! // Our value, which must have enough alignment to have spare least-significant-bits. 223 | //! let my_precious_data: u32 = 17; 224 | //! assert!(core::mem::align_of::() > 1); 225 | //! 226 | //! // Create a tagged pointer 227 | //! let ptr = &my_precious_data as *const u32; 228 | //! let tagged = ptr.map_addr(|addr| addr | HAS_DATA); 229 | //! 230 | //! // Check the flag: 231 | //! if tagged.addr() & HAS_DATA != 0 { 232 | //! // Untag and read the pointer 233 | //! let data = *tagged.map_addr(|addr| addr & FLAG_MASK); 234 | //! assert_eq!(data, 17); 235 | //! } else { 236 | //! unreachable!() 237 | //! } 238 | //! } 239 | //! ``` 240 | //! 241 | //! (Yes, if you've been using AtomicUsize for pointers in concurrent datastructures, you should 242 | //! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers, 243 | //! we would like to know why, and what needs to be done to fix it.) 244 | //! 245 | //! Something more complicated and just generally *evil* like a XOR-List requires more significant 246 | //! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer 247 | //! to the whole allocation to reconstitute the XORed addresses. 248 | //! 249 | //! Situations where a valid pointer *must* be created from just an address, such as baremetal code 250 | //! accessing a memory-mapped interface at a fixed address, are an open question on how to support. 251 | //! These situations *will* still be allowed, but we might require some kind of "I know what I'm 252 | //! doing" annotation to explain the situation to the compiler. It's also possible they need no 253 | //! special attention at all, because they're generally accessing memory outside the scope of 254 | //! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile". 255 | //! 256 | //! Under [Strict Provenance] is is Undefined Behaviour to: 257 | //! 258 | //! * Access memory through a pointer that does not have provenance over that memory. 259 | //! 260 | //! * [`offset`] a pointer to or from an address it doesn't have provenance over. 261 | //! This means it's always UB to offset a pointer derived from something deallocated, 262 | //! even if the offset is 0. Note that a pointer "one past the end" of its provenance 263 | //! is not actually outside its provenance, it just has 0 bytes it can load/store. 264 | //! 265 | //! But it *is* still sound to: 266 | //! 267 | //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can 268 | //! be used for sentinel values like `null` *or* to represent a tagged pointer that will 269 | //! never be dereferencable. In general, it is always sound for an integer to pretend 270 | //! to be a pointer "for fun" as long as you don't use operations on it which require 271 | //! it to be valid (offset, read, write, etc). 272 | //! 273 | //! * Forge an allocation of size zero at any sufficiently aligned non-null address. 274 | //! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies 275 | //! for actual forgery (integers cast to pointers). If you borrow some struct's field 276 | //! that *happens* to be zero-sized, the resulting pointer will have provenance tied to 277 | //! that allocation and it will still get invalidated if the allocation gets deallocated. 278 | //! In the future we may introduce an API to make such a forged allocation explicit. 279 | //! 280 | //! * [`wrapping_offset`][] a pointer outside its provenance. This includes invalid pointers 281 | //! which have "no" provenance. Unfortunately there may be practical limits on this for a 282 | //! particular platform, and it's an open question as to how to specify this (if at all). 283 | //! Notably, [CHERI][] relies on a compression scheme that can't handle a 284 | //! pointer getting offset "too far" out of bounds. If this happens, the address 285 | //! returned by `addr` will be the value you expect, but the provenance will get invalidated 286 | //! and using it to read/write will fault. The details of this are architecture-specific 287 | //! and based on alignment, but the buffer on either side of the pointer's range is pretty 288 | //! generous (think kilobytes, not bytes). 289 | //! 290 | //! * Compare arbitrary pointers by address. Addresses *are* just integers and so there is 291 | //! always a coherent answer, even if the pointers are invalid or from different 292 | //! address-spaces/provenances. Of course, comparing addresses from different address-spaces 293 | //! is generally going to be *meaningless*, but so is comparing Kilograms to Meters, and Rust 294 | //! doesn't prevent that either. Similarly, if you get "lucky" and notice that a pointer 295 | //! one-past-the-end is the "same" address as the start of an unrelated allocation, anything 296 | //! you do with that fact is *probably* going to be gibberish. The scope of that gibberish 297 | //! is kept under control by the fact that the two pointers *still* aren't allowed to access 298 | //! the other's allocation (bytes), because they still have different provenance. 299 | //! 300 | //! * Perform pointer tagging tricks. This falls out of [`wrapping_offset`] but is worth 301 | //! mentioning in more detail because of the limitations of [CHERI][]. Low-bit tagging 302 | //! is very robust, and often doesn't even go out of bounds because types ensure 303 | //! size >= align (and over-aligning actually gives CHERI more flexibility). Anything 304 | //! more complex than this rapidly enters "extremely platform-specific" territory as 305 | //! certain things may or may not be allowed based on specific supported operations. 306 | //! For instance, ARM explicitly supports high-bit tagging, and so CHERI on ARM inherits 307 | //! that and should support it. 308 | //! 309 | //! ## Pointer-usize-pointer roundtrips and 'exposed' provenance 310 | //! 311 | //! **This section is *non-normative* and is part of the [Strict Provenance] experiment.** 312 | //! 313 | //! As discussed above, pointer-usize-pointer roundtrips are not possible under [Strict Provenance]. 314 | //! However, there exists legacy Rust code that is full of such roundtrips, and legacy platform APIs 315 | //! regularly assume that `usize` can capture all the information that makes up a pointer. There 316 | //! also might be code that cannot be ported to Strict Provenance (which is something we would [like 317 | //! to hear about][Strict Provenance]). 318 | //! 319 | //! For situations like this, there is a fallback plan, a way to 'opt out' of Strict Provenance. 320 | //! However, note that this makes your code a lot harder to specify, and the code will not work 321 | //! (well) with tools like [Miri] and [CHERI]. 322 | //! 323 | //! This fallback plan is provided by the [`expose_addr`] and [`from_exposed_addr`] methods (which 324 | //! are equivalent to `as` casts between pointers and integers). [`expose_addr`] is a lot like 325 | //! [`addr`], but additionally adds the provenance of the pointer to a global list of 'exposed' 326 | //! provenances. (This list is purely conceptual, it exists for the purpose of specifying Rust but 327 | //! is not materialized in actual executions, except in tools like [Miri].) [`from_exposed_addr`] 328 | //! can be used to construct a pointer with one of these previously 'exposed' provenances. 329 | //! [`from_exposed_addr`] takes only `addr: usize` as arguments, so unlike in [`with_addr`] there is 330 | //! no indication of what the correct provenance for the returned pointer is -- and that is exactly 331 | //! what makes pointer-usize-pointer roundtrips so tricky to rigorously specify! There is no 332 | //! algorithm that decides which provenance will be used. You can think of this as "guessing" the 333 | //! right provenance, and the guess will be "maximally in your favor", in the sense that if there is 334 | //! any way to avoid undefined behavior, then that is the guess that will be taken. However, if 335 | //! there is *no* previously 'exposed' provenance that justifies the way the returned pointer will 336 | //! be used, the program has undefined behavior. 337 | //! 338 | //! Using [`expose_addr`] or [`from_exposed_addr`] (or the equivalent `as` casts) means that code is 339 | //! *not* following Strict Provenance rules. The goal of the Strict Provenance experiment is to 340 | //! determine whether it is possible to use Rust without [`expose_addr`] and [`from_exposed_addr`]. 341 | //! If this is successful, it would be a major win for avoiding specification complexity and to 342 | //! facilitate adoption of tools like [CHERI] and [Miri] that can be a big help in increasing the 343 | //! confidence in (unsafe) Rust code. 344 | //! 345 | //! 346 | //! [aliasing]: https://doc.rust-lang.org/nightly/nomicon/aliasing.html 347 | //! [book]: https://doc.rust-lang.org/nightly/book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer 348 | //! [ub]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html 349 | //! [zst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts 350 | //! [atomic operations]: core::sync::atomic 351 | //! [`offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.offset 352 | //! [`wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset 353 | //! [`with_addr`]: Strict::with_addr 354 | //! [`map_addr`]: Strict::map_addr 355 | //! [`addr`]: Strict::addr 356 | //! [`ptr::invalid`]: crate::invalid 357 | //! [`expose_addr`]: Strict::expose_addr 358 | //! [`from_exposed_addr`]: crate::from_exposed_addr 359 | //! [Miri]: https://github.com/rust-lang/miri 360 | //! [CHERI]: https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/ 361 | //! [Strict Provenance]: https://github.com/rust-lang/rust/issues/95228 362 | //! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/ 363 | 364 | /// Creates an invalid pointer with the given address. 365 | /// 366 | /// This is different from `addr as *const T`, which creates a pointer that picks up a previously 367 | /// exposed provenance. See [`from_exposed_addr`] for more details on that operation. 368 | /// 369 | /// The module's top-level documentation discusses the precise meaning of an "invalid" 370 | /// pointer but essentially this expresses that the pointer is not associated 371 | /// with any actual allocation and is little more than a usize address in disguise. 372 | /// 373 | /// This pointer will have no provenance associated with it and is therefore 374 | /// UB to read/write/offset. This mostly exists to facilitate things 375 | /// like `ptr::null` and `NonNull::dangling` which make invalid pointers. 376 | /// 377 | /// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it 378 | /// may be desirable to give them their own API just to make that 100% clear.) 379 | /// 380 | /// This API and its claimed semantics are part of the Strict Provenance experiment, 381 | /// see the [module documentation][crate] for details. 382 | #[inline(always)] 383 | #[must_use] 384 | pub const fn invalid(addr: usize) -> *const T { 385 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 386 | // We use transmute rather than a cast so tools like Miri can tell that this 387 | // is *not* the same as from_exposed_addr. 388 | // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that 389 | // pointer). 390 | #[cfg(miri)] 391 | return unsafe { core::mem::transmute(addr) }; 392 | // Outside Miri we keep using casts, so that we can be a `const fn` on old Rust (pre-1.56). 393 | #[cfg(not(miri))] 394 | return addr as *const T; 395 | } 396 | 397 | /// Creates an invalid mutable pointer with the given address. 398 | /// 399 | /// This is different from `addr as *mut T`, which creates a pointer that picks up a previously 400 | /// exposed provenance. See [`from_exposed_addr_mut`] for more details on that operation. 401 | /// 402 | /// The module's top-level documentation discusses the precise meaning of an "invalid" 403 | /// pointer but essentially this expresses that the pointer is not associated 404 | /// with any actual allocation and is little more than a usize address in disguise. 405 | /// 406 | /// This pointer will have no provenance associated with it and is therefore 407 | /// UB to read/write/offset. This mostly exists to facilitate things 408 | /// like `ptr::null` and `NonNull::dangling` which make invalid pointers. 409 | /// 410 | /// (Standard "Zero-Sized-Types get to cheat and lie" caveats apply, although it 411 | /// may be desirable to give them their own API just to make that 100% clear.) 412 | /// 413 | /// This API and its claimed semantics are part of the Strict Provenance experiment, 414 | /// see the [module documentation][crate] for details. 415 | #[inline(always)] 416 | #[must_use] 417 | pub const fn invalid_mut(addr: usize) -> *mut T { 418 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 419 | // We use transmute rather than a cast so tools like Miri can tell that this 420 | // is *not* the same as from_exposed_addr. 421 | // SAFETY: every valid integer is also a valid pointer (as long as you don't dereference that 422 | // pointer). 423 | #[cfg(miri)] 424 | return unsafe { core::mem::transmute(addr) }; 425 | // Outside Miri we keep using casts, so that we can be a `const fn` on old Rust (pre-1.56). 426 | #[cfg(not(miri))] 427 | return addr as *mut T; 428 | } 429 | 430 | /// Convert an address back to a pointer, picking up a previously 'exposed' provenance. 431 | /// 432 | /// This is equivalent to `addr as *const T`. The provenance of the returned pointer is that of *any* 433 | /// pointer that was previously passed to [`expose_addr`][Strict::expose_addr] or a `ptr as usize` 434 | /// cast. If there is no previously 'exposed' provenance that justifies the way this pointer will be 435 | /// used, the program has undefined behavior. Note that there is no algorithm that decides which 436 | /// provenance will be used. You can think of this as "guessing" the right provenance, and the guess 437 | /// will be "maximally in your favor", in the sense that if there is any way to avoid undefined 438 | /// behavior, then that is the guess that will be taken. 439 | /// 440 | /// On platforms with multiple address spaces, it is your responsibility to ensure that the 441 | /// address makes sense in the address space that this pointer will be used with. 442 | /// 443 | /// Using this method means that code is *not* following strict provenance rules. "Guessing" a 444 | /// suitable provenance complicates specification and reasoning and may not be supported by 445 | /// tools that help you to stay conformant with the Rust memory model, so it is recommended to 446 | /// use [`with_addr`][Strict::with_addr] wherever possible. 447 | /// 448 | /// On most platforms this will produce a value with the same bytes as the address. Platforms 449 | /// which need to store additional information in a pointer may not support this operation, 450 | /// since it is generally not possible to actually *compute* which provenance the returned 451 | /// pointer has to pick up. 452 | /// 453 | /// This API and its claimed semantics are part of the Strict Provenance experiment, see the 454 | /// [module documentation][crate] for details. 455 | #[must_use] 456 | #[inline] 457 | pub fn from_exposed_addr(addr: usize) -> *const T 458 | where 459 | T: Sized, 460 | { 461 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 462 | addr as *const T 463 | } 464 | 465 | /// Convert an address back to a mutable pointer, picking up a previously 'exposed' provenance. 466 | /// 467 | /// This is equivalent to `addr as *mut T`. The provenance of the returned pointer is that of *any* 468 | /// pointer that was previously passed to [`expose_addr`][Strict::expose_addr] or a `ptr as usize` 469 | /// cast. If there is no previously 'exposed' provenance that justifies the way this pointer will be 470 | /// used, the program has undefined behavior. Note that there is no algorithm that decides which 471 | /// provenance will be used. You can think of this as "guessing" the right provenance, and the guess 472 | /// will be "maximally in your favor", in the sense that if there is any way to avoid undefined 473 | /// behavior, then that is the guess that will be taken. 474 | /// 475 | /// On platforms with multiple address spaces, it is your responsibility to ensure that the 476 | /// address makes sense in the address space that this pointer will be used with. 477 | /// 478 | /// Using this method means that code is *not* following strict provenance rules. "Guessing" a 479 | /// suitable provenance complicates specification and reasoning and may not be supported by 480 | /// tools that help you to stay conformant with the Rust memory model, so it is recommended to 481 | /// use [`with_addr`][Strict::with_addr] wherever possible. 482 | /// 483 | /// On most platforms this will produce a value with the same bytes as the address. Platforms 484 | /// which need to store additional information in a pointer may not support this operation, 485 | /// since it is generally not possible to actually *compute* which provenance the returned 486 | /// pointer has to pick up. 487 | /// 488 | /// This API and its claimed semantics are part of the Strict Provenance experiment, see the 489 | /// [module documentation][crate] for details. 490 | #[must_use] 491 | #[inline] 492 | pub fn from_exposed_addr_mut(addr: usize) -> *mut T 493 | where 494 | T: Sized, 495 | { 496 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 497 | addr as *mut T 498 | } 499 | 500 | mod private { 501 | pub trait Sealed {} 502 | } 503 | 504 | pub trait Strict: private::Sealed { 505 | type Pointee; 506 | /// Gets the "address" portion of the pointer. 507 | /// 508 | /// This is similar to `self as usize`, which semantically discards *provenance* and 509 | /// *address-space* information. However, unlike `self as usize`, casting the returned address 510 | /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To 511 | /// properly restore the lost information and obtain a dereferencable pointer, use 512 | /// [`with_addr`][Strict::with_addr] or [`map_addr`][Strict::map_addr]. 513 | /// 514 | /// If using those APIs is not possible because there is no way to preserve a pointer with the 515 | /// required provenance, use [`expose_addr`][Strict::expose_addr] and 516 | /// [`from_exposed_addr`][from_exposed_addr] instead. However, note that this makes 517 | /// your code less portable and less amenable to tools that check for compliance with the Rust 518 | /// memory model. 519 | /// 520 | /// On most platforms this will produce a value with the same bytes as the original 521 | /// pointer, because all the bytes are dedicated to describing the address. 522 | /// Platforms which need to store additional information in the pointer may 523 | /// perform a change of representation to produce a value containing only the address 524 | /// portion of the pointer. What that means is up to the platform to define. 525 | /// 526 | /// This API and its claimed semantics are part of the Strict Provenance experiment, and as such 527 | /// might change in the future (including possibly weakening this so it becomes wholly 528 | /// equivalent to `self as usize`). See the [module documentation][crate] for details. 529 | #[must_use] 530 | fn addr(self) -> usize 531 | where 532 | Self::Pointee: Sized; 533 | 534 | /// Gets the "address" portion of the pointer, and 'exposes' the "provenance" part for future 535 | /// use in [`from_exposed_addr`][]. 536 | /// 537 | /// This is equivalent to `self as usize`, which semantically discards *provenance* and 538 | /// *address-space* information. Furthermore, this (like the `as` cast) has the implicit 539 | /// side-effect of marking the provenance as 'exposed', so on platforms that support it you can 540 | /// later call [`from_exposed_addr`][] to reconstitute the original pointer including its 541 | /// provenance. (Reconstructing address space information, if required, is your responsibility.) 542 | /// 543 | /// Using this method means that code is *not* following Strict Provenance rules. Supporting 544 | /// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by 545 | /// tools that help you to stay conformant with the Rust memory model, so it is recommended to 546 | /// use [`addr`][Strict::addr] wherever possible. 547 | /// 548 | /// On most platforms this will produce a value with the same bytes as the original pointer, 549 | /// because all the bytes are dedicated to describing the address. Platforms which need to store 550 | /// additional information in the pointer may not support this operation, since the 'expose' 551 | /// side-effect which is required for [`from_exposed_addr`][] to work is typically not 552 | /// available. 553 | /// 554 | /// This API and its claimed semantics are part of the Strict Provenance experiment, see the 555 | /// [module documentation][crate] for details. 556 | /// 557 | /// [`from_exposed_addr`]: crate::from_exposed_addr 558 | #[must_use] 559 | fn expose_addr(self) -> usize 560 | where 561 | Self::Pointee: Sized; 562 | 563 | /// Creates a new pointer with the given address. 564 | /// 565 | /// This performs the same operation as an `addr as ptr` cast, but copies 566 | /// the *address-space* and *provenance* of `self` to the new pointer. 567 | /// This allows us to dynamically preserve and propagate this important 568 | /// information in a way that is otherwise impossible with a unary cast. 569 | /// 570 | /// This is equivalent to using [`wrapping_offset`][] to offset 571 | /// `self` to the given address, and therefore has all the same capabilities and restrictions. 572 | /// 573 | /// This API and its claimed semantics are part of the Strict Provenance experiment, 574 | /// see the [module documentation][crate] for details. 575 | /// 576 | /// [`wrapping_offset`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_offset 577 | #[must_use] 578 | fn with_addr(self, addr: usize) -> Self 579 | where 580 | Self::Pointee: Sized; 581 | 582 | /// Creates a new pointer by mapping `self`'s address to a new one. 583 | /// 584 | /// This is a convenience for [`with_addr`][Strict::with_addr], see that method for details. 585 | /// 586 | /// This API and its claimed semantics are part of the Strict Provenance experiment, 587 | /// see the [module documentation][crate] for details. 588 | #[must_use] 589 | fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self 590 | where 591 | Self::Pointee: Sized; 592 | } 593 | 594 | impl private::Sealed for *mut T {} 595 | impl private::Sealed for *const T {} 596 | 597 | impl Strict for *mut T { 598 | type Pointee = T; 599 | 600 | #[must_use] 601 | #[inline] 602 | fn addr(self) -> usize 603 | where 604 | T: Sized, 605 | { 606 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 607 | // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the 608 | // provenance). 609 | unsafe { core::mem::transmute(self) } 610 | } 611 | 612 | #[must_use] 613 | #[inline] 614 | fn expose_addr(self) -> usize 615 | where 616 | T: Sized, 617 | { 618 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 619 | self as usize 620 | } 621 | 622 | #[must_use] 623 | #[inline] 624 | fn with_addr(self, addr: usize) -> Self 625 | where 626 | T: Sized, 627 | { 628 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 629 | // 630 | // In the mean-time, this operation is defined to be "as if" it was 631 | // a wrapping_offset, so we can emulate it as such. This should properly 632 | // restore pointer provenance even under today's compiler. 633 | let self_addr = self.addr() as isize; 634 | let dest_addr = addr as isize; 635 | let offset = dest_addr.wrapping_sub(self_addr); 636 | 637 | // This is the canonical desugarring of this operation, 638 | // but `pointer::cast` was only stabilized in 1.38. 639 | // self.cast::().wrapping_offset(offset).cast::() 640 | (self as *mut u8).wrapping_offset(offset) as *mut T 641 | } 642 | 643 | #[must_use] 644 | #[inline] 645 | fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self 646 | where 647 | T: Sized, 648 | { 649 | self.with_addr(f(self.addr())) 650 | } 651 | } 652 | 653 | impl Strict for *const T { 654 | type Pointee = T; 655 | 656 | #[must_use] 657 | #[inline] 658 | fn addr(self) -> usize 659 | where 660 | T: Sized, 661 | { 662 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 663 | // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the 664 | // provenance). 665 | unsafe { core::mem::transmute(self) } 666 | } 667 | 668 | #[must_use] 669 | #[inline] 670 | fn expose_addr(self) -> usize 671 | where 672 | T: Sized, 673 | { 674 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 675 | self as usize 676 | } 677 | 678 | #[must_use] 679 | #[inline] 680 | fn with_addr(self, addr: usize) -> Self 681 | where 682 | T: Sized, 683 | { 684 | // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic. 685 | // 686 | // In the mean-time, this operation is defined to be "as if" it was 687 | // a wrapping_offset, so we can emulate it as such. This should properly 688 | // restore pointer provenance even under today's compiler. 689 | let self_addr = self.addr() as isize; 690 | let dest_addr = addr as isize; 691 | let offset = dest_addr.wrapping_sub(self_addr); 692 | 693 | // This is the canonical desugarring of this operation, 694 | // but `pointer::cast` was only stabilized in 1.38. 695 | // self.cast::().wrapping_offset(offset).cast::() 696 | (self as *const u8).wrapping_offset(offset) as *const T 697 | } 698 | 699 | #[must_use] 700 | #[inline] 701 | fn map_addr(self, f: impl FnOnce(usize) -> usize) -> Self 702 | where 703 | T: Sized, 704 | { 705 | self.with_addr(f(self.addr())) 706 | } 707 | } 708 | 709 | #[cfg(test)] 710 | mod test { 711 | #![allow(unstable_name_collisions)] 712 | use crate::Strict; 713 | 714 | #[test] 715 | fn test_overlay() { 716 | let null_ptr = core::ptr::null_mut::(); 717 | let ptr = crate::invalid_mut::(0); 718 | assert_eq!(ptr, null_ptr); 719 | 720 | let addr = ptr.addr(); 721 | assert_eq!(addr, ptr as usize); 722 | 723 | let new_ptr = ptr.map_addr(|a| a + 1); 724 | assert_eq!(new_ptr, ptr.wrapping_offset(1)); 725 | 726 | let new_ptr = ptr.with_addr(3); 727 | assert_eq!(new_ptr, 3 as *mut u8); 728 | 729 | let mut x = 7u32; 730 | let x_ref = &mut x; 731 | let x_ptr = x_ref as *mut u32; 732 | let x_addr = x_ptr.expose_addr(); 733 | let x_new_ptr = crate::from_exposed_addr_mut::(x_addr); 734 | 735 | unsafe { 736 | *x_new_ptr *= 3; 737 | *x_ptr *= 5; 738 | *x_ref *= 13; 739 | x *= 17; 740 | } 741 | 742 | assert_eq!(x, 7 * 3 * 5 * 13 * 17); 743 | } 744 | } 745 | 746 | #[cfg(feature = "uptr")] 747 | pub mod int; 748 | #[cfg(feature = "uptr")] 749 | pub use self::int::iptr; 750 | #[cfg(feature = "uptr")] 751 | pub use self::int::uptr; 752 | 753 | #[cfg(feature = "opaque_fn")] 754 | pub mod func; 755 | #[cfg(feature = "opaque_fn")] 756 | pub use self::func::OpaqueFnPtr; 757 | --------------------------------------------------------------------------------