sptr/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`]`<T>(addr: usize) -> *const T;`
13//! * `pub fn `[`invalid_mut`]`<T>(addr: usize) -> *mut T;`
14//! * `pub fn `[`from_exposed_addr`]`<T>(addr: usize) -> *const T;`
15//! * `pub fn `[`from_exposed_addr_mut`]`<T>(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::<u8>(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::<u32>() > 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]
384pub const fn invalid<T>(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]
417pub const fn invalid_mut<T>(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]
457pub fn from_exposed_addr<T>(addr: usize) -> *const T
458where
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]
492pub fn from_exposed_addr_mut<T>(addr: usize) -> *mut T
493where
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
500mod private {
501 pub trait Sealed {}
502}
503
504pub 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
594impl<T> private::Sealed for *mut T {}
595impl<T> private::Sealed for *const T {}
596
597impl<T> 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::<u8>().wrapping_offset(offset).cast::<T>()
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
653impl<T> 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::<u8>().wrapping_offset(offset).cast::<T>()
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)]
710mod 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::<u8>();
717 let ptr = crate::invalid_mut::<u8>(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::<u32>(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")]
747pub mod int;
748#[cfg(feature = "uptr")]
749pub use self::int::iptr;
750#[cfg(feature = "uptr")]
751pub use self::int::uptr;
752
753#[cfg(feature = "opaque_fn")]
754pub mod func;
755#[cfg(feature = "opaque_fn")]
756pub use self::func::OpaqueFnPtr;