remove the ZST allocation and abort all zero byte writes/reads
This commit is contained in:
parent
0690a26ddf
commit
875a4542f9
@ -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 =>
|
||||
|
@ -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(())
|
||||
|
4
tests/compile-fail/zst.rs
Normal file
4
tests/compile-fail/zst.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
let x = &() as *const () as *const i32;
|
||||
let _ = unsafe { *x }; //~ ERROR: tried to access the ZST allocation
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user