Skip to content

Commit 4029dea

Browse files
committed
[pointer] Fix bug in try_cast_into_no_leftover
gherrit-pr-id: G27c254ea62bb8b789e4fcd4a2e9e09a74676b45a
1 parent 62ba5db commit 4029dea

1 file changed

Lines changed: 37 additions & 23 deletions

File tree

src/pointer/ptr.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,18 @@ mod _casts {
995995
}
996996
}
997997

998+
impl<Src, NewSrc, Dst> Map<NewSrc> for crate::CastError<Src, Dst>
999+
where
1000+
Dst: ?Sized,
1001+
{
1002+
type Input = Src;
1003+
type Output = crate::CastError<NewSrc, Dst>;
1004+
1005+
fn map<F: FnOnce(Src) -> NewSrc>(self, f: F) -> Self::Output {
1006+
self.map_src(f)
1007+
}
1008+
}
1009+
9981010
impl<'a, T, I> Ptr<'a, T, I>
9991011
where
10001012
T: 'a + KnownLayout + ?Sized,
@@ -1159,30 +1171,18 @@ mod _casts {
11591171
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
11601172
[u8]: Read<I::Aliasing, R>,
11611173
{
1162-
// FIXME(#67): Remove this allow. See NonNullExt for more details.
1163-
#[allow(unstable_name_collisions)]
1164-
match self.try_cast_into(CastType::Prefix, meta) {
1165-
Ok((slf, remainder)) => {
1166-
if remainder.len() == 0 {
1167-
Ok(slf)
1168-
} else {
1169-
// Undo the cast so we can return the original bytes.
1170-
let slf = slf.as_bytes();
1171-
// Restore the initial alignment invariant of `self`.
1172-
//
1173-
// SAFETY: The referent type of `slf` is now equal to
1174-
// that of `self`, but the alignment invariants
1175-
// nominally differ. Since `slf` and `self` refer to the
1176-
// same memory and no actions have been taken that would
1177-
// violate the original invariants on `self`, it is
1178-
// sound to apply the alignment invariant of `self` onto
1179-
// `slf`.
1180-
let slf = unsafe { slf.assume_alignment::<I::Alignment>() };
1181-
let slf = slf.unify_invariants();
1182-
Err(CastError::Size(SizeError::<_, U>::new(slf)))
1174+
// SAFETY: The provided closure returns the only copy of `slf`.
1175+
unsafe {
1176+
self.try_with_unchecked(|slf| match slf.try_cast_into(CastType::Prefix, meta) {
1177+
Ok((slf, remainder)) => {
1178+
if remainder.len() == 0 {
1179+
Ok(slf)
1180+
} else {
1181+
Err(CastError::Size(SizeError::<_, U>::new(())))
1182+
}
11831183
}
1184-
}
1185-
Err(err) => Err(err),
1184+
Err(err) => Err(err.map_src(|_slf| ())),
1185+
})
11861186
}
11871187
}
11881188
}
@@ -1520,4 +1520,18 @@ mod tests {
15201520
// succeed.
15211521
test!(Dst, 8, usize::MAX - 8 + 1, None);
15221522
}
1523+
1524+
#[test]
1525+
fn test_try_cast_into_no_leftover_restores_original_slice() {
1526+
let bytes = [0u8; 4];
1527+
let ptr = Ptr::from_ref(&bytes[..]);
1528+
let res = ptr.try_cast_into_no_leftover::<u16, BecauseImmutable>(None);
1529+
match res {
1530+
Ok(_) => panic!("should have failed due to leftover bytes"),
1531+
Err(CastError::Size(e)) => {
1532+
assert_eq!(e.into_src().len(), 4, "Should return original slice length");
1533+
}
1534+
Err(e) => panic!("wrong error type: {:?}", e),
1535+
}
1536+
}
15231537
}

0 commit comments

Comments
 (0)