remove the ZST allocation and abort all zero byte writes/reads

This commit is contained in:
Oliver Schneider 2016-09-22 15:22:00 +02:00
parent 0690a26ddf
commit 875a4542f9
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
3 changed files with 34 additions and 18 deletions

View File

@ -10,6 +10,7 @@ use syntax::codemap::Span;
pub enum EvalError<'tcx> {
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
DanglingPointerDeref,
ZstAllocAccess,
InvalidFunctionPointer,
InvalidBool,
InvalidDiscriminant,
@ -53,6 +54,8 @@ impl<'tcx> Error for EvalError<'tcx> {
match *self {
EvalError::FunctionPointerTyMismatch(..) =>
"tried to call a function through a function pointer of a different type",
EvalError::ZstAllocAccess =>
"tried to access the ZST allocation",
EvalError::DanglingPointerDeref =>
"dangling pointer was dereferenced",
EvalError::InvalidFunctionPointer =>

View File

@ -105,7 +105,7 @@ const ZST_ALLOC_ID: AllocId = AllocId(0);
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
let mut mem = Memory {
Memory {
alloc_map: HashMap::new(),
functions: HashMap::new(),
function_alloc_cache: HashMap::new(),
@ -113,21 +113,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
layout: layout,
memory_size: max_memory,
memory_usage: 0,
};
// alloc id 0 is reserved for ZSTs, this is an optimization to prevent ZST
// (e.g. function items, (), [], ...) from requiring memory
let alloc = Allocation {
bytes: Vec::new(),
relocations: BTreeMap::new(),
undef_mask: UndefMask::new(0),
align: 8, // should be infinity?
immutable: false, // must be mutable, because sometimes we "move out" of a ZST
};
mem.alloc_map.insert(ZST_ALLOC_ID, alloc);
// check that additional zst allocs work
debug_assert!(mem.allocate(0, 1).unwrap().points_to_zst());
debug_assert!(mem.get(ZST_ALLOC_ID).is_ok());
mem
}
}
pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation> {
@ -293,6 +279,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
Some(alloc) => Ok(alloc),
None => match self.functions.get(&id) {
Some(_) => Err(EvalError::DerefFunctionPointer),
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
None => Err(EvalError::DanglingPointerDeref),
}
}
@ -304,6 +291,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
Some(alloc) => Ok(alloc),
None => match self.functions.get(&id) {
Some(_) => Err(EvalError::DerefFunctionPointer),
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
None => Err(EvalError::DanglingPointerDeref),
}
}
@ -353,6 +341,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
while let Some(id) = allocs_to_print.pop_front() {
allocs_seen.insert(id);
let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
if id == ZST_ALLOC_ID {
trace!("{} zst allocation", msg);
continue;
}
let prefix_len = msg.len();
let mut relocations = vec![];
@ -406,6 +398,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
/// Byte accessors
impl<'a, 'tcx> Memory<'a, 'tcx> {
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
if size == 0 {
return Ok(&[]);
}
let alloc = self.get(ptr.alloc_id)?;
if ptr.offset + size > alloc.bytes.len() {
return Err(EvalError::PointerOutOfBounds {
@ -418,6 +413,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
if size == 0 {
return Ok(&mut []);
}
let alloc = self.get_mut(ptr.alloc_id)?;
if ptr.offset + size > alloc.bytes.len() {
return Err(EvalError::PointerOutOfBounds {
@ -430,6 +428,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> {
if size == 0 {
return Ok(&[]);
}
self.check_align(ptr, align)?;
if self.relocations(ptr, size)?.count() != 0 {
return Err(EvalError::ReadPointerAsBytes);
@ -439,6 +440,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &mut [u8]> {
if size == 0 {
return Ok(&mut []);
}
self.check_align(ptr, align)?;
self.clear_relocations(ptr, size)?;
self.mark_definedness(ptr, size, true)?;
@ -449,8 +453,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
/// Reading and writing
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn freeze(&mut self, alloc_id: AllocId) -> EvalResult<'tcx, ()> {
// Never freeze the zero-sized allocation. If you do that, then getting a mutable handle to
// _any_ ZST becomes an error, since they all share the same allocation.
// It's not possible to freeze the zero-sized allocation, because it doesn't exist.
if alloc_id != ZST_ALLOC_ID {
self.get_mut(alloc_id)?.immutable = true;
}
@ -458,6 +461,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
}
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize, align: usize) -> EvalResult<'tcx, ()> {
if size == 0 {
return Ok(());
}
self.check_relocation_edges(src, size)?;
let src_bytes = self.get_bytes_unchecked(src, size)?.as_ptr();
@ -714,6 +720,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn mark_definedness(&mut self, ptr: Pointer, size: usize, new_state: bool)
-> EvalResult<'tcx, ()>
{
if size == 0 {
return Ok(())
}
let mut alloc = self.get_mut(ptr.alloc_id)?;
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
Ok(())

View File

@ -0,0 +1,4 @@
fn main() {
let x = &() as *const () as *const i32;
let _ = unsafe { *x }; //~ ERROR: tried to access the ZST allocation
}