Skip to content

Commit 823b952

Browse files
committed
Only check pointers when dereferencing
Before we also checked whether pointers had alloc_ids when we created rvalue references
1 parent 8ff5d59 commit 823b952

File tree

6 files changed

+104
-106
lines changed

6 files changed

+104
-106
lines changed

src/eval_context.rs

Lines changed: 32 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
351351
let global_value = self.globals.get_mut(&id)
352352
.expect("global should have been cached (static)");
353353
match global_value.value {
354-
Value::ByRef(ptr) => self.memory.mark_static_initalized(ptr.alloc_id, mutable)?,
354+
// FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
355+
Value::ByRef(ptr) => self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?,
355356
Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
356357
self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
357358
},
@@ -409,6 +410,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
409410
pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
410411
if let Some(Value::ByRef(ptr)) = local {
411412
trace!("deallocating local");
413+
let ptr = ptr.to_ptr()?;
412414
self.memory.dump_alloc(ptr.alloc_id);
413415
match self.memory.deallocate(ptr) {
414416
// We could alternatively check whether the alloc_id is static before calling
@@ -693,26 +695,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
693695

694696
// Check alignment and non-NULLness.
695697
let (_, align) = self.size_and_align_of_dst(ty, val)?;
696-
match ptr {
697-
PrimVal::Ptr(ptr) => {
698-
self.memory.check_align(ptr, align, 0)?;
699-
}
700-
PrimVal::Bytes(bytes) => {
701-
let v = ((bytes as u128) % (1 << self.memory.pointer_size())) as u64;
702-
if v == 0 {
703-
return Err(EvalError::InvalidNullPointerUsage);
704-
}
705-
if v % align != 0 {
706-
return Err(EvalError::AlignmentCheckFailed {
707-
has: v % align,
708-
required: align,
709-
});
710-
}
711-
}
712-
PrimVal::Undef => {
713-
return Err(EvalError::ReadUndefBytes);
714-
}
715-
}
698+
self.memory.check_align(ptr, align, 0)?;
716699

717700
self.write_value(val, dest, dest_ty)?;
718701
}
@@ -1036,14 +1019,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10361019
match self.stack[frame].locals[local.index() - 1] {
10371020
None => return Err(EvalError::DeadLocal),
10381021
Some(Value::ByRef(ptr)) => {
1039-
Lvalue::from_ptr(ptr)
1022+
Lvalue::from_primval_ptr(ptr)
10401023
},
10411024
Some(val) => {
10421025
let ty = self.stack[frame].mir.local_decls[local].ty;
10431026
let ty = self.monomorphize(ty, self.stack[frame].instance.substs);
10441027
let substs = self.stack[frame].instance.substs;
10451028
let ptr = self.alloc_ptr_with_substs(ty, substs)?;
1046-
self.stack[frame].locals[local.index() - 1] = Some(Value::ByRef(ptr)); // it stays live
1029+
self.stack[frame].locals[local.index() - 1] = Some(Value::ByRef(PrimVal::Ptr(ptr))); // it stays live
10471030
self.write_value_to_ptr(val, PrimVal::Ptr(ptr), ty)?;
10481031
Lvalue::from_ptr(ptr)
10491032
}
@@ -1053,7 +1036,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10531036
Lvalue::Global(cid) => {
10541037
let global_val = *self.globals.get(&cid).expect("global not cached");
10551038
match global_val.value {
1056-
Value::ByRef(ptr) => Lvalue::from_ptr(ptr),
1039+
Value::ByRef(ptr) => Lvalue::from_primval_ptr(ptr),
10571040
_ => {
10581041
let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?;
10591042
self.memory.mark_static(ptr.alloc_id);
@@ -1064,7 +1047,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10641047
}
10651048
let lval = self.globals.get_mut(&cid).expect("already checked");
10661049
*lval = Global {
1067-
value: Value::ByRef(ptr),
1050+
value: Value::ByRef(PrimVal::Ptr(ptr)),
10681051
.. global_val
10691052
};
10701053
Lvalue::from_ptr(ptr)
@@ -1160,7 +1143,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11601143
//
11611144
// Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
11621145
// knew for certain that there were no outstanding pointers to this allocation.
1163-
self.write_value_to_ptr(src_val, PrimVal::Ptr(dest_ptr), dest_ty)?;
1146+
self.write_value_to_ptr(src_val, dest_ptr, dest_ty)?;
11641147

11651148
} else if let Value::ByRef(src_ptr) = src_val {
11661149
// If the value is not `ByRef`, then we know there are no pointers to it
@@ -1178,8 +1161,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11781161
write_dest(self, src_val)?;
11791162
} else {
11801163
let dest_ptr = self.alloc_ptr(dest_ty)?;
1181-
self.copy(PrimVal::Ptr(src_ptr), PrimVal::Ptr(dest_ptr), dest_ty)?;
1182-
write_dest(self, Value::ByRef(dest_ptr))?;
1164+
self.copy(src_ptr, PrimVal::Ptr(dest_ptr), dest_ty)?;
1165+
write_dest(self, Value::ByRef(PrimVal::Ptr(dest_ptr)))?;
11831166
}
11841167

11851168
} else {
@@ -1197,7 +1180,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
11971180
dest_ty: Ty<'tcx>,
11981181
) -> EvalResult<'tcx> {
11991182
match value {
1200-
Value::ByRef(ptr) => self.copy(PrimVal::Ptr(ptr), dest, dest_ty),
1183+
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
12011184
Value::ByVal(primval) => {
12021185
let size = self.type_size(dest_ty)?.expect("dest type must be sized");
12031186
self.memory.write_primval(dest, primval, size)
@@ -1327,7 +1310,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13271310
}
13281311
}
13291312

1330-
pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1313+
pub(super) fn read_value(&mut self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
13311314
if let Some(val) = self.try_read_value(ptr, ty)? {
13321315
Ok(val)
13331316
} else {
@@ -1352,13 +1335,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13521335
}
13531336
}
13541337

1355-
fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
1338+
fn try_read_value(&mut self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
13561339
use syntax::ast::FloatTy;
13571340

13581341
let val = match ty.sty {
1359-
ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr)?),
1342+
ty::TyBool => PrimVal::from_bool(self.memory.read_bool(ptr.to_ptr()?)?),
13601343
ty::TyChar => {
1361-
let c = self.memory.read_uint(ptr, 4)? as u32;
1344+
let c = self.memory.read_uint(ptr.to_ptr()?, 4)? as u32;
13621345
match ::std::char::from_u32(c) {
13631346
Some(ch) => PrimVal::from_char(ch),
13641347
None => return Err(EvalError::InvalidChar(c as u128)),
@@ -1377,8 +1360,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13771360
};
13781361
// if we transmute a ptr to an isize, reading it back into a primval shouldn't panic
13791362
// Due to read_ptr ignoring the sign, we need to jump around some hoops
1380-
match self.memory.read_int(ptr, size) {
1381-
Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() => self.memory.read_ptr(ptr)?,
1363+
match self.memory.read_int(ptr.to_ptr()?, size) {
1364+
Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() => self.memory.read_ptr(ptr.to_ptr()?)?,
13821365
other => PrimVal::from_i128(other?),
13831366
}
13841367
}
@@ -1395,30 +1378,30 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
13951378
};
13961379
if size == self.memory.pointer_size() {
13971380
// if we transmute a ptr to an usize, reading it back into a primval shouldn't panic
1398-
self.memory.read_ptr(ptr)?
1381+
self.memory.read_ptr(ptr.to_ptr()?)?
13991382
} else {
1400-
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1383+
PrimVal::from_u128(self.memory.read_uint(ptr.to_ptr()?, size)?)
14011384
}
14021385
}
14031386

1404-
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
1405-
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
1387+
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr.to_ptr()?)?),
1388+
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr.to_ptr()?)?),
14061389

1407-
ty::TyFnPtr(_) => self.memory.read_ptr(ptr)?,
1390+
ty::TyFnPtr(_) => self.memory.read_ptr(ptr.to_ptr()?)?,
14081391
ty::TyRef(_, ref tam) |
1409-
ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some),
1392+
ty::TyRawPtr(ref tam) => return self.read_ptr(ptr.to_ptr()?, tam.ty).map(Some),
14101393

14111394
ty::TyAdt(def, _) => {
14121395
if def.is_box() {
1413-
return self.read_ptr(ptr, ty.boxed_ty()).map(Some);
1396+
return self.read_ptr(ptr.to_ptr()?, ty.boxed_ty()).map(Some);
14141397
}
14151398
use rustc::ty::layout::Layout::*;
14161399
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
14171400
let size = discr.size().bytes();
14181401
if signed {
1419-
PrimVal::from_i128(self.memory.read_int(ptr, size)?)
1402+
PrimVal::from_i128(self.memory.read_int(ptr.to_ptr()?, size)?)
14201403
} else {
1421-
PrimVal::from_u128(self.memory.read_uint(ptr, size)?)
1404+
PrimVal::from_u128(self.memory.read_uint(ptr.to_ptr()?, size)?)
14221405
}
14231406
} else {
14241407
return Ok(None);
@@ -1537,7 +1520,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15371520
let src_f_ptr = src_ptr.offset(src_field_offset, self.memory.layout)?;
15381521
let dst_f_ptr = dest.offset(dst_field_offset, self.memory.layout)?;
15391522
if src_fty == dst_fty {
1540-
self.copy(PrimVal::Ptr(src_f_ptr), PrimVal::Ptr(dst_f_ptr), src_fty)?;
1523+
self.copy(src_f_ptr, PrimVal::Ptr(dst_f_ptr), src_fty)?;
15411524
} else {
15421525
self.unsize_into(Value::ByRef(src_f_ptr), src_fty, Lvalue::from_ptr(dst_f_ptr), dst_fty)?;
15431526
}
@@ -1566,10 +1549,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15661549
Err(err) => {
15671550
panic!("Failed to access local: {:?}", err);
15681551
}
1569-
Ok(Value::ByRef(ptr)) => {
1552+
Ok(Value::ByRef(PrimVal::Ptr(ptr))) => {
15701553
write!(msg, " by ref:").unwrap();
15711554
allocs.push(ptr.alloc_id);
15721555
}
1556+
Ok(Value::ByRef(ptr)) => {
1557+
write!(msg, " integral by ref: {:?}", ptr).unwrap();
1558+
}
15731559
Ok(Value::ByVal(val)) => {
15741560
write!(msg, " {:?}", val).unwrap();
15751561
if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }

src/lvalue.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ impl<'tcx> Lvalue<'tcx> {
6767
Self::from_primval_ptr(PrimVal::Undef)
6868
}
6969

70-
fn from_primval_ptr(ptr: PrimVal) -> Self {
70+
pub(crate) fn from_primval_ptr(ptr: PrimVal) -> Self {
7171
Lvalue::Ptr { ptr, extra: LvalueExtra::None }
7272
}
7373

74-
pub fn from_ptr(ptr: Pointer) -> Self {
74+
pub(crate) fn from_ptr(ptr: Pointer) -> Self {
7575
Self::from_primval_ptr(PrimVal::Ptr(ptr))
7676
}
7777

@@ -192,7 +192,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
192192
match lvalue {
193193
Lvalue::Ptr { ptr, extra } => {
194194
assert_eq!(extra, LvalueExtra::None);
195-
Ok(Value::ByRef(ptr.to_ptr()?))
195+
Ok(Value::ByRef(ptr))
196196
}
197197
Lvalue::Local { frame, local } => {
198198
self.stack[frame].get_local(local)

src/memory.rs

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
189189
}
190190

191191
let ptr = self.allocate(bytes.len() as u64, 1)?;
192-
self.write_bytes(ptr, bytes)?;
192+
self.write_bytes(PrimVal::Ptr(ptr), bytes)?;
193193
self.mark_static_initalized(ptr.alloc_id, false)?;
194194
self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id);
195195
Ok(ptr)
@@ -288,39 +288,52 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
288288
self.layout.endian
289289
}
290290

291-
pub fn check_align(&self, ptr: Pointer, align: u64, len: u64) -> EvalResult<'tcx> {
292-
let alloc = self.get(ptr.alloc_id)?;
293-
// check whether the memory was marked as packed
294-
// we select all elements that have the correct alloc_id and are within
295-
// the range given by the offset into the allocation and the length
296-
let start = Entry {
297-
alloc_id: ptr.alloc_id,
298-
packed_start: 0,
299-
packed_end: ptr.offset + len,
300-
};
301-
let end = Entry {
302-
alloc_id: ptr.alloc_id,
303-
packed_start: ptr.offset + len,
304-
packed_end: 0,
291+
pub fn check_align(&self, ptr: PrimVal, align: u64, len: u64) -> EvalResult<'tcx> {
292+
let offset = match ptr {
293+
PrimVal::Ptr(ptr) => {
294+
let alloc = self.get(ptr.alloc_id)?;
295+
// check whether the memory was marked as packed
296+
// we select all elements that have the correct alloc_id and are within
297+
// the range given by the offset into the allocation and the length
298+
let start = Entry {
299+
alloc_id: ptr.alloc_id,
300+
packed_start: 0,
301+
packed_end: ptr.offset + len,
302+
};
303+
let end = Entry {
304+
alloc_id: ptr.alloc_id,
305+
packed_start: ptr.offset + len,
306+
packed_end: 0,
307+
};
308+
for &Entry { packed_start, packed_end, .. } in self.packed.range(start..end) {
309+
// if the region we are checking is covered by a region in `packed`
310+
// ignore the actual alignment
311+
if packed_start <= ptr.offset && (ptr.offset + len) <= packed_end {
312+
return Ok(());
313+
}
314+
}
315+
if alloc.align < align {
316+
return Err(EvalError::AlignmentCheckFailed {
317+
has: alloc.align,
318+
required: align,
319+
});
320+
}
321+
ptr.offset
322+
},
323+
PrimVal::Bytes(bytes) => {
324+
let v = ((bytes as u128) % (1 << self.pointer_size())) as u64;
325+
if v == 0 {
326+
return Err(EvalError::InvalidNullPointerUsage);
327+
}
328+
v
329+
},
330+
PrimVal::Undef => return Err(EvalError::ReadUndefBytes),
305331
};
306-
for &Entry { packed_start, packed_end, .. } in self.packed.range(start..end) {
307-
// if the region we are checking is covered by a region in `packed`
308-
// ignore the actual alignment
309-
if packed_start <= ptr.offset && (ptr.offset + len) <= packed_end {
310-
return Ok(());
311-
}
312-
}
313-
if alloc.align < align {
314-
return Err(EvalError::AlignmentCheckFailed {
315-
has: alloc.align,
316-
required: align,
317-
});
318-
}
319-
if ptr.offset % align == 0 {
332+
if offset % align == 0 {
320333
Ok(())
321334
} else {
322335
Err(EvalError::AlignmentCheckFailed {
323-
has: ptr.offset % align,
336+
has: offset % align,
324337
required: align,
325338
})
326339
}
@@ -572,7 +585,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
572585
if size == 0 {
573586
return Ok(&[]);
574587
}
575-
self.check_align(ptr, align, size)?;
588+
self.check_align(PrimVal::Ptr(ptr), align, size)?;
576589
self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
577590
let alloc = self.get(ptr.alloc_id)?;
578591
assert_eq!(ptr.offset as usize as u64, ptr.offset);
@@ -585,7 +598,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
585598
if size == 0 {
586599
return Ok(&mut []);
587600
}
588-
self.check_align(ptr, align, size)?;
601+
self.check_align(PrimVal::Ptr(ptr), align, size)?;
589602
self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
590603
let alloc = self.get_mut(ptr.alloc_id)?;
591604
assert_eq!(ptr.offset as usize as u64, ptr.offset);
@@ -710,20 +723,20 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
710723
self.get_bytes(ptr.to_ptr()?, size, 1)
711724
}
712725

713-
pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> {
726+
pub fn write_bytes(&mut self, ptr: PrimVal, src: &[u8]) -> EvalResult<'tcx> {
714727
if src.is_empty() {
715728
return Ok(());
716729
}
717-
let bytes = self.get_bytes_mut(ptr, src.len() as u64, 1)?;
730+
let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, 1)?;
718731
bytes.clone_from_slice(src);
719732
Ok(())
720733
}
721734

722-
pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> {
735+
pub fn write_repeat(&mut self, ptr: PrimVal, val: u8, count: u64) -> EvalResult<'tcx> {
723736
if count == 0 {
724737
return Ok(());
725738
}
726-
let bytes = self.get_bytes_mut(ptr, count, 1)?;
739+
let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, 1)?;
727740
for b in bytes { *b = val; }
728741
Ok(())
729742
}

0 commit comments

Comments
 (0)