|
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