mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +00:00
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> {
|
pub enum EvalError<'tcx> {
|
||||||
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
|
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
|
||||||
DanglingPointerDeref,
|
DanglingPointerDeref,
|
||||||
|
ZstAllocAccess,
|
||||||
InvalidFunctionPointer,
|
InvalidFunctionPointer,
|
||||||
InvalidBool,
|
InvalidBool,
|
||||||
InvalidDiscriminant,
|
InvalidDiscriminant,
|
||||||
@ -53,6 +54,8 @@ impl<'tcx> Error for EvalError<'tcx> {
|
|||||||
match *self {
|
match *self {
|
||||||
EvalError::FunctionPointerTyMismatch(..) =>
|
EvalError::FunctionPointerTyMismatch(..) =>
|
||||||
"tried to call a function through a function pointer of a different type",
|
"tried to call a function through a function pointer of a different type",
|
||||||
|
EvalError::ZstAllocAccess =>
|
||||||
|
"tried to access the ZST allocation",
|
||||||
EvalError::DanglingPointerDeref =>
|
EvalError::DanglingPointerDeref =>
|
||||||
"dangling pointer was dereferenced",
|
"dangling pointer was dereferenced",
|
||||||
EvalError::InvalidFunctionPointer =>
|
EvalError::InvalidFunctionPointer =>
|
||||||
|
@ -105,7 +105,7 @@ const ZST_ALLOC_ID: AllocId = AllocId(0);
|
|||||||
|
|
||||||
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||||
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
|
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
|
||||||
let mut mem = Memory {
|
Memory {
|
||||||
alloc_map: HashMap::new(),
|
alloc_map: HashMap::new(),
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
function_alloc_cache: HashMap::new(),
|
function_alloc_cache: HashMap::new(),
|
||||||
@ -113,21 +113,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
layout: layout,
|
layout: layout,
|
||||||
memory_size: max_memory,
|
memory_size: max_memory,
|
||||||
memory_usage: 0,
|
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> {
|
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),
|
Some(alloc) => Ok(alloc),
|
||||||
None => match self.functions.get(&id) {
|
None => match self.functions.get(&id) {
|
||||||
Some(_) => Err(EvalError::DerefFunctionPointer),
|
Some(_) => Err(EvalError::DerefFunctionPointer),
|
||||||
|
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
|
||||||
None => Err(EvalError::DanglingPointerDeref),
|
None => Err(EvalError::DanglingPointerDeref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,6 +291,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
Some(alloc) => Ok(alloc),
|
Some(alloc) => Ok(alloc),
|
||||||
None => match self.functions.get(&id) {
|
None => match self.functions.get(&id) {
|
||||||
Some(_) => Err(EvalError::DerefFunctionPointer),
|
Some(_) => Err(EvalError::DerefFunctionPointer),
|
||||||
|
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
|
||||||
None => Err(EvalError::DanglingPointerDeref),
|
None => Err(EvalError::DanglingPointerDeref),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,6 +341,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
while let Some(id) = allocs_to_print.pop_front() {
|
while let Some(id) = allocs_to_print.pop_front() {
|
||||||
allocs_seen.insert(id);
|
allocs_seen.insert(id);
|
||||||
let mut msg = format!("Alloc {:<5} ", format!("{}:", 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 prefix_len = msg.len();
|
||||||
let mut relocations = vec![];
|
let mut relocations = vec![];
|
||||||
|
|
||||||
@ -406,6 +398,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
/// Byte accessors
|
/// Byte accessors
|
||||||
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||||
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(&[]);
|
||||||
|
}
|
||||||
let alloc = self.get(ptr.alloc_id)?;
|
let alloc = self.get(ptr.alloc_id)?;
|
||||||
if ptr.offset + size > alloc.bytes.len() {
|
if ptr.offset + size > alloc.bytes.len() {
|
||||||
return Err(EvalError::PointerOutOfBounds {
|
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]> {
|
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)?;
|
let alloc = self.get_mut(ptr.alloc_id)?;
|
||||||
if ptr.offset + size > alloc.bytes.len() {
|
if ptr.offset + size > alloc.bytes.len() {
|
||||||
return Err(EvalError::PointerOutOfBounds {
|
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]> {
|
fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> {
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(&[]);
|
||||||
|
}
|
||||||
self.check_align(ptr, align)?;
|
self.check_align(ptr, align)?;
|
||||||
if self.relocations(ptr, size)?.count() != 0 {
|
if self.relocations(ptr, size)?.count() != 0 {
|
||||||
return Err(EvalError::ReadPointerAsBytes);
|
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]> {
|
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.check_align(ptr, align)?;
|
||||||
self.clear_relocations(ptr, size)?;
|
self.clear_relocations(ptr, size)?;
|
||||||
self.mark_definedness(ptr, size, true)?;
|
self.mark_definedness(ptr, size, true)?;
|
||||||
@ -449,8 +453,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
|
|||||||
/// Reading and writing
|
/// Reading and writing
|
||||||
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
impl<'a, 'tcx> Memory<'a, 'tcx> {
|
||||||
pub fn freeze(&mut self, alloc_id: AllocId) -> EvalResult<'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
|
// It's not possible to freeze the zero-sized allocation, because it doesn't exist.
|
||||||
// _any_ ZST becomes an error, since they all share the same allocation.
|
|
||||||
if alloc_id != ZST_ALLOC_ID {
|
if alloc_id != ZST_ALLOC_ID {
|
||||||
self.get_mut(alloc_id)?.immutable = true;
|
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, ()> {
|
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)?;
|
self.check_relocation_edges(src, size)?;
|
||||||
|
|
||||||
let src_bytes = self.get_bytes_unchecked(src, size)?.as_ptr();
|
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)
|
pub fn mark_definedness(&mut self, ptr: Pointer, size: usize, new_state: bool)
|
||||||
-> EvalResult<'tcx, ()>
|
-> EvalResult<'tcx, ()>
|
||||||
{
|
{
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
let mut alloc = self.get_mut(ptr.alloc_id)?;
|
let mut alloc = self.get_mut(ptr.alloc_id)?;
|
||||||
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
|
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
|
||||||
Ok(())
|
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…
Reference in New Issue
Block a user