@@ -31,17 +31,32 @@ mod _def {
3131 {
3232 /// # Invariants
3333 ///
34- /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from
35- /// some valid Rust allocation, `A`.
36- /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid
37- /// provenance for `A`.
38- /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a
39- /// byte range which is entirely contained in `A`.
40- /// 3. `ptr` addresses a byte range whose length fits in an `isize`.
41- /// 4. `ptr` addresses a byte range which does not wrap around the
42- /// address space.
43- /// 5. If `ptr`'s referent is not zero sized,`A` is guaranteed to live
34+ /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
35+ /// provenance for its referent, which is entirely contained in some
36+ /// Rust allocation, `A`.
37+ /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
4438 /// for at least `'a`.
39+ ///
40+ /// # Postconditions
41+ ///
42+ /// By virtue of these invariants, code may assume the following, which
43+ /// are logical implications of the invariants:
44+ /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\]
45+ /// - `ptr`'s referent does not wrap around the address space \[1\]
46+ ///
47+ /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>:
48+ ///
49+ /// For any allocated object with `base` address, `size`, and a set of
50+ /// `addresses`, the following are guaranteed:
51+ /// ...
52+ /// - `size <= isize::MAX`
53+ ///
54+ /// As a consequence of these guarantees, given any address `a` within
55+ /// the set of addresses of an allocated object:
56+ /// ...
57+ /// - It is guaranteed that, given `o = a - base` (i.e., the offset of
58+ /// `a` within the allocated object), `base + o` will not wrap around
59+ /// the address space (in other words, will not overflow `usize`)
4560 ptr : NonNull < T > ,
4661 // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T`
4762 // [1]. We use this construction rather than the equivalent `&mut T`,
@@ -67,17 +82,11 @@ mod _def {
6782 ///
6883 /// The caller promises that:
6984 ///
70- /// 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from
71- /// some valid Rust allocation, `A`.
72- /// 1. If `ptr`'s referent is not zero sized, then `ptr` has valid
73- /// provenance for `A`.
74- /// 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a
75- /// byte range which is entirely contained in `A`.
76- /// 3. `ptr` addresses a byte range whose length fits in an `isize`.
77- /// 4. `ptr` addresses a byte range which does not wrap around the
78- /// address space.
79- /// 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to
80- /// live for at least `'a`.
85+ /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
86+ /// provenance for its referent, which is entirely contained in some
87+ /// Rust allocation, `A`.
88+ /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
89+ /// for at least `'a`.
8190 pub ( crate ) const unsafe fn new ( ptr : NonNull < T > ) -> PtrInner < ' a , T > {
8291 // SAFETY: The caller has promised to satisfy all safety invariants
8392 // of `PtrInner`.
@@ -102,18 +111,23 @@ impl<'a, T: ?Sized> PtrInner<'a, T> {
102111 let ptr = NonNull :: from ( ptr) ;
103112 // SAFETY:
104113 // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
105- // `&'a T`, is derived from some valid Rust allocation, `A`.
106- // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
107- // `&'a T`, has valid provenance for `A`.
108- // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
109- // `&'a T`, addresses a byte range which is entirely contained in
110- // `A`.
111- // 3. `ptr`, by invariant on `&'a T`, addresses a byte range whose
112- // length fits in an `isize`.
113- // 4. `ptr`, by invariant on `&'a T`, addresses a byte range which does
114- // not wrap around the address space.
115- // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on
114+ // `&'a T` [1], has valid provenance for its referent, which is
115+ // entirely contained in some Rust allocation, `A`.
116+ // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
116117 // `&'a T`, is guaranteed to live for at least `'a`.
118+ //
119+ // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
120+ //
121+ // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
122+ // when such values cross an API boundary, the following invariants
123+ // must generally be upheld:
124+ // ...
125+ // - if `size_of_val(t) > 0`, then `t` is dereferenceable for
126+ // `size_of_val(t)` many bytes
127+ //
128+ // If `t` points at address `a`, being “dereferenceable” for N bytes
129+ // means that the memory range `[a, a + N)` is all contained within a
130+ // single allocated object.
117131 unsafe { Self :: new ( ptr) }
118132 }
119133
@@ -123,18 +137,23 @@ impl<'a, T: ?Sized> PtrInner<'a, T> {
123137 let ptr = NonNull :: from ( ptr) ;
124138 // SAFETY:
125139 // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
126- // `&'a mut T`, is derived from some valid Rust allocation, `A`.
127- // 1. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
128- // `&'a mut T`, has valid provenance for `A`.
129- // 2. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
130- // `&'a mut T`, addresses a byte range which is entirely contained in
131- // `A`.
132- // 3. `ptr`, by invariant on `&'a mut T`, addresses a byte range whose
133- // length fits in an `isize`.
134- // 4. `ptr`, by invariant on `&'a mut T`, addresses a byte range which
135- // does not wrap around the address space.
136- // 5. If `ptr`'s referent is not zero sized, then `A`, by invariant on
140+ // `&'a mut T` [1], has valid provenance for its referent, which is
141+ // entirely contained in some Rust allocation, `A`.
142+ // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
137143 // `&'a mut T`, is guaranteed to live for at least `'a`.
144+ //
145+ // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
146+ //
147+ // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
148+ // when such values cross an API boundary, the following invariants
149+ // must generally be upheld:
150+ // ...
151+ // - if `size_of_val(t) > 0`, then `t` is dereferenceable for
152+ // `size_of_val(t)` many bytes
153+ //
154+ // If `t` points at address `a`, being “dereferenceable” for N bytes
155+ // means that the memory range `[a, a + N)` is all contained within a
156+ // single allocated object.
138157 unsafe { Self :: new ( ptr) }
139158 }
140159}
@@ -168,34 +187,24 @@ impl<'a, T> PtrInner<'a, [T]> {
168187
169188 let ptr = core:: ptr:: slice_from_raw_parts_mut ( base, len) ;
170189
171- // SAFETY: By invariant, `self`'s address is non-null and its range does
172- // not wrap around the address space. Since, by the preceding lemma,
173- // `ptr` addresses a range within that addressed by `self`, `ptr` is
174- // non-null.
190+ // SAFETY: By invariant, `self`'s referent is either a ZST or lives
191+ // entirely in an allocation. `ptr` points inside of or one byte past
192+ // the end of that referent. Thus, in either case, `ptr` is non-null.
175193 let ptr = unsafe { NonNull :: new_unchecked ( ptr) } ;
176194
177195 // SAFETY:
178196 //
179197 // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`,
180198 // and has the same provenance. Proof: The caller guarantees
181- // that `start <= end <= self.len()`. Thus, `base` is in-bounds of
182- // `self`, and `base + (end - start)` is also in-bounds of self.
183- // Finally, `ptr` is constructed using provenance-preserving
184- // operations.
199+ // that `start <= end <= self.len()`. Thus, `base` is in-bounds
200+ // of `self`, and `base + (end - start)` is also in-bounds of
201+ // self. Finally, `ptr` is constructed using
202+ // provenance-preserving operations.
185203 //
186204 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
187- // zero sized, then `ptr` is derived from some valid Rust allocation ,
188- // `A`.
205+ // zero sized, then `ptr` has valid provenance for its referent ,
206+ // which is entirely contained in some Rust allocation, `A`.
189207 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
190- // zero sized, then `ptr` has valid provenance for `A`.
191- // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
192- // zero sized, then `ptr` addresses a byte range which is entirely
193- // contained in `A`.
194- // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
195- // range whose length fits in an `isize`.
196- // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
197- // range which does not wrap around the address space.
198- // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
199208 // zero sized, then `A` is guaranteed to live for at least `'a`.
200209 unsafe { PtrInner :: new ( ptr) }
201210 }
@@ -267,30 +276,23 @@ impl<'a, T> PtrInner<'a, [T]> {
267276 // provenance, cite those docs.
268277 let elem = unsafe { base. add ( i) } ;
269278
270- // SAFETY:
271- // - `elem` must not be null. `base` is constructed from a
272- // `NonNull` pointer, and the addition that produces `elem` must
273- // not overflow or wrap around, so `elem >= base > 0`.
279+ // SAFETY: `elem` must not be null. `base` is constructed from a
280+ // `NonNull` pointer, and the addition that produces `elem` must not
281+ // overflow or wrap around, so `elem >= base > 0`.
274282 //
275283 // TODO(#429): Once `NonNull::new_unchecked` documents that it
276284 // preserves provenance, cite those docs.
277285 let elem = unsafe { NonNull :: new_unchecked ( elem) } ;
278286
279287 // SAFETY: The safety invariants of `Ptr::new` (see definition) are
280288 // satisfied:
281- // 0. If `elem`'s referent is not zero sized, then `elem` is derived
282- // from a valid Rust allocation, because `self` is derived from a
283- // valid Rust allocation, by invariant on `Ptr`.
284- // 1. If `elem`'s referent is not zero sized, then `elem` has valid
285- // provenance for `self`, because it derived from `self` using a
286- // series of provenance-preserving operations.
287- // 2. If `elem`'s referent is not zero sized, then `elem` is
288- // entirely contained in the allocation of `self` (see above).
289- // 3. `elem` addresses a byte range whose length fits in an `isize`
290- // (see above).
291- // 4. `elem` addresses a byte range which does not wrap around the
292- // address space (see above).
293- // 5. If `elem`'s referent is not zero sized, then the allocation of
289+ // 0. If `elem`'s referent is not zero sized, then `elem` has valid
290+ // provenance for its referent, because it derived from `self`
291+ // using a series of provenance-preserving operations, and
292+ // because `self` has valid provenance for its referent. By the
293+ // same argument, `elem`'s referent is entirely contained within
294+ // the same allocated object as `self`'s referent.
295+ // 1. If `elem`'s referent is not zero sized, then the allocation of
294296 // `elem` is guaranteed to live for at least `'a`, because `elem`
295297 // is entirely contained in `self`, which lives for at least `'a`
296298 // by invariant on `Ptr`.
@@ -346,25 +348,11 @@ impl<'a, T, const N: usize> PtrInner<'a, [T; N]> {
346348 // same allocation as `self`, if any.
347349 //
348350 // 0. By the above lemma, if `slice`'s referent is not zero sized, then
349- // `slice` is derived from the same allocation as `self`, which, by
350- // invariant on `Ptr`, is valid.
351+ // `slice` has the same referent as `self`. By invariant on `self`,
352+ // this referent is entirely contained within some allocation, `A`.
353+ // Because `slice` was constructed using provenance-preserving
354+ // operations, it has provenance for its entire referent.
351355 // 1. By the above lemma, if `slice`'s referent is not zero sized, then
352- // , `slice` has valid provenance for `A`, since it is derived from
353- // the pointer `self`, which, by invariant on `Ptr`, has valid
354- // provenance for `A`.
355- // 2. By the above lemma, if `slice`'s referent is not zero sized, then
356- // `slice` addresses a byte range which is entirely contained in `A`,
357- // because it references exactly the same byte range as `self`,
358- // which, by invariant on `Ptr`, is entirely contained in `A`.
359- // 3. By the above lemma, `slice` addresses a byte range whose length
360- // fits in an `isize`, since it addresses exactly the same byte range
361- // as `self`, which, by invariant on `Ptr`, has a length that fits in
362- // an `isize`.
363- // 4. By the above lemma, `slice` addresses a byte range which does not
364- // wrap around the address space, since it addresses exactly the same
365- // byte range as `self`, which, by invariant on `Ptr`, does not wrap
366- // around the address space.
367- // 5. By the above lemma, if `slice`'s referent is not zero sized, then
368356 // `A` is guaranteed to live for at least `'a`, because it is derived
369357 // from the same allocation as `self`, which, by invariant on `Ptr`,
370358 // lives for at least `'a`.
@@ -464,26 +452,16 @@ impl<'a> PtrInner<'a, [u8]> {
464452
465453 // SAFETY:
466454 // 0. By invariant, if `target`'s referent is not zero sized, then
467- // `target` is derived from some valid Rust allocation, `A`. By
468- // contract on `cast`, `ptr` is derived from `self`, and thus from
469- // the same valid Rust allocation, `A`.
470- // 1. By invariant, if `target`'s referent is not zero sized, then
471455 // `target` has provenance valid for some Rust allocation, `A`.
472456 // Because `ptr` is derived from `target` via provenance-preserving
473- // operations, `ptr` will also have provenance valid for `A`.
474- // - `validate_cast_and_convert_metadata` promises that the object
457+ // operations, `ptr` will also have provenance valid for its entire
458+ // referent.
459+ // 1. `validate_cast_and_convert_metadata` promises that the object
475460 // described by `elems` and `split_at` lives at a byte range which is
476- // a subset of the input byte range. Thus:
477- // 2. Since, by invariant, if `target`'s referent is not zero sized,
478- // then `target` addresses a byte range which is entirely
479- // contained in `A`, so does `ptr`.
480- // 3. Since, by invariant, `target` addresses a byte range whose
481- // length fits in an `isize`, so does `ptr`.
482- // 4. Since, by invariant, `target` addresses a byte range which does
483- // not wrap around the address space, so does `ptr`.
484- // 5. Since, by invariant, if `target`'s referent is not zero sized,
485- // then `target` refers to an allocation which is guaranteed to
486- // live for at least `'a`, so does `ptr`.
461+ // a subset of the input byte range. Thus, by invariant, if
462+ // `target`'s referent is not zero sized, then `target` refers to an
463+ // allocation which is guaranteed to live for at least `'a`, and thus
464+ // so does `ptr`.
487465 Ok ( ( unsafe { PtrInner :: new ( ptr) } , remainder) )
488466 }
489467}
0 commit comments