|
47 | 47 | //! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
|
48 | 48 | //! are free to use for the tag.
|
49 | 49 | //!
|
50 |
| -//! The only important thing to note is that `ptr::add` and `ptr::sub` are |
51 |
| -//! used to tag the pointer, rather than bitwise operations. This should |
52 |
| -//! preserve the pointer's provenance, which would otherwise be lost. |
| 50 | +//! The only important thing to note is that `ptr::wrapping_add` and |
| 51 | +//! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise |
| 52 | +//! operations. This should preserve the pointer's provenance, which would |
| 53 | +//! otherwise be lost. |
53 | 54 | //!
|
54 | 55 | //! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
|
55 | 56 | //! in the pointer's most significant 32 bits, and don't use the bits `2..32`
|
@@ -126,11 +127,14 @@ impl Repr {
|
126 | 127 | // Should only be possible if an allocator handed out a pointer with
|
127 | 128 | // wrong alignment.
|
128 | 129 | debug_assert_eq!((p as usize & TAG_MASK), 0);
|
129 |
| - // Safety: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at |
| 130 | + // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at |
130 | 131 | // end of file), and both the start and end of the expression must be
|
131 | 132 | // valid without address space wraparound due to `Box`'s semantics.
|
132 |
| - // Note: `add` is used as a provenance-preserving way of pointer tagging. |
133 |
| - let tagged = unsafe { p.add(TAG_CUSTOM).cast::<()>() }; |
| 133 | + // |
| 134 | + // This means it would be correct to implement this using `ptr::add` |
| 135 | + // (rather than `ptr::wrapping_add`), but it's unclear this would give |
| 136 | + // any benefit, so we just use `wrapping_add` instead. |
| 137 | + let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>(); |
134 | 138 | // Safety: the above safety comment also means the result can't be null.
|
135 | 139 | let res = Self(unsafe { NonNull::new_unchecked(tagged) });
|
136 | 140 | // quickly smoke-check we encoded the right thing (This generally will
|
@@ -238,7 +242,10 @@ where
|
238 | 242 | }
|
239 | 243 | TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
|
240 | 244 | TAG_CUSTOM => {
|
241 |
| - let custom = ptr.as_ptr().cast::<u8>().sub(TAG_CUSTOM).cast::<Custom>(); |
| 245 | + // It would be correct for us to use `ptr::sub` here (see the |
| 246 | + // comment above the `wrapping_add` call in `new_custom` for why), |
| 247 | + // but it isn't clear that it makes a difference, so we don't. |
| 248 | + let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>(); |
242 | 249 | ErrorData::Custom(make_custom(custom))
|
243 | 250 | }
|
244 | 251 | _ => {
|
@@ -337,7 +344,7 @@ static_assert!(align_of::<SimpleMessage>() >= 4);
|
337 | 344 | static_assert!(align_of::<Custom>() >= 4);
|
338 | 345 |
|
339 | 346 | // This is obviously true (`TAG_CUSTOM` is `0b01`), but our implementation of
|
340 |
| -// `Repr::new_custom` and such would be UB if it were not, so we check. |
| 347 | +// `Repr::new_custom` and such would be wrong if it were not, so we check. |
341 | 348 | static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
|
342 | 349 | // These two store a payload which is allowed to be zero, so they must be
|
343 | 350 | // non-zero to preserve the `NonNull`'s range invariant.
|
|
0 commit comments