Skip to content

Commit a5aa985

Browse files
authored
[pointer] Fix bug in try_cast_into_no_leftover (#2937)
Previously, `Ptr::try_cast_into_no_leftover` used the following logic to recover the original `Ptr` in the case of failure: ```rust match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { if remainder.len() == 0 { Ok(slf) } else { // Undo the cast so we can return the original bytes. let slf = slf.as_bytes(); ``` This is incorrect: In the case that `remainder.len() > 0`, `slf` no longer refers to the same referent as it did originally, as there are remainder bytes (either in the prefix or the suffix). In this commit, we use `Ptr::try_with` to restore the original `Ptr` exactly. gherrit-pr-id: G27c254ea62bb8b789e4fcd4a2e9e09a74676b45a
1 parent d161a87 commit a5aa985

File tree

1 file changed

+25
-23
lines changed

1 file changed

+25
-23
lines changed

src/pointer/ptr.rs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,30 +1162,18 @@ mod _casts {
11621162
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
11631163
[u8]: Read<I::Aliasing, R>,
11641164
{
1165-
// FIXME(#67): Remove this allow. See NonNullExt for more details.
1166-
#[allow(unstable_name_collisions)]
1167-
match self.try_cast_into(CastType::Prefix, meta) {
1168-
Ok((slf, remainder)) => {
1169-
if remainder.len() == 0 {
1170-
Ok(slf)
1171-
} else {
1172-
// Undo the cast so we can return the original bytes.
1173-
let slf = slf.as_bytes();
1174-
// Restore the initial alignment invariant of `self`.
1175-
//
1176-
// SAFETY: The referent type of `slf` is now equal to
1177-
// that of `self`, but the alignment invariants
1178-
// nominally differ. Since `slf` and `self` refer to the
1179-
// same memory and no actions have been taken that would
1180-
// violate the original invariants on `self`, it is
1181-
// sound to apply the alignment invariant of `self` onto
1182-
// `slf`.
1183-
let slf = unsafe { slf.assume_alignment::<I::Alignment>() };
1184-
let slf = slf.unify_invariants();
1185-
Err(CastError::Size(SizeError::<_, U>::new(slf)))
1165+
// SAFETY: The provided closure returns the only copy of `slf`.
1166+
unsafe {
1167+
self.try_with_unchecked(|slf| match slf.try_cast_into(CastType::Prefix, meta) {
1168+
Ok((slf, remainder)) => {
1169+
if remainder.len() == 0 {
1170+
Ok(slf)
1171+
} else {
1172+
Err(CastError::Size(SizeError::<_, U>::new(())))
1173+
}
11861174
}
1187-
}
1188-
Err(err) => Err(err),
1175+
Err(err) => Err(err.map_src(|_slf| ())),
1176+
})
11891177
}
11901178
}
11911179
}
@@ -1523,4 +1511,18 @@ mod tests {
15231511
// succeed.
15241512
test!(Dst, 8, usize::MAX - 8 + 1, None);
15251513
}
1514+
1515+
#[test]
1516+
fn test_try_cast_into_no_leftover_restores_original_slice() {
1517+
let bytes = [0u8; 4];
1518+
let ptr = Ptr::from_ref(&bytes[..]);
1519+
let res = ptr.try_cast_into_no_leftover::<[u8; 2], BecauseImmutable>(None);
1520+
match res {
1521+
Ok(_) => panic!("should have failed due to leftover bytes"),
1522+
Err(CastError::Size(e)) => {
1523+
assert_eq!(e.into_src().len(), 4, "Should return original slice length");
1524+
}
1525+
Err(e) => panic!("wrong error type: {:?}", e),
1526+
}
1527+
}
15261528
}

0 commit comments

Comments
 (0)