Skip to content

Prohibit casts between fat pointers to different traits #26394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Item=u8>`) 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
Expand Down Expand Up @@ -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>),
Expand All @@ -75,7 +80,7 @@ fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-> Option<UnsizeKind<'tcx>> {
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,
Expand Down
6 changes: 6 additions & 0 deletions src/test/compile-fail/cast-rfc0401.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
trait Foo { fn foo(&self) {} }
impl<T> Foo for T {}

trait Bar { fn foo(&self) {} }
impl<T> Bar for T {}

enum E {
A, B
}
Expand Down Expand Up @@ -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
}
9 changes: 4 additions & 5 deletions src/test/run-pass/cast-rfc0401-vtable-kinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@ impl<T> Foo<T> for () {}
impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
impl Bar for () {}

unsafe fn fool<'a>(t: *const (Foo<u32>+'a)) -> u32 {
let bar : *const Bar = t as *const Bar;
unsafe fn round_trip_and_call<'a>(t: *const (Foo<u32>+'a)) -> u32 {
let foo_e : *const Foo<u16> = t as *const _;
let r_1 = foo_e as *mut Foo<u32>;

(&*r_1).foo(0)*(&*(bar as *const Foo<u32>)).foo(0)
(&*r_1).foo(0)
}

#[repr(C)]
Expand All @@ -43,8 +42,8 @@ fn foo_to_bar<T:?Sized>(u: *const FooS<T>) -> *const BarS<T> {
fn main() {
let x = 4u32;
let y : &Foo<u32> = &x;
let fl = unsafe { fool(y as *const Foo<u32>) };
assert_eq!(fl, (43+4)*(43+4));
let fl = unsafe { round_trip_and_call(y as *const Foo<u32>) };
assert_eq!(fl, (43+4));

let s = FooS([0,1,2]);
let u: &FooS<[u32]> = &s;
Expand Down
8 changes: 7 additions & 1 deletion src/test/run-pass/cast-rfc0401.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -99,6 +99,12 @@ fn main()
let l_via_str = unsafe{&*(s as *const [u8])};
assert_eq!(&l, l_via_str);

// 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]])};
assert_eq!(p, [[3, 2], [6, 4]]);

// enum-cast
assert_eq!(Simple::A as u8, 0);
assert_eq!(Simple::B as u8, 1);
Expand Down