Skip to content

Commit e98c7f7

Browse files
committed
Use wrapping pointer arithmetic in the bitpacked io::Error
1 parent f950edb commit e98c7f7

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

library/std/src/io/error/repr_bitpacked.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@
4747
//! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
4848
//! are free to use for the tag.
4949
//!
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.
5354
//!
5455
//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
5556
//! in the pointer's most significant 32 bits, and don't use the bits `2..32`
@@ -126,11 +127,14 @@ impl Repr {
126127
// Should only be possible if an allocator handed out a pointer with
127128
// wrong alignment.
128129
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
130131
// end of file), and both the start and end of the expression must be
131132
// 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::<()>();
134138
// Safety: the above safety comment also means the result can't be null.
135139
let res = Self(unsafe { NonNull::new_unchecked(tagged) });
136140
// quickly smoke-check we encoded the right thing (This generally will
@@ -238,7 +242,10 @@ where
238242
}
239243
TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
240244
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>();
242249
ErrorData::Custom(make_custom(custom))
243250
}
244251
_ => {
@@ -337,7 +344,7 @@ static_assert!(align_of::<SimpleMessage>() >= 4);
337344
static_assert!(align_of::<Custom>() >= 4);
338345

339346
// 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.
341348
static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
342349
// These two store a payload which is allowed to be zero, so they must be
343350
// non-zero to preserve the `NonNull`'s range invariant.

0 commit comments

Comments
 (0)