Skip to content

Commit ce342f5

Browse files
committed
auto merge of #18041 : arielb1/rust/no-size-overflow, r=pnkfelix
Should fix #17913. Also clean-up u64/u32-ness. I really should split this commit and add tests (I have no idea how to add them).
2 parents d670919 + ccdf8d5 commit ce342f5

24 files changed

+388
-142
lines changed

src/librustc/middle/trans/_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10901090
let sw = if kind == Switch {
10911091
build::Switch(bcx, test_val, else_cx.llbb, opts.len())
10921092
} else {
1093-
C_int(ccx, 0) // Placeholder for when not using a switch
1093+
C_int(ccx, 0i) // Placeholder for when not using a switch
10941094
};
10951095

10961096
let defaults = enter_default(else_cx, dm, m, col, val);

src/librustc/middle/trans/adt.rs

+97-54
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545

4646
#![allow(unsigned_negate)]
4747

48-
use libc::c_ulonglong;
4948
use std::collections::Map;
5049
use std::num::Int;
5150
use std::rc::Rc;
@@ -132,7 +131,7 @@ pub struct Struct {
132131
// If the struct is DST, then the size and alignment do not take into
133132
// account the unsized fields of the struct.
134133
pub size: u64,
135-
pub align: u64,
134+
pub align: u32,
136135
pub sized: bool,
137136
pub packed: bool,
138137
pub fields: Vec<ty::t>
@@ -164,7 +163,7 @@ pub fn represent_type(cx: &CrateContext, t: ty::t) -> Rc<Repr> {
164163
fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
165164
match ty::get(t).sty {
166165
ty::ty_tup(ref elems) => {
167-
return Univariant(mk_struct(cx, elems.as_slice(), false), false)
166+
return Univariant(mk_struct(cx, elems.as_slice(), false, t), false)
168167
}
169168
ty::ty_struct(def_id, ref substs) => {
170169
let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
@@ -175,12 +174,12 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
175174
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
176175
if dtor { ftys.push(ty::mk_bool()); }
177176

178-
return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
177+
return Univariant(mk_struct(cx, ftys.as_slice(), packed, t), dtor)
179178
}
180179
ty::ty_unboxed_closure(def_id, _) => {
181180
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
182181
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
183-
return Univariant(mk_struct(cx, upvar_types.as_slice(), false),
182+
return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t),
184183
false)
185184
}
186185
ty::ty_enum(def_id, ref substs) => {
@@ -195,7 +194,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
195194
// (Typechecking will reject discriminant-sizing attrs.)
196195
assert_eq!(hint, attr::ReprAny);
197196
let ftys = if dtor { vec!(ty::mk_bool()) } else { vec!() };
198-
return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
197+
return Univariant(mk_struct(cx, ftys.as_slice(), false, t),
198+
dtor);
199199
}
200200

201201
if !dtor && cases.iter().all(|c| c.tys.len() == 0) {
@@ -226,15 +226,17 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
226226
assert_eq!(hint, attr::ReprAny);
227227
let mut ftys = cases.get(0).tys.clone();
228228
if dtor { ftys.push(ty::mk_bool()); }
229-
return Univariant(mk_struct(cx, ftys.as_slice(), false), dtor);
229+
return Univariant(mk_struct(cx, ftys.as_slice(), false, t),
230+
dtor);
230231
}
231232

232233
if !dtor && cases.len() == 2 && hint == attr::ReprAny {
233234
// Nullable pointer optimization
234235
let mut discr = 0;
235236
while discr < 2 {
236-
if cases.get(1 - discr).is_zerolen(cx) {
237-
let st = mk_struct(cx, cases.get(discr).tys.as_slice(), false);
237+
if cases.get(1 - discr).is_zerolen(cx, t) {
238+
let st = mk_struct(cx, cases.get(discr).tys.as_slice(),
239+
false, t);
238240
match cases.get(discr).find_ptr() {
239241
Some(ThinPointer(_)) if st.fields.len() == 1 => {
240242
return RawNullablePointer {
@@ -264,11 +266,15 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
264266
slo: 0, shi: (cases.len() - 1) as i64 };
265267
let ity = range_to_inttype(cx, hint, &bounds);
266268

267-
return General(ity, cases.iter().map(|c| {
269+
let fields : Vec<_> = cases.iter().map(|c| {
268270
let mut ftys = vec!(ty_of_inttype(ity)).append(c.tys.as_slice());
269271
if dtor { ftys.push(ty::mk_bool()); }
270-
mk_struct(cx, ftys.as_slice(), false)
271-
}).collect(), dtor);
272+
mk_struct(cx, ftys.as_slice(), false, t)
273+
}).collect();
274+
275+
ensure_enum_fits_in_address_space(cx, ity, fields.as_slice(), t);
276+
277+
General(ity, fields, dtor)
272278
}
273279
_ => cx.sess().bug(format!("adt::represent_type called on non-ADT type: {}",
274280
ty_to_string(cx.tcx(), t)).as_slice())
@@ -289,8 +295,8 @@ pub enum PointerField {
289295
}
290296

291297
impl Case {
292-
fn is_zerolen(&self, cx: &CrateContext) -> bool {
293-
mk_struct(cx, self.tys.as_slice(), false).size == 0
298+
fn is_zerolen(&self, cx: &CrateContext, scapegoat: ty::t) -> bool {
299+
mk_struct(cx, self.tys.as_slice(), false, scapegoat).size == 0
294300
}
295301

296302
fn find_ptr(&self) -> Option<PointerField> {
@@ -345,29 +351,25 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<
345351
}).collect()
346352
}
347353

348-
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
349-
if tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty)) {
350-
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
351-
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
352-
Struct {
353-
size: machine::llsize_of_alloc(cx, llty_rec),
354-
align: machine::llalign_of_min(cx, llty_rec),
355-
sized: true,
356-
packed: packed,
357-
fields: Vec::from_slice(tys),
358-
}
354+
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool, scapegoat: ty::t) -> Struct {
355+
let sized = tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty));
356+
let lltys : Vec<Type> = if sized {
357+
tys.iter()
358+
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
359359
} else {
360-
// Ignore any dynamically sized fields.
361-
let lltys = tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
362-
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
363-
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
364-
Struct {
365-
size: machine::llsize_of_alloc(cx, llty_rec),
366-
align: machine::llalign_of_min(cx, llty_rec),
367-
sized: false,
368-
packed: packed,
369-
fields: Vec::from_slice(tys),
370-
}
360+
tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
361+
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
362+
};
363+
364+
ensure_struct_fits_in_address_space(cx, lltys.as_slice(), packed, scapegoat);
365+
366+
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
367+
Struct {
368+
size: machine::llsize_of_alloc(cx, llty_rec),
369+
align: machine::llalign_of_min(cx, llty_rec),
370+
sized: sized,
371+
packed: packed,
372+
fields: Vec::from_slice(tys),
371373
}
372374
}
373375

@@ -463,6 +465,51 @@ pub fn ty_of_inttype(ity: IntType) -> ty::t {
463465
}
464466
}
465467

468+
// LLVM doesn't like types that don't fit in the address space
469+
fn ensure_struct_fits_in_address_space(ccx: &CrateContext,
470+
fields: &[Type],
471+
packed: bool,
472+
scapegoat: ty::t) {
473+
let mut offset = 0;
474+
for &llty in fields.iter() {
475+
// Invariant: offset < ccx.max_obj_size() <= 1<<61
476+
if !packed {
477+
let type_align = machine::llalign_of_min(ccx, llty);
478+
offset = roundup(offset, type_align);
479+
}
480+
// type_align is a power-of-2, so still offset < ccx.max_obj_size()
481+
// llsize_of_alloc(ccx, llty) is also less than ccx.max_obj_size()
482+
// so the sum is less than 1<<62 (and therefore can't overflow).
483+
offset += machine::llsize_of_alloc(ccx, llty);
484+
485+
if offset >= ccx.max_obj_size() {
486+
ccx.report_overbig_object(scapegoat);
487+
}
488+
}
489+
}
490+
491+
fn union_size_and_align(sts: &[Struct]) -> (machine::llsize, machine::llalign) {
492+
let size = sts.iter().map(|st| st.size).max().unwrap();
493+
let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
494+
(size, most_aligned.align)
495+
}
496+
497+
fn ensure_enum_fits_in_address_space(ccx: &CrateContext,
498+
discr: IntType,
499+
fields: &[Struct],
500+
scapegoat: ty::t) {
501+
let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr));
502+
let (field_size, field_align) = union_size_and_align(fields);
503+
504+
// field_align < 1<<32, discr_size <= 8, field_size < MAX_OBJ_SIZE <= 1<<61
505+
// so the sum is less than 1<<62 (and can't overflow).
506+
let total_size = roundup(discr_size, field_align) + field_size;
507+
508+
if total_size >= ccx.max_obj_size() {
509+
ccx.report_overbig_object(scapegoat);
510+
}
511+
}
512+
466513

467514
/**
468515
* LLVM-level types are a little complicated.
@@ -525,13 +572,12 @@ fn generic_type_of(cx: &CrateContext,
525572
// of the size.
526573
//
527574
// FIXME #10604: this breaks when vector types are present.
528-
let size = sts.iter().map(|st| st.size).max().unwrap();
529-
let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
530-
let align = most_aligned.align;
575+
let (size, align) = union_size_and_align(sts.as_slice());
576+
let align_s = align as u64;
531577
let discr_ty = ll_inttype(cx, ity);
532-
let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64;
533-
let align_units = (size + align - 1) / align - 1;
534-
let pad_ty = match align {
578+
let discr_size = machine::llsize_of_alloc(cx, discr_ty);
579+
let align_units = (size + align_s - 1) / align_s - 1;
580+
let pad_ty = match align_s {
535581
1 => Type::array(&Type::i8(cx), align_units),
536582
2 => Type::array(&Type::i16(cx), align_units),
537583
4 => Type::array(&Type::i32(cx), align_units),
@@ -541,10 +587,10 @@ fn generic_type_of(cx: &CrateContext,
541587
align_units),
542588
_ => fail!("unsupported enum alignment: {}", align)
543589
};
544-
assert_eq!(machine::llalign_of_min(cx, pad_ty) as u64, align);
545-
assert_eq!(align % discr_size, 0);
590+
assert_eq!(machine::llalign_of_min(cx, pad_ty), align);
591+
assert_eq!(align_s % discr_size, 0);
546592
let fields = vec!(discr_ty,
547-
Type::array(&discr_ty, align / discr_size - 1),
593+
Type::array(&discr_ty, align_s / discr_size - 1),
548594
pad_ty);
549595
match name {
550596
None => Type::struct_(cx, fields.as_slice(), false),
@@ -653,9 +699,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
653699
} else {
654700
// llvm::ConstantRange can deal with ranges that wrap around,
655701
// so an overflow on (max + 1) is fine.
656-
LoadRangeAssert(bcx, ptr, min as c_ulonglong,
657-
(max + 1) as c_ulonglong,
658-
/* signed: */ True)
702+
LoadRangeAssert(bcx, ptr, min, (max+1), /* signed: */ True)
659703
}
660704
}
661705

@@ -974,11 +1018,11 @@ fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec<u64> {
9741018
for &ty in st.fields.iter() {
9751019
let llty = type_of::sizing_type_of(ccx, ty);
9761020
if !st.packed {
977-
let type_align = type_of::align_of(ccx, ty) as u64;
1021+
let type_align = type_of::align_of(ccx, ty);
9781022
offset = roundup(offset, type_align);
9791023
}
9801024
offsets.push(offset);
981-
offset += machine::llsize_of_alloc(ccx, llty) as u64;
1025+
offset += machine::llsize_of_alloc(ccx, llty);
9821026
}
9831027
assert_eq!(st.fields.len(), offsets.len());
9841028
offsets
@@ -1005,8 +1049,7 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
10051049
let mut cfields = Vec::new();
10061050
for (&val, &target_offset) in vals.iter().zip(target_offsets.iter()) {
10071051
if !st.packed {
1008-
let val_align = machine::llalign_of_min(ccx, val_ty(val))
1009-
/*bad*/as u64;
1052+
let val_align = machine::llalign_of_min(ccx, val_ty(val));
10101053
offset = roundup(offset, val_align);
10111054
}
10121055
if offset != target_offset {
@@ -1015,7 +1058,7 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
10151058
}
10161059
assert!(!is_undef(val));
10171060
cfields.push(val);
1018-
offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64;
1061+
offset += machine::llsize_of_alloc(ccx, val_ty(val));
10191062
}
10201063

10211064
assert!(st.sized && offset <= st.size);
@@ -1032,7 +1075,7 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
10321075

10331076
// FIXME this utility routine should be somewhere more general
10341077
#[inline]
1035-
fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
1078+
fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a }
10361079

10371080
/// Get the discriminant of a constant value. (Not currently used.)
10381081
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)

src/librustc/middle/trans/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ pub fn malloc_raw_dyn_proc<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: ty::t) -> Resu
398398

399399
let llty = type_of(bcx.ccx(), t);
400400
let size = llsize_of(bcx.ccx(), llty);
401-
let llalign = C_uint(ccx, llalign_of_min(bcx.ccx(), llty) as uint);
401+
let llalign = C_uint(ccx, llalign_of_min(bcx.ccx(), llty));
402402

403403
// Allocate space and store the destructor pointer:
404404
let Result {bcx: bcx, val: llbox} = malloc_raw_dyn(bcx, ptr_llty, t, size, llalign);

src/librustc/middle/trans/build.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use syntax::codemap::Span;
2121
use middle::trans::builder::Builder;
2222
use middle::trans::type_::Type;
2323

24-
use libc::{c_uint, c_ulonglong, c_char};
24+
use libc::{c_uint, c_char};
2525

2626
pub fn terminate(cx: Block, _: &str) {
2727
debug!("terminate({})", cx.to_str());
@@ -380,8 +380,8 @@ pub fn AtomicLoad(cx: Block, pointer_val: ValueRef, order: AtomicOrdering) -> Va
380380
}
381381

382382

383-
pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: c_ulonglong,
384-
hi: c_ulonglong, signed: llvm::Bool) -> ValueRef {
383+
pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: u64,
384+
hi: u64, signed: llvm::Bool) -> ValueRef {
385385
if cx.unreachable.get() {
386386
let ccx = cx.fcx.ccx;
387387
let ty = val_ty(pointer_val);

src/librustc/middle/trans/builder.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use middle::trans::common::*;
1919
use middle::trans::machine::llalign_of_pref;
2020
use middle::trans::type_::Type;
2121
use std::collections::HashMap;
22-
use libc::{c_uint, c_ulonglong, c_char};
22+
use libc::{c_uint, c_char};
2323
use std::string::String;
2424
use syntax::codemap::Span;
2525

@@ -477,8 +477,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
477477
}
478478

479479

480-
pub fn load_range_assert(&self, ptr: ValueRef, lo: c_ulonglong,
481-
hi: c_ulonglong, signed: llvm::Bool) -> ValueRef {
480+
pub fn load_range_assert(&self, ptr: ValueRef, lo: u64,
481+
hi: u64, signed: llvm::Bool) -> ValueRef {
482482
let value = self.load(ptr);
483483

484484
unsafe {
@@ -490,7 +490,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
490490

491491
llvm::LLVMSetMetadata(value, llvm::MD_range as c_uint,
492492
llvm::LLVMMDNodeInContext(self.ccx.llcx(),
493-
v.as_ptr(), v.len() as c_uint));
493+
v.as_ptr(),
494+
v.len() as c_uint));
494495
}
495496

496497
value

0 commit comments

Comments
 (0)