Skip to content

Commit 03ca15e

Browse files
authored
Merge pull request rust-lang#267 from RalfJung/cast
Fix ptr-int-casts
2 parents 6e10752 + 4a34a1b commit 03ca15e

File tree

10 files changed

+184
-129
lines changed

10 files changed

+184
-129
lines changed

src/librustc_mir/interpret/cast.rs

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
44
use error::{EvalResult, EvalError};
55
use eval_context::EvalContext;
66
use value::PrimVal;
7+
use memory::{MemoryPointer, PointerArithmetic};
78

89
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
910
pub(super) fn cast_primval(
@@ -12,38 +13,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
1213
src_ty: Ty<'tcx>,
1314
dest_ty: Ty<'tcx>
1415
) -> EvalResult<'tcx, PrimVal> {
15-
let kind = self.ty_to_primval_kind(src_ty)?;
16-
17-
use value::PrimValKind::*;
18-
match kind {
19-
F32 => self.cast_float(val.to_f32()? as f64, dest_ty),
20-
F64 => self.cast_float(val.to_f64()?, dest_ty),
21-
22-
I8 | I16 | I32 | I64 | I128 => {
23-
if val.is_ptr() {
24-
self.cast_ptr(val, dest_ty)
25-
} else {
26-
self.cast_signed_int(val.to_i128()?, dest_ty)
16+
let src_kind = self.ty_to_primval_kind(src_ty)?;
17+
18+
match val {
19+
PrimVal::Undef => Ok(PrimVal::Undef),
20+
PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
21+
val @ PrimVal::Bytes(_) => {
22+
use value::PrimValKind::*;
23+
match src_kind {
24+
F32 => self.cast_from_float(val.to_f32()? as f64, dest_ty),
25+
F64 => self.cast_from_float(val.to_f64()?, dest_ty),
26+
27+
I8 | I16 | I32 | I64 | I128 => {
28+
self.cast_from_signed_int(val.to_i128()?, dest_ty)
29+
},
30+
31+
Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => {
32+
self.cast_from_int(val.to_u128()?, dest_ty, false)
33+
},
2734
}
28-
},
29-
30-
Bool | Char | U8 | U16 | U32 | U64 | U128 => {
31-
if val.is_ptr() {
32-
self.cast_ptr(val, dest_ty)
33-
} else {
34-
self.cast_int(val.to_u128()?, dest_ty, false)
35-
}
36-
},
37-
38-
FnPtr | Ptr => self.cast_ptr(val, dest_ty),
35+
}
3936
}
4037
}
4138

42-
fn cast_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
43-
self.cast_int(val as u128, ty, val < 0)
39+
fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
40+
self.cast_from_int(val as u128, ty, val < 0)
4441
}
4542

46-
fn cast_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
43+
fn cast_from_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
4744
use rustc::ty::TypeVariants::*;
4845
match ty.sty {
4946
// Casts to bool are not permitted by rustc, no need to handle them here.
@@ -63,13 +60,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
6360
TyInt(IntTy::Is) => {
6461
let int_ty = self.tcx.sess.target.int_type;
6562
let ty = self.tcx.mk_mach_int(int_ty);
66-
self.cast_int(v, ty, negative)
63+
self.cast_from_int(v, ty, negative)
6764
}
6865

6966
TyUint(UintTy::Us) => {
7067
let uint_ty = self.tcx.sess.target.uint_type;
7168
let ty = self.tcx.mk_mach_uint(uint_ty);
72-
self.cast_int(v, ty, negative)
69+
self.cast_from_int(v, ty, negative)
7370
}
7471

7572
TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)),
@@ -80,34 +77,34 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
8077
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
8178
TyChar => Err(EvalError::InvalidChar(v)),
8279

83-
// No alignment check needed for raw pointers
84-
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),
80+
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
81+
TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)),
8582

8683
_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
8784
}
8885
}
8986

90-
fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
87+
fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
9188
use rustc::ty::TypeVariants::*;
9289
match ty.sty {
9390
// Casting negative floats to unsigned integers yields zero.
94-
TyUint(_) if val < 0.0 => self.cast_int(0, ty, false),
95-
TyInt(_) if val < 0.0 => self.cast_int(val as i128 as u128, ty, true),
91+
TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false),
92+
TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true),
9693

97-
TyInt(_) | ty::TyUint(_) => self.cast_int(val as u128, ty, false),
94+
TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false),
9895

9996
TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)),
10097
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)),
10198
_ => Err(EvalError::Unimplemented(format!("float to {:?} cast", ty))),
10299
}
103100
}
104101

105-
fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
102+
fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
106103
use rustc::ty::TypeVariants::*;
107104
match ty.sty {
108105
// Casting to a reference or fn pointer is not permitted by rustc, no need to support it here.
109106
TyRawPtr(_) | TyInt(IntTy::Is) | TyUint(UintTy::Us) =>
110-
Ok(ptr),
107+
Ok(PrimVal::Ptr(ptr)),
111108
TyInt(_) | TyUint(_) => Err(EvalError::ReadPointerAsBytes),
112109
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
113110
}

src/librustc_mir/interpret/eval_context.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
439439
// FIXME(solson)
440440
let dest_ptr = self.force_allocation(dest)?.to_ptr()?;
441441

442-
let discr_dest = dest_ptr.offset(discr_offset, self.memory.layout)?;
442+
let discr_dest = dest_ptr.offset(discr_offset, &self)?;
443443
self.memory.write_uint(discr_dest, discr_val, discr_size)?;
444444

445445
let dest = Lvalue::Ptr {
@@ -585,7 +585,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
585585
// FIXME(solson)
586586
let dest = self.force_allocation(dest)?.to_ptr()?;
587587

588-
let dest = dest.offset(offset.bytes(), self.memory.layout)?;
588+
let dest = dest.offset(offset.bytes(), &self)?;
589589
let dest_size = self.type_size(ty)?
590590
.expect("bad StructWrappedNullablePointer discrfield");
591591
self.memory.write_int(dest, 0, dest_size)?;
@@ -645,7 +645,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
645645
let dest = Pointer::from(self.force_allocation(dest)?.to_ptr()?);
646646

647647
for i in 0..length {
648-
let elem_dest = dest.offset(i * elem_size, self.memory.layout)?;
648+
let elem_dest = dest.offset(i * elem_size, &self)?;
649649
self.write_value_to_ptr(value, elem_dest, elem_ty)?;
650650
}
651651
}
@@ -911,7 +911,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
911911
// FIXME: assuming here that type size is < i64::max_value()
912912
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
913913
let offset = offset.overflowing_mul(pointee_size).0;
914-
ptr.wrapping_signed_offset(offset, self.memory.layout)
914+
ptr.wrapping_signed_offset(offset, self)
915915
}
916916

917917
pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
@@ -926,7 +926,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
926926
// FIXME: assuming here that type size is < i64::max_value()
927927
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
928928
return if let Some(offset) = offset.checked_mul(pointee_size) {
929-
let ptr = ptr.signed_offset(offset, self.memory.layout)?;
929+
let ptr = ptr.signed_offset(offset, self)?;
930930
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
931931
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
932932
self.memory.check_bounds(ptr, false)?;
@@ -1217,8 +1217,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
12171217
let field_1_ty = self.get_field_ty(ty, 1)?;
12181218
let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
12191219
let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
1220-
self.memory.write_primval(ptr.offset(field_0, self.memory.layout)?.into(), a, field_0_size)?;
1221-
self.memory.write_primval(ptr.offset(field_1, self.memory.layout)?.into(), b, field_1_size)?;
1220+
let field_0_ptr = ptr.offset(field_0, &self)?.into();
1221+
let field_1_ptr = ptr.offset(field_1, &self)?.into();
1222+
self.memory.write_primval(field_0_ptr, a, field_0_size)?;
1223+
self.memory.write_primval(field_1_ptr, b, field_1_size)?;
12221224
Ok(())
12231225
}
12241226

@@ -1335,7 +1337,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13351337
Ok(p.to_value())
13361338
} else {
13371339
trace!("reading fat pointer extra of type {}", pointee_ty);
1338-
let extra = ptr.offset(self.memory.pointer_size(), self.memory.layout)?;
1340+
let extra = ptr.offset(self.memory.pointer_size(), self)?;
13391341
match self.tcx.struct_tail(pointee_ty).sty {
13401342
ty::TyDynamic(..) => Ok(p.to_value_with_vtable(self.memory.read_ptr(extra)?.to_ptr()?)),
13411343
ty::TySlice(..) |
@@ -1530,8 +1532,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15301532
}
15311533
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes();
15321534
let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
1533-
let src_f_ptr = src_ptr.offset(src_field_offset, self.memory.layout)?;
1534-
let dst_f_ptr = dest.offset(dst_field_offset, self.memory.layout)?;
1535+
let src_f_ptr = src_ptr.offset(src_field_offset, &self)?;
1536+
let dst_f_ptr = dest.offset(dst_field_offset, &self)?;
15351537
if src_fty == dst_fty {
15361538
self.copy(src_f_ptr, dst_f_ptr.into(), src_fty)?;
15371539
} else {

src/librustc_mir/interpret/lvalue.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
329329
_ => offset.bytes(),
330330
};
331331

332-
let ptr = base_ptr.offset(offset, self.memory.layout)?;
332+
let ptr = base_ptr.offset(offset, &self)?;
333333

334334
let field_ty = self.monomorphize(field_ty, self.substs());
335335

@@ -412,7 +412,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
412412
let usize = self.tcx.types.usize;
413413
let n = self.value_to_primval(n_ptr, usize)?.to_u64()?;
414414
assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
415-
let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?;
415+
let ptr = base_ptr.offset(n * elem_size, &self)?;
416416
(ptr, LvalueExtra::None, aligned)
417417
}
418418

@@ -431,7 +431,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
431431
u64::from(offset)
432432
};
433433

434-
let ptr = base_ptr.offset(index * elem_size, self.memory.layout)?;
434+
let ptr = base_ptr.offset(index * elem_size, &self)?;
435435
(ptr, LvalueExtra::None, aligned)
436436
}
437437

@@ -443,7 +443,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
443443
let (elem_ty, n) = base.elem_ty_and_len(base_ty);
444444
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
445445
assert!(u64::from(from) <= n - u64::from(to));
446-
let ptr = base_ptr.offset(u64::from(from) * elem_size, self.memory.layout)?;
446+
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
447447
let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from));
448448
(ptr, extra, aligned)
449449
}

0 commit comments

Comments
 (0)