Skip to content

Commit d539faf

Browse files
authored
Merge pull request #200 from oli-obk/master
Get rid of the integer allocation (Round 2)
2 parents 2302f2b + a6cd7a2 commit d539faf

27 files changed

+691
-300
lines changed

.travis.yml

+6-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ before_script:
1010
- cargo install xargo
1111
- export RUST_SYSROOT=$HOME/rust
1212
script:
13+
- |
14+
# get ourselves a MIR-ful libstd
15+
cd xargo &&
16+
RUSTFLAGS='-Zalways-encode-mir' xargo build &&
17+
cd ..
1318
- |
1419
# Test plain miri
1520
cargo build &&
@@ -22,11 +27,7 @@ script:
2227
cargo miri test &&
2328
cd ..
2429
- |
25-
# get ourselves a MIR-ful libstd
26-
cd xargo &&
27-
RUSTFLAGS='-Zalways-encode-mir' xargo build &&
28-
cd .. &&
29-
# and run the tests with it
30+
# and run all tests with full mir
3031
MIRI_SYSROOT=~/.xargo/HOST cargo test
3132
notifications:
3233
email:

src/cast.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
33

44
use error::{EvalResult, EvalError};
55
use eval_context::EvalContext;
6-
use memory::Pointer;
76
use value::PrimVal;
87

98
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
@@ -24,7 +23,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
2423

2524
Bool | Char | U8 | U16 | U32 | U64 | U128 => self.cast_int(val.to_u128()?, dest_ty, false),
2625

27-
FnPtr | Ptr => self.cast_ptr(val.to_ptr()?, dest_ty),
26+
FnPtr | Ptr => self.cast_ptr(val, dest_ty),
2827
}
2928
}
3029

@@ -71,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
7170
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
7271
TyChar => Err(EvalError::InvalidChar(v)),
7372

74-
TyRawPtr(_) => Ok(PrimVal::Ptr(Pointer::from_int(v as u64))),
73+
TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),
7574

7675
_ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
7776
}
@@ -92,11 +91,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9291
}
9392
}
9493

95-
fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
94+
fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
9695
use rustc::ty::TypeVariants::*;
9796
match ty.sty {
9897
TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) =>
99-
Ok(PrimVal::Ptr(ptr)),
98+
Ok(ptr),
10099
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
101100
}
102101
}

src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub enum EvalError<'tcx> {
2222
allocation_size: u64,
2323
},
2424
ReadPointerAsBytes,
25+
ReadBytesAsPointer,
2526
InvalidPointerMath,
2627
ReadUndefBytes,
2728
DeadLocal,
@@ -81,6 +82,8 @@ impl<'tcx> Error for EvalError<'tcx> {
8182
"pointer offset outside bounds of allocation",
8283
EvalError::ReadPointerAsBytes =>
8384
"a raw memory access tried to access part of a pointer value as raw bytes",
85+
EvalError::ReadBytesAsPointer =>
86+
"a memory access tried to interpret some bytes as a pointer",
8487
EvalError::InvalidPointerMath =>
8588
"attempted to do math or a comparison on pointers into different allocations",
8689
EvalError::ReadUndefBytes =>

src/eval_context.rs

+62-37
Large diffs are not rendered by default.

src/lvalue.rs

+33-13
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use value::{PrimVal, Value};
1212
pub enum Lvalue<'tcx> {
1313
/// An lvalue referring to a value allocated in the `Memory` system.
1414
Ptr {
15-
ptr: Pointer,
15+
/// An lvalue may have an invalid (integral or undef) pointer,
16+
/// since it might be turned back into a reference
17+
/// before ever being dereferenced.
18+
ptr: PrimVal,
1619
extra: LvalueExtra,
1720
},
1821

@@ -61,22 +64,35 @@ pub struct Global<'tcx> {
6164
}
6265

6366
impl<'tcx> Lvalue<'tcx> {
64-
pub fn from_ptr(ptr: Pointer) -> Self {
67+
/// Produces an Lvalue that will error if attempted to be read from
68+
pub fn undef() -> Self {
69+
Self::from_primval_ptr(PrimVal::Undef)
70+
}
71+
72+
fn from_primval_ptr(ptr: PrimVal) -> Self {
6573
Lvalue::Ptr { ptr, extra: LvalueExtra::None }
6674
}
6775

68-
pub(super) fn to_ptr_and_extra(self) -> (Pointer, LvalueExtra) {
76+
pub fn zst() -> Self {
77+
Self::from_ptr(Pointer::zst_ptr())
78+
}
79+
80+
pub fn from_ptr(ptr: Pointer) -> Self {
81+
Self::from_primval_ptr(PrimVal::Ptr(ptr))
82+
}
83+
84+
pub(super) fn to_ptr_and_extra(self) -> (PrimVal, LvalueExtra) {
6985
match self {
7086
Lvalue::Ptr { ptr, extra } => (ptr, extra),
7187
_ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self),
7288

7389
}
7490
}
7591

76-
pub(super) fn to_ptr(self) -> Pointer {
92+
pub(super) fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
7793
let (ptr, extra) = self.to_ptr_and_extra();
7894
assert_eq!(extra, LvalueExtra::None);
79-
ptr
95+
ptr.to_ptr()
8096
}
8197

8298
pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
@@ -127,7 +143,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
127143
match lvalue {
128144
Lvalue::Ptr { ptr, extra } => {
129145
assert_eq!(extra, LvalueExtra::None);
130-
Ok(Value::ByRef(ptr))
146+
Ok(Value::ByRef(ptr.to_ptr()?))
131147
}
132148
Lvalue::Local { frame, local, field } => {
133149
self.stack[frame].get_local(local, field.map(|(i, _)| i))
@@ -167,7 +183,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
167183
field_ty: Ty<'tcx>,
168184
) -> EvalResult<'tcx, Lvalue<'tcx>> {
169185
let base_layout = self.type_layout(base_ty)?;
170-
171186
use rustc::ty::layout::Layout::*;
172187
let (offset, packed) = match *base_layout {
173188
Univariant { ref variant, .. } => {
@@ -229,19 +244,24 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
229244
Lvalue::Local { frame, local, field } => match self.stack[frame].get_local(local, field.map(|(i, _)| i))? {
230245
Value::ByRef(ptr) => {
231246
assert!(field.is_none(), "local can't be ByRef and have a field offset");
232-
(ptr, LvalueExtra::None)
247+
(PrimVal::Ptr(ptr), LvalueExtra::None)
233248
},
234249
Value::ByVal(PrimVal::Undef) => {
235250
// FIXME: allocate in fewer cases
236251
if self.ty_to_primval_kind(base_ty).is_ok() {
237252
return Ok(base);
238253
} else {
239-
(self.force_allocation(base)?.to_ptr(), LvalueExtra::None)
254+
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
240255
}
241256
},
242257
Value::ByVal(_) => {
243-
assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0");
244-
return Ok(base);
258+
if self.get_field_count(base_ty)? == 1 {
259+
assert_eq!(field_index, 0, "ByVal can only have 1 non zst field with offset 0");
260+
return Ok(base);
261+
}
262+
// this branch is taken when a union creates a large ByVal which is then
263+
// accessed as a struct with multiple small fields
264+
(PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
245265
},
246266
Value::ByValPair(_, _) => {
247267
let field_count = self.get_field_count(base_ty)?;
@@ -264,7 +284,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
264284

265285
let offset = match base_extra {
266286
LvalueExtra::Vtable(tab) => {
267-
let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(PrimVal::Ptr(base_ptr), PrimVal::Ptr(tab)))?;
287+
let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(base_ptr, PrimVal::Ptr(tab)))?;
268288
offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes()
269289
}
270290
_ => offset.bytes(),
@@ -276,7 +296,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
276296

277297
if packed {
278298
let size = self.type_size(field_ty)?.expect("packed struct must be sized");
279-
self.memory.mark_packed(ptr, size);
299+
self.memory.mark_packed(ptr.to_ptr()?, size);
280300
}
281301

282302
let extra = if self.type_is_sized(field_ty) {

0 commit comments

Comments
 (0)