deferred_reference/
lib.rs

1//! This crate helps with creating multiple mutable references to the contents of a variable without triggering undefined behavior.
2//! The Rust borrow rules dictate that it is undefined behavior to create more than one mutable reference to the same region,
3//! even if the mutable reference is not used. However, this can sometimes be a tad too restrictive if the programmer knows
4//! that two mutable references will not overlap. Using raw pointers, it is already possible to work-around the Rust borrow rules today,
5//! but this requires wizard-like skills and in-depth knowledge of handling raw pointers and this is more prone to error than
6//! using Rust references. With the introduction of non-lexical lifetimes in the Rust 2018 edition, the ergonomics around references 
7//! have already significantly improved, but there are still some corner-cases where the programmer wished there was some way
8//! to create non-overlapping mutable references into the same location (e.g. disjoint indices of a slice or array), without
9//! resorting to manually managed raw pointers. In order to aid with this, this crate introduces the concept of a "*deferred reference*"[^1].
10//! A deferred reference is almost exactly like a regular reference (e.g. a `&T` or a `&mut T`), but it differs from a regular reference
11//! in the following ways:
12//! * A deferred reference is not an actual reference, it is merely a smart pointer tied to the lifetime of the location it points to
13//!   (regular raw pointers always have a static lifetime, and can thus become dangling if the location it points to is moved or dropped).
14//! * It is allowed to keep multiple deferred mutable references around (as long as these are not dereferenced in a way so that
15//!   these create an overlap between a mutable reference and another (de)reference).
16//!
17//! A deferred reference is embodied by an instance of the [Deferred] struct, which can be used like a regular [Reference].
18//! There exist only two types of references and therefore there are two flavors of [Deferred], namely `Deferred<&T>` and
19//! `Deferred<&mut T>`. Both of these can be used the same way as a regular reference, because `Deferred<&T>` implements 
20//! the [Deref](core::ops::Deref) trait and `Deferred<&mut T>` implements both the [Deref](core::ops::Deref) trait and the
21//! [DerefMut](core::ops::DerefMut) trait.
22//!
23//! In order to obtain a `Deferred<&T>` or a `Deferred<&mut T>`, see the documentation at [Deferred] explaining the
24//! [constructors for deferred immutable references](Deferred#constructors-for-deferred-immutable-references) and
25//! [constructors for deferred mutable references](Deferred#constructors-for-deferred-mutable-references).
26//!
27//! # Arrays and slices
28//! The [Deferred] struct also provides some interesting functionality for deferred arrays and slices, for which it implements the
29//! [Index](core::ops::Index) and [IndexMut](core::ops::IndexMut) traits in a way that it only creates references to the
30//! queried indices but not to the other disjoint subslices. This allows multiple threads to simultaneouslt mutate the same array
31//! or slice as long as these threads don't create mutable references that overlap in index or in lifetime. Currently this functionality
32//! is available on stable Rust 1.51.0 for arrays `[T; N]` thanks to the introduction of the
33//! [`min_const_generics` feature](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md), but to use this
34//! functionality on slices `[T]`, too, nightly Rust is required until the `slice_ptr_len` feature stabilizes. For more details, see the
35//! [methods available for deferred references to slices and arrays](Deferred#methods-only-available-for-deferred-references-to-slices-and-arrays).
36//!
37//! # Example
38//! Here is an example of how one might use the [Deferred] struct:
39//! ```
40//! use deferred_reference::{Defer, DeferMut, Deferred};
41//! use core::cell::UnsafeCell;
42//! use core::ops::DerefMut;
43//! let buffer = Box::new(UnsafeCell::new([0u8; 1024])); // the `Box` is optional
44//! // calling defer() or defer_mut() immutably borrows `buffer` for as long
45//! // as the returned `Deferred` is in use.
46//! let deferred: Deferred<&[u8; 1024]> = buffer.defer();
47//! // SAFETY: this is safe, because we promise not to create an overlapping mutable reference
48//! let mut deferred_mut: Deferred<&mut [u8; 1024]> = unsafe { buffer.defer_mut() };
49//! // both `deferred` and `deferred_mut` can be safely immutably dereferenced simultaneously:
50//! assert_eq!(&deferred[0], &deferred_mut[0]);
51//! // we can mutate the `buffer` through `deferred_mut` as any other array.
52//! // this implicity creates a temporary mutable reference into the array inside `buffer`.
53//! // even though an immutable reference to `buffer` exists, this is okay because
54//! // the inner array sits inside an `UnsafeCell` which allows interior mutability:
55//! deferred_mut[0] = 42; 
56//! // and observe the change through `deferred`:
57//! assert_eq!(deferred[0], 42);
58//! // all this time, both deferred references are alive, but because
59//! // these are not actual references, this doesn't violate the Rust borrow
60//! // rules and this is not undefined behavior. The lifetimes of the mutable
61//! // and immutable references derived from the Deferred do not overlap,
62//! // so the Rust borrow rules are respected all this time.
63//! assert_eq!(&deferred[0], &deferred_mut[0]);
64//! // this also works for multiple deferred mutable references!
65//! // SAFETY: this is safe, because we promise not to create overlapping references
66//! let mut deferred_mut2 = unsafe { buffer.defer_mut() };
67//! // we can mutate the buffer through 2 distinct deferred mutable references
68//! // (as long as we don't do this at the same time!)
69//! deferred_mut[0] += 1; // the actual mutable borrow starts and ends here
70//! // the next line does not overlap with the previous, thanks to non-lexical lifetimes:
71//! deferred_mut2[0] += 1; 
72//! assert_eq!(44, deferred[0]);
73//! assert_eq!(deferred_mut[0], deferred_mut2[0]);
74//! // however, the following is not okay, because this would create two overlapping
75//! // mutable references and this is undefined behavior (hence the use of `unsafe` above):
76//! //assert_eq!(&mut deferred_mut[0], &mut deferred_mut2[0]); // undefined behavior!
77//! // because `Deferred` implements the `Index` and `IndexMut` trait, it is possible
78//! // to create two references that overlap in lifetime, but are disjoint in index:
79//! assert_eq!(&mut deferred_mut[1], &mut deferred_mut2[2]); // indices are disjoint, so no UB
80//! // this is not possible with regular slice references, because these alias the entire slice:
81//! //assert_eq!(&mut deferred_mut.deref_mut()[1], &mut deferred_mut2.deref_mut()[2]); // UB!
82//! ```
83//!
84//! # Why not use `<[T]>::split_at_mut` instead of `Deferred`?
85//! The Rust core library function [split_at_mut](<slice::split_at_mut>) provides a convenient method to safely split a mutable reference
86//! into two mutable references. However, it has one big drawback: in order to call it, you must already have the mutable reference.
87//! This might not always be possible. For example, in a multi-threaded environment, some threads may want to temporarily keep an
88//! immutable reference to a slice index because these threads only read, while some threads need a temporary mutable reference into
89//! another slice index. This is not possible if one thread holds a mutable reference to the entire slice, because then the co-existance
90//! of any mutable and immutable references would trigger undefined behavior. With deferred references, this is no longer a problem, because an
91//! initial mutable reference is not required. In fact, the first mutable reference is not even created until the first time the
92//! `Deferred<&mut>` is dereferenced. This crate also provides a method [Deferred::split_at_mut] which can split a deferred reference
93//! to a slice or an array into two deferred references. This method does not create any intermediary references to the subslices.
94//!
95//! # `#![no_std]` environments
96//! This crate is entirely `#![no_std]` and does not depend on the `alloc` crate. No additional `Cargo.toml` features need to be configured
97//! in order to support `#![no_std]` environments. This crate also does not have any dependencies in its `Cargo.toml`.
98//!
99//! # Miri tested
100//! This crate is extensively tested using [Miri](https://github.com/rust-lang/miri) using the `-Zmiri-track-raw-pointers` flag:
101//! ```bash
102//! $ MIRIFLAGS="-Zmiri-track-raw-pointers" cargo miri test
103//! ```
104//! Miri follows the [Stacked Borrows](https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md) model
105//! (by Ralf Jung et al.) and so does this crate. If you happen to spot any violations of this model in this crate, feel free
106//! to open a Github issue!
107//!
108//! # Footnotes
109//! [^1]: The concept of "deferred references" is inspired by the concept of "[Deferred Borrows](https://c1f.net/pubs/ecoop2020_defborrow.pdf)"
110//!       authored by Chris Fallin. However, these are not entirely the same concept. These differ in the sense that deferred borrows bring
111//!       an extension to the Rust type system (called *static path-dependent types*) and its implementation is intended to live within the
112//!       Rust compiler, while deferred references are implemented in Rust code that is already possible today with its existing type system.
113//!       The trade-off made here is that this requires minimal use of `unsafe` code blocks with deferred references, while deferred borrows
114//!       would work entirely within "safe Rust" if these were to be implemented in the Rust compiler. There are also some similarities between
115//!       the two concepts: both concepts are statically applied during compile-time and due not incur any runtime overhead. Also, with both
116//!       approaches an actual reference is not created until the reference is actually in use (i.e. dereferenced or borrowed for an extended
117//!       period of time).
118
119#![no_std]
120#![doc(html_root_url = "https://docs.rs/deferred-reference/0.1.2")]
121// the `slice_ptr_len` feature is needed for deferred references to slices
122#![cfg_attr(feature = "slice_ptr_len", feature(slice_ptr_len))]
123// experimental: the `coerce_unsized` feature is need to unsize the reference
124// through [Deferred::unsize], because we can't implement [CoerceUnsized] on
125// [Deferred] (yet, this gives compiler errors).
126#![cfg_attr(feature = "coerce_unsized", feature(coerce_unsized))]
127
128#![deny(missing_docs)]
129#![forbid(clippy::missing_docs_in_private_items)]
130
131// the `alloc` crate is only used for tests, but it is not used by this crate otherwise.
132#[cfg(test)] #[macro_use] extern crate alloc;
133
134
135// from <https://rust-lang.github.io/unsafe-code-guidelines/glossary.html>:
136// "Aliasing occurs when one pointer or reference points to a "span" of memory that overlaps
137// with the span of another pointer or reference. A span of memory is similar to how a slice
138// works: there's a base byte address as well as a length in bytes.
139// Note: a full aliasing model for Rust, defining when aliasing is allowed and when not, has
140// not yet been defined. The purpose of this definition is to define when aliasing happens,
141// not when it is allowed. The most developed potential aliasing model so far is Stacked Borrows."
142
143mod core_traits_impl;
144pub use core_traits_impl::*;
145
146mod defer;
147pub use defer::*;
148
149mod defer_mut;
150pub use defer_mut::*;
151
152mod deferred;
153pub use deferred::*;
154
155mod pointer_length;
156pub use pointer_length::*;
157
158mod reference;
159pub use reference::*;
160
161mod slice_like;
162pub use slice_like::*;
163
164mod slice_like_impl;
165pub use slice_like_impl::*;
166
167mod slice_pointer_index;
168pub use slice_pointer_index::*;
169
170
171#[cfg(test)]
172mod tests {
173    use alloc::boxed::Box;
174    use core::{cell::UnsafeCell, fmt::{Debug, Pointer}, ops::{Deref, DerefMut}};
175
176    use super::*;
177
178    #[test]
179    fn example() {
180        use crate::{Deferred, DeferMut};
181        use core::cell::UnsafeCell;
182        const N: usize = 1024;
183        let buffer = UnsafeCell::new([0usize; N]);
184        // SAFETY: this is safe because there are no references into `buffer` yet
185        let mut deferred1: Deferred<&mut [usize; N]> = unsafe { buffer.defer_mut() };
186        // SAFETY: this is safe because we promise not to create overlap with mutable references
187        let mut deferred2: Deferred<&mut [usize; N]> = unsafe { deferred1.clone_unchecked() };
188        assert_eq!(&mut deferred1[0..10], &mut deferred2[10..20]); // subslices do not overlap
189    }
190
191    /// A method to assert that `t` is still being used.
192    fn use_it<T: Pointer>(t: T) {
193        assert!(!format!("{:p}", t).is_empty());
194    }
195
196    #[test]
197    fn doctest1() {
198        let buffer = Box::new(UnsafeCell::new([0u8; 1024])); // the `Box` is optional
199        // calling defer() or defer_mut() immutably borrows `buffer` for as long
200        // as the returned `Deferred` is in use.
201        let deferred: Deferred<&[u8; 1024]> = buffer.defer();
202        // SAFETY: this is safe, because we promise not to create overlapping references
203        let mut deferred_mut: Deferred<&mut [u8; 1024]> = unsafe { buffer.defer_mut() };
204        // both `deferred` and `deferred_mut` can be safely immutably dereferenced simultaneously:
205        assert_eq!(&deferred[0], &deferred_mut[0]);
206        // we can mutate the `buffer` through `deferred_mut` as any other array.
207        // this implicity creates a temporary mutable reference into the array inside `buffer`.
208        // even though an immutable reference to `buffer` exists, this is okay because
209        // the inner array sits inside an `UnsafeCell` which allows interior mutability:
210        deferred_mut[0] = 42; 
211        // and observe the change through `deferred`:
212        assert_eq!(deferred[0], 42);
213        // all this time, both deferred references are alive, but because
214        // these are not actual references, this doesn't violate the Rust borrow
215        // rules and this is not undefined behavior. The lifetimes of the mutable
216        // and immutable references derived from the Deferred do not overlap,
217        // so the Rust borrow rules are respected all this time.
218        assert_eq!(&deferred[0], &deferred_mut[0]);
219        // this also works for multiple deferred mutable references!
220        // SAFETY: this is safe, because we promise not to create overlapping references
221        let mut deferred_mut2 = unsafe { buffer.defer_mut() };
222        // we can mutate the buffer through 2 distinct deferred mutable references
223        // (as long as we don't do this at the same time!)
224        deferred_mut[0] += 1; // the actual mutable borrow starts and ends here
225        // the next line does not overlap with the previous, thanks to non-lexical lifetimes:
226        deferred_mut2[0] += 1; 
227        assert_eq!(44, deferred[0]);
228        assert_eq!(deferred_mut[0], deferred_mut2[0]);
229        // however, the following is not okay, because this would create two overlapping
230        // mutable references and this is undefined behavior (hence the use of `unsafe` above):
231        //assert_eq!(&mut deferred_mut[0], &mut deferred_mut2[0]); // undefined behavior!
232        // because `Deferred` implements the `Index` and `IndexMut` trait, it is possible
233        // to create two references that overlap in lifetime, but are disjoint in index:
234        assert_eq!(&mut deferred_mut[1], &mut deferred_mut2[2]); // indices are disjoint, so no UB
235        // this is not possible with regular slice references, because these alias the entire slice:
236        //assert_eq!(&mut deferred_mut.deref_mut()[1], &mut deferred_mut2.deref_mut()[2]); // UB!
237    }
238
239    #[test]
240    fn dyn_trait_ref() {
241        // multi trait dyn refs are not allowed yet, except for auto traits:
242        // error[E0225]: only auto traits can be used as additional traits in a trait object
243        // this results in a single vtable in the pointer, hence this is a sized fat pointer
244        let x: Box<UnsafeCell<dyn core::fmt::Debug + Send + Sync + Unpin>> = Box::new(UnsafeCell::new(core::fmt::Error));
245        let _ = x.defer();
246    }
247
248    #[cfg(feature = "coerce_unsized")]
249    #[test]
250    fn test_coerce_unsized() {
251        let b = Box::new(UnsafeCell::new([0u8; 1024]));
252        let deferred1: Deferred<&[u8; 1024]> = b.defer();
253        let deferred2: Deferred<&[u8]> = deferred1.unsize();
254        assert_eq!(deferred1.len(), deferred2.len());
255        assert_eq!(deferred1.deref(), deferred2.deref());
256        assert_eq!(deferred1.len(), deferred2.len());
257    }
258
259    #[test]
260    fn test_copy() {
261        let b = Box::new(UnsafeCell::new([0u8; 1024]));
262        let deferred2;
263        {
264            let deferred1 = b.defer();
265            deferred2 = deferred1; // copies
266        }
267        //let x = b.get_mut(); // cannot borrow `*b` as mutable because it is also borrowed as immutable
268        use_it(deferred2);
269    }
270
271    #[test]
272    fn test_box() {
273        let b = Box::new(UnsafeCell::new([0u8; 1024]));
274        let _x = unsafe { b.defer_mut() };
275    }
276
277    #[test]
278    fn deref_mut_unsafe_cell() {
279        let /*mut*/ buffer = UnsafeCell::new([0u8; 1024]);
280        let mut deferred = unsafe { buffer.defer_mut() };
281        let mut deferred2 = unsafe { buffer.defer_mut() };
282        // let tmp = buffer.get_mut(); // not possible
283        // let tmp = &mut buffer; // not possible :)
284        let _t = deferred.deref_mut();
285        let _t = deferred.deref();
286        let _t = deferred.deref_mut();
287        let _t = deferred.deref();
288        let _t = deferred.deref_mut();
289        let _t = deferred.deref();
290        use_it(&deferred);
291        assert_eq!(deferred[0], deferred2[1]); // okay, immutable access
292        assert_eq!(&deferred[0], &mut deferred2[1]); // okay, indices are disjoint
293        assert_eq!(&mut deferred[0], &mut deferred2[1]); // okay, indices are disjoint
294        // assert_eq!(&mut deferred[0], &mut deferred2[0]); // not okay, references overlap
295    }
296
297    mod mut_wrapper {
298        use super::*;
299        use super::super::Defer;
300
301        #[derive(Default, Debug)]
302        pub struct MaliciousContainer {
303            pub container: UnsafeCell<[u8; 32]>,
304        }
305
306        impl MaliciousContainer {
307            fn get_mut(&mut self) -> Deferred<&mut [u8; 32]> {
308                Deferred::from(self.container.get_mut())
309            }
310        }
311        impl Defer for MaliciousContainer {
312            type Target = [u8; 32];
313
314            fn defer(&self) -> Deferred<&Self::Target> {
315                self.container.defer()
316            }
317        }
318        unsafe impl DeferMut for MaliciousContainer {
319            unsafe fn defer_mut(&self) -> Deferred<&mut Self::Target> {
320                self.container.defer_mut()
321            }
322        }
323
324        #[test]
325        fn try_to_trigger_ub() {
326            let mut malicious_container = MaliciousContainer::default();
327            // this mutable alias works all the way through the [u8; 32] inside the UnsafeCell
328            // UnsafeCell only protects immutable references, not mutable references!
329            // we ensure it exists until the end of the scope.
330            let mut_ref = &mut malicious_container;
331
332            let x = mut_ref.get_mut();
333            let y = x.deref();
334            assert_eq!(&0, &y[0]);
335            use_it(&x);
336            use_it(&y);
337
338            let mut x = unsafe { mut_ref.defer_mut() };
339            let y = x.deref_mut();
340            assert_eq!(&0, &mut y[0]);
341            use_it(&y);
342            use_it(&x);
343
344            let x = mut_ref.defer();
345            let xcopy = x;
346            let y = x.deref();
347            assert_eq!(&0, &y[0]);
348            use_it(&x);
349            use_it(&y);
350            
351            use_it(&mut_ref);
352            let xcopy = xcopy.deref();
353            use_it(&xcopy);
354            use_it(&mut_ref);
355        }
356    }
357}