Skip to content

Commit 9378e3a

Browse files
committed
Fix a bunch of bugs
* segfault due to not copying drop flag when coercing * fat pointer casts * segfault due to not checking drop flag properly * debuginfo for DST smart pointers * unreachable code in drop glue
1 parent 7e20e1f commit 9378e3a

File tree

11 files changed

+122
-51
lines changed

11 files changed

+122
-51
lines changed

src/liballoc/rc.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,8 @@ impl<T: ?Sized> Drop for Rc<T> {
544544
fn drop(&mut self) {
545545
unsafe {
546546
let ptr = *self._ptr;
547-
if !(*(&ptr as *const _ as *const *const ())).is_null() {
547+
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
548+
ptr as usize != mem::POST_DROP_USIZE {
548549
self.dec_strong();
549550
if self.strong() == 0 {
550551
// destroy the contained object
@@ -1011,7 +1012,8 @@ impl<T: ?Sized> Drop for Weak<T> {
10111012
fn drop(&mut self) {
10121013
unsafe {
10131014
let ptr = *self._ptr;
1014-
if !(*(&ptr as *const _ as *const *const ())).is_null() {
1015+
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
1016+
ptr as usize != mem::POST_DROP_USIZE {
10151017
self.dec_weak();
10161018
// the weak count starts at 1, and will only go to zero if all
10171019
// the strong pointers have disappeared.

src/librustc/middle/ty.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -5390,8 +5390,7 @@ impl DtorKind {
53905390
}
53915391
}
53925392

5393-
/* If struct_id names a struct with a dtor, return Some(the dtor's id).
5394-
Otherwise return none. */
5393+
/* If struct_id names a struct with a dtor. */
53955394
pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind {
53965395
match cx.destructor_for_type.borrow().get(&struct_id) {
53975396
Some(&method_def_id) => {

src/librustc_trans/trans/adt.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
143143

144144
/// Decides how to represent a given type.
145145
pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
146-
t: Ty<'tcx>) -> Rc<Repr<'tcx>> {
146+
t: Ty<'tcx>)
147+
-> Rc<Repr<'tcx>> {
147148
debug!("Representing: {}", ty_to_string(cx.tcx(), t));
148149
match cx.adt_reprs().borrow().get(&t) {
149150
Some(repr) => return repr.clone(),
@@ -218,7 +219,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
218219
}).collect::<Vec<_>>();
219220
let packed = ty::lookup_packed(cx.tcx(), def_id);
220221
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
221-
if dtor { ftys.push(cx.tcx().dtor_type()); }
222+
if dtor {
223+
ftys.push(cx.tcx().dtor_type());
224+
}
222225

223226
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
224227
}
@@ -499,8 +502,7 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
499502
-> Struct<'tcx> {
500503
let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty));
501504
let lltys : Vec<Type> = if sized {
502-
tys.iter()
503-
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
505+
tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
504506
} else {
505507
tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty))
506508
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
@@ -1041,7 +1043,9 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
10411043
}
10421044

10431045
/// Access the struct drop flag, if present.
1044-
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef)
1046+
pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
1047+
r: &Repr<'tcx>,
1048+
val: ValueRef)
10451049
-> datum::DatumBlock<'blk, 'tcx, datum::Expr>
10461050
{
10471051
let tcx = bcx.tcx();

src/librustc_trans/trans/debuginfo.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,7 @@ fn pointer_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
18721872
// Common facilities for record-like types (structs, enums, tuples)
18731873
//=-----------------------------------------------------------------------------
18741874

1875+
#[derive(Debug)]
18751876
enum MemberOffset {
18761877
FixedMemberOffset { bytes: usize },
18771878
// For ComputedMemberOffset, the offset is read from the llvm type definition
@@ -1880,6 +1881,7 @@ enum MemberOffset {
18801881

18811882
// Description of a type member, which can either be a regular field (as in
18821883
// structs or tuples) or an enum variant
1884+
#[derive(Debug)]
18831885
struct MemberDescription {
18841886
name: String,
18851887
llvm_type: Type,
@@ -1995,7 +1997,7 @@ impl<'tcx> RecursiveTypeDescription<'tcx> {
19951997
set_members_of_composite_type(cx,
19961998
metadata_stub,
19971999
llvm_type,
1998-
&member_descriptions[..]);
2000+
&member_descriptions);
19992001
return MetadataCreationResult::new(metadata_stub, true);
20002002
}
20012003
}
@@ -2061,7 +2063,7 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
20612063
span: Span)
20622064
-> RecursiveTypeDescription<'tcx> {
20632065
let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
2064-
let struct_llvm_type = type_of::type_of(cx, struct_type);
2066+
let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type);
20652067

20662068
let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
20672069

src/librustc_trans/trans/expr.rs

+32-17
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ use middle::check_const;
5858
use middle::def;
5959
use middle::lang_items::CoerceUnsizedTraitLangItem;
6060
use middle::mem_categorization::Typer;
61-
use middle::subst::{Subst, Substs, VecPerParamSpace};
61+
use middle::subst::{Substs, VecPerParamSpace};
6262
use middle::traits;
6363
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
6464
use trans::base::*;
@@ -471,8 +471,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
471471
}
472472

473473
// This can be extended to enums and tuples in the future.
474-
// (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) |
475-
(&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => {
474+
// (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) |
475+
(&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
476476
assert_eq!(def_id_a, def_id_b);
477477

478478
// The target is already by-ref because it's to be written to.
@@ -499,35 +499,41 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
499499
};
500500

501501
let repr_source = adt::represent_type(bcx.ccx(), source.ty);
502+
let src_fields = match &*repr_source {
503+
&adt::Repr::Univariant(ref s, _) => &s.fields,
504+
_ => bcx.sess().span_bug(span,
505+
&format!("Non univariant struct? (repr_source: {:?})",
506+
repr_source)),
507+
};
502508
let repr_target = adt::represent_type(bcx.ccx(), target.ty);
503-
let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a);
509+
let target_fields = match &*repr_target {
510+
&adt::Repr::Univariant(ref s, _) => &s.fields,
511+
_ => bcx.sess().span_bug(span,
512+
&format!("Non univariant struct? (repr_target: {:?})",
513+
repr_target)),
514+
};
504515

505516
let coerce_index = match kind {
506517
ty::CustomCoerceUnsized::Struct(i) => i
507518
};
508-
assert!(coerce_index < fields.len());
519+
assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
509520

510-
for (i, field) in fields.iter().enumerate() {
521+
let iter = src_fields.iter().zip(target_fields.iter()).enumerate();
522+
for (i, (src_ty, target_ty)) in iter {
511523
let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
512524
let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);
513525

514-
let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(),
515-
def_id_a,
516-
field.id);
517-
let field_source = ty.subst(bcx.tcx(), substs_a);
518-
let field_target = ty.subst(bcx.tcx(), substs_b);
519-
520526
// If this is the field we need to coerce, recurse on it.
521527
if i == coerce_index {
522528
coerce_unsized(bcx, span,
523-
Datum::new(ll_source, field_source,
529+
Datum::new(ll_source, src_ty,
524530
Rvalue::new(ByRef)),
525-
Datum::new(ll_target, field_target,
531+
Datum::new(ll_target, target_ty,
526532
Rvalue::new(ByRef)));
527533
} else {
528534
// Otherwise, simply copy the data from the source.
529-
assert_eq!(field_source, field_target);
530-
memcpy_ty(bcx, ll_target, ll_source, field_source);
535+
assert_eq!(src_ty, target_ty);
536+
memcpy_ty(bcx, ll_target, ll_source, src_ty);
531537
}
532538
}
533539
}
@@ -2008,6 +2014,7 @@ fn float_cast(bcx: Block,
20082014
#[derive(Copy, Clone, PartialEq, Debug)]
20092015
pub enum cast_kind {
20102016
cast_pointer,
2017+
cast_fat_ptr,
20112018
cast_integral,
20122019
cast_float,
20132020
cast_enum,
@@ -2022,7 +2029,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
20222029
if type_is_sized(tcx, mt.ty) {
20232030
cast_pointer
20242031
} else {
2025-
cast_other
2032+
cast_fat_ptr
20262033
}
20272034
}
20282035
ty::ty_bare_fn(..) => cast_pointer,
@@ -2098,10 +2105,18 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
20982105
let llexpr = datum.to_llscalarish(bcx);
20992106
PtrToInt(bcx, llexpr, ll_t_out)
21002107
}
2108+
(cast_fat_ptr, cast_integral) => {
2109+
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
2110+
PtrToInt(bcx, data_ptr, ll_t_out)
2111+
}
21012112
(cast_pointer, cast_pointer) => {
21022113
let llexpr = datum.to_llscalarish(bcx);
21032114
PointerCast(bcx, llexpr, ll_t_out)
21042115
}
2116+
(cast_fat_ptr, cast_pointer) => {
2117+
let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
2118+
PointerCast(bcx, data_ptr, ll_t_out)
2119+
}
21052120
(cast_enum, cast_integral) |
21062121
(cast_enum, cast_float) => {
21072122
let mut bcx = bcx;

src/librustc_trans/trans/glue.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,14 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
225225

226226
fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
227227
t: Ty<'tcx>,
228-
v0: ValueRef,
228+
struct_data: ValueRef,
229229
dtor_did: ast::DefId,
230230
class_did: ast::DefId,
231231
substs: &subst::Substs<'tcx>)
232232
-> Block<'blk, 'tcx> {
233+
assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
234+
233235
let repr = adt::represent_type(bcx.ccx(), t);
234-
let struct_data = if type_is_sized(bcx.tcx(), t) {
235-
v0
236-
} else {
237-
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
238-
Load(bcx, llval)
239-
};
240236
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
241237
let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
242238
let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
@@ -260,9 +256,8 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
260256

261257
let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
262258
with_cond(bcx, drop_flag_dtor_needed, |cx| {
263-
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
259+
trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs)
264260
})
265-
266261
}
267262

268263
pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,

src/librustc_trans/trans/machine.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign {
101101

102102
pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 {
103103
unsafe {
104-
return llvm::LLVMOffsetOfElement(cx.td().lltd, struct_ty.to_ref(),
104+
return llvm::LLVMOffsetOfElement(cx.td().lltd,
105+
struct_ty.to_ref(),
105106
element as u32);
106107
}
107108
}

src/librustc_typeck/check/cast.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
9999
let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
100100
let t_1_is_float = ty::type_is_floating_point(t_1);
101101
let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1);
102+
let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
102103

103104
// casts to scalars other than `char` and `bare fn` are trivial
104105
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
@@ -170,17 +171,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
170171
demand::coerce(fcx, e.span, t_1, &e);
171172
}
172173
}
173-
} else if fcx.type_is_fat_ptr(t_e, span) && !fcx.type_is_fat_ptr(t_1, span) {
174+
} else if t1_is_fat_ptr {
175+
// FIXME This should be allowed where the lefthandside is also a fat
176+
// pointer as is the same kind of fat pointer, i.e., array to array,
177+
// trait object to trait object.
174178
fcx.type_error_message(span, |actual| {
175-
format!("illegal cast; cast from fat pointer: `{}` as `{}`",
176-
actual, fcx.infcx().ty_to_string(t_1))
179+
format!("cast to fat pointer: `{}` as `{}`",
180+
actual,
181+
fcx.infcx().ty_to_string(t_1))
177182
}, t_e, None);
178183
} else if !(t_e_is_scalar && t_1_is_trivial) {
179-
/*
180-
If more type combinations should be supported than are
181-
supported here, then file an enhancement issue and
182-
record the issue number in this comment.
183-
*/
184184
fcx.type_error_message(span, |actual| {
185185
format!("non-scalar cast: `{}` as `{}`",
186186
actual,

src/test/compile-fail/fat-ptr-cast.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
fn main() {
1212
let a: &[i32] = &[1, 2, 3];
1313
let b: Box<[i32]> = Box::new([1, 2, 3]);
14-
let p = a as *const [i32];
1514

16-
a as usize; //~ ERROR cast from fat pointer
17-
b as usize; //~ ERROR cast from fat pointer
18-
p as usize; //~ ERROR cast from fat pointer
15+
a as usize; //~ ERROR non-scalar cast: `&[i32]` as `usize`
16+
b as usize; //~ ERROR non-scalar cast: `Box<[i32]>` as `usize`
17+
18+
let a: usize = 42;
19+
a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
20+
21+
let a: *const u8 = &42;
22+
a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
1923
}

src/test/compile-fail/issue-22289.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
// except according to those terms.
1010

1111
fn main() {
12-
0 as &std::any::Any; //~ ERROR non-scalar cast: `i32` as `&core::any::Any`
12+
0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any`
1313
}

src/test/run-pass/fat-ptr-cast.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(core)]
12+
13+
use std::mem;
14+
use std::raw;
15+
16+
trait Foo {
17+
fn foo(&self) {}
18+
}
19+
20+
struct Bar;
21+
22+
impl Foo for Bar {}
23+
24+
fn main() {
25+
// Test we can turn a fat pointer to array back into a thin pointer.
26+
let a: *const [i32] = &[1, 2, 3];
27+
let b = a as *const [i32; 2];
28+
unsafe {
29+
assert!(*b == [1, 2]);
30+
}
31+
32+
// Test conversion to an address (usize).
33+
let a: *const [i32; 3] = &[1, 2, 3];
34+
let b: *const [i32] = a;
35+
assert!(a as usize == b as usize);
36+
37+
// And conversion to a void pointer/address for trait objects too.
38+
let a: *mut Foo = &mut Bar;
39+
let b = a as *mut ();
40+
let c = a as usize;
41+
42+
let d = unsafe {
43+
let r: raw::TraitObject = mem::transmute(a);
44+
r.data
45+
};
46+
47+
assert!(b == d);
48+
assert!(c == d as usize);
49+
}

0 commit comments

Comments
 (0)