From ea7637ebc0e5d325ccf0537a8013316c2ed78108 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 18 Jun 2015 15:51:06 +0300 Subject: [PATCH 1/2] Prohibit casts between fat pointers to different traits This makes them compliant with the new version of RFC 401 (i.e. RFC 1052). Fixes #26391. I *hope* the tests I have are enough. This is a [breaking-change] --- src/librustc_typeck/check/cast.rs | 11 ++++++++--- src/test/compile-fail/cast-rfc0401.rs | 6 ++++++ src/test/run-pass/cast-rfc0401-vtable-kinds.rs | 9 ++++----- src/test/run-pass/cast-rfc0401.rs | 6 ++++++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 6e306047f75c9..2b0ed06f1ae59 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -27,7 +27,12 @@ //! //! where `&.T` and `*T` are references of either mutability, //! and where unsize_kind(`T`) is the kind of the unsize info -//! in `T` - a vtable or a length (or `()` if `T: Sized`). +//! in `T` - the vtable for a trait definition (e.g. `fmt::Display` or +//! `Iterator`, not `Iterator`) or a length (or `()` if `T: Sized`). +//! +//! Note that lengths are not adjusted when casting raw slices - +//! `T: *const [u16] as *const [u8]` creates a slice that only includes +//! half of the original memory. //! //! Casting is not transitive, that is, even if `e as U1 as U2` is a valid //! expression, `e as U2` is not necessarily so (in fact it will only be valid if @@ -60,7 +65,7 @@ pub struct CastCheck<'tcx> { /// fat pointers if their unsize-infos have the same kind. #[derive(Copy, Clone, PartialEq, Eq)] enum UnsizeKind<'tcx> { - Vtable, + Vtable(ast::DefId), Length, /// The unsize info of this projection OfProjection(&'tcx ty::ProjectionTy<'tcx>), @@ -75,7 +80,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>, -> Option> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), - ty::TyTrait(_) => Some(UnsizeKind::Vtable), + ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())), ty::TyStruct(did, substs) => { match ty::struct_fields(fcx.tcx(), did, substs).pop() { None => None, diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs index f3537e5413508..29ce8c15143f5 100644 --- a/src/test/compile-fail/cast-rfc0401.rs +++ b/src/test/compile-fail/cast-rfc0401.rs @@ -21,6 +21,9 @@ fn illegal_cast_2(u: *const U) -> *const str trait Foo { fn foo(&self) {} } impl Foo for T {} +trait Bar { fn foo(&self) {} } +impl Bar for T {} + enum E { A, B } @@ -72,4 +75,7 @@ fn main() // check no error cascade let _ = main.f as *const u32; //~ ERROR attempted access of field + let cf: *const Foo = &0; + let _ = cf as *const [u8]; //~ ERROR vtable kinds + let _ = cf as *const Bar; //~ ERROR vtable kinds } diff --git a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs index e53d4af8e36cb..3a9f24ad4cc7c 100644 --- a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs @@ -23,12 +23,11 @@ impl Foo for () {} impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} -unsafe fn fool<'a>(t: *const (Foo+'a)) -> u32 { - let bar : *const Bar = t as *const Bar; +unsafe fn round_trip_and_call<'a>(t: *const (Foo+'a)) -> u32 { let foo_e : *const Foo = t as *const _; let r_1 = foo_e as *mut Foo; - (&*r_1).foo(0)*(&*(bar as *const Foo)).foo(0) + (&*r_1).foo(0) } #[repr(C)] @@ -43,8 +42,8 @@ fn foo_to_bar(u: *const FooS) -> *const BarS { fn main() { let x = 4u32; let y : &Foo = &x; - let fl = unsafe { fool(y as *const Foo) }; - assert_eq!(fl, (43+4)*(43+4)); + let fl = unsafe { round_trip_and_call(y as *const Foo) }; + assert_eq!(fl, (43+4)); let s = FooS([0,1,2]); let u: &FooS<[u32]> = &s; diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs index 7c64c34fae5ce..efbf265bd80cf 100644 --- a/src/test/run-pass/cast-rfc0401.rs +++ b/src/test/run-pass/cast-rfc0401.rs @@ -99,6 +99,12 @@ fn main() let l_via_str = unsafe{&*(s as *const [u8])}; assert_eq!(&l, l_via_str); + // ptr-ptr-cast (both vk=Length, check length is preserved) + let l: [[u8; 3]; 2] = [[3, 2, 6], [4, 5, 1]]; + let p: *const [[u8; 3]] = &l; + let p: &[[u8; 2]] = unsafe {&*(p as *const [[u8; 2]])}; + assert_eq!(p, [[3, 2], [6, 4]]); + // enum-cast assert_eq!(Simple::A as u8, 0); assert_eq!(Simple::B as u8, 1); From 51336064b1c640db9bb4e84a6f9b29b2d0a301f0 Mon Sep 17 00:00:00 2001 From: arielb1 Date: Fri, 19 Jun 2015 17:10:26 +0300 Subject: [PATCH 2/2] address review comments --- src/test/run-pass/cast-rfc0401.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/cast-rfc0401.rs b/src/test/run-pass/cast-rfc0401.rs index efbf265bd80cf..5b6f6ccc627a4 100644 --- a/src/test/run-pass/cast-rfc0401.rs +++ b/src/test/run-pass/cast-rfc0401.rs @@ -88,7 +88,7 @@ fn main() assert_eq!(u as *const u8, p as *const u8); assert_eq!(u as *const u16, p as *const u16); - // ptr-ptr-cast (both vk=Length) + // ptr-ptr-cast (Length vtables) let mut l : [u8; 2] = [0,1]; let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _; let w: *mut [u16] = unsafe {&mut *w}; @@ -99,7 +99,7 @@ fn main() let l_via_str = unsafe{&*(s as *const [u8])}; assert_eq!(&l, l_via_str); - // ptr-ptr-cast (both vk=Length, check length is preserved) + // ptr-ptr-cast (Length vtables, check length is preserved) let l: [[u8; 3]; 2] = [[3, 2, 6], [4, 5, 1]]; let p: *const [[u8; 3]] = &l; let p: &[[u8; 2]] = unsafe {&*(p as *const [[u8; 2]])};