Skip to content

Commit 875a454

Browse files
committed
remove the ZST allocation and abort all zero byte writes/reads
1 parent 0690a26 commit 875a454

File tree

3 files changed

+34
-18
lines changed

3 files changed

+34
-18
lines changed

src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use syntax::codemap::Span;
1010
pub enum EvalError<'tcx> {
1111
FunctionPointerTyMismatch(&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>),
1212
DanglingPointerDeref,
13+
ZstAllocAccess,
1314
InvalidFunctionPointer,
1415
InvalidBool,
1516
InvalidDiscriminant,
@@ -53,6 +54,8 @@ impl<'tcx> Error for EvalError<'tcx> {
5354
match *self {
5455
EvalError::FunctionPointerTyMismatch(..) =>
5556
"tried to call a function through a function pointer of a different type",
57+
EvalError::ZstAllocAccess =>
58+
"tried to access the ZST allocation",
5659
EvalError::DanglingPointerDeref =>
5760
"dangling pointer was dereferenced",
5861
EvalError::InvalidFunctionPointer =>

src/memory.rs

+27-18
Original file line numberDiff line numberDiff line change
@@ -105,29 +105,15 @@ const ZST_ALLOC_ID: AllocId = AllocId(0);
105105

106106
impl<'a, 'tcx> Memory<'a, 'tcx> {
107107
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
108-
let mut mem = Memory {
108+
Memory {
109109
alloc_map: HashMap::new(),
110110
functions: HashMap::new(),
111111
function_alloc_cache: HashMap::new(),
112112
next_id: AllocId(1),
113113
layout: layout,
114114
memory_size: max_memory,
115115
memory_usage: 0,
116-
};
117-
// alloc id 0 is reserved for ZSTs, this is an optimization to prevent ZST
118-
// (e.g. function items, (), [], ...) from requiring memory
119-
let alloc = Allocation {
120-
bytes: Vec::new(),
121-
relocations: BTreeMap::new(),
122-
undef_mask: UndefMask::new(0),
123-
align: 8, // should be infinity?
124-
immutable: false, // must be mutable, because sometimes we "move out" of a ZST
125-
};
126-
mem.alloc_map.insert(ZST_ALLOC_ID, alloc);
127-
// check that additional zst allocs work
128-
debug_assert!(mem.allocate(0, 1).unwrap().points_to_zst());
129-
debug_assert!(mem.get(ZST_ALLOC_ID).is_ok());
130-
mem
116+
}
131117
}
132118

133119
pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation> {
@@ -293,6 +279,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
293279
Some(alloc) => Ok(alloc),
294280
None => match self.functions.get(&id) {
295281
Some(_) => Err(EvalError::DerefFunctionPointer),
282+
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
296283
None => Err(EvalError::DanglingPointerDeref),
297284
}
298285
}
@@ -304,6 +291,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
304291
Some(alloc) => Ok(alloc),
305292
None => match self.functions.get(&id) {
306293
Some(_) => Err(EvalError::DerefFunctionPointer),
294+
None if id == ZST_ALLOC_ID => Err(EvalError::ZstAllocAccess),
307295
None => Err(EvalError::DanglingPointerDeref),
308296
}
309297
}
@@ -353,6 +341,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
353341
while let Some(id) = allocs_to_print.pop_front() {
354342
allocs_seen.insert(id);
355343
let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
344+
if id == ZST_ALLOC_ID {
345+
trace!("{} zst allocation", msg);
346+
continue;
347+
}
356348
let prefix_len = msg.len();
357349
let mut relocations = vec![];
358350

@@ -406,6 +398,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
406398
/// Byte accessors
407399
impl<'a, 'tcx> Memory<'a, 'tcx> {
408400
fn get_bytes_unchecked(&self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &[u8]> {
401+
if size == 0 {
402+
return Ok(&[]);
403+
}
409404
let alloc = self.get(ptr.alloc_id)?;
410405
if ptr.offset + size > alloc.bytes.len() {
411406
return Err(EvalError::PointerOutOfBounds {
@@ -418,6 +413,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
418413
}
419414

420415
fn get_bytes_unchecked_mut(&mut self, ptr: Pointer, size: usize) -> EvalResult<'tcx, &mut [u8]> {
416+
if size == 0 {
417+
return Ok(&mut []);
418+
}
421419
let alloc = self.get_mut(ptr.alloc_id)?;
422420
if ptr.offset + size > alloc.bytes.len() {
423421
return Err(EvalError::PointerOutOfBounds {
@@ -430,6 +428,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
430428
}
431429

432430
fn get_bytes(&self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &[u8]> {
431+
if size == 0 {
432+
return Ok(&[]);
433+
}
433434
self.check_align(ptr, align)?;
434435
if self.relocations(ptr, size)?.count() != 0 {
435436
return Err(EvalError::ReadPointerAsBytes);
@@ -439,6 +440,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
439440
}
440441

441442
fn get_bytes_mut(&mut self, ptr: Pointer, size: usize, align: usize) -> EvalResult<'tcx, &mut [u8]> {
443+
if size == 0 {
444+
return Ok(&mut []);
445+
}
442446
self.check_align(ptr, align)?;
443447
self.clear_relocations(ptr, size)?;
444448
self.mark_definedness(ptr, size, true)?;
@@ -449,15 +453,17 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
449453
/// Reading and writing
450454
impl<'a, 'tcx> Memory<'a, 'tcx> {
451455
pub fn freeze(&mut self, alloc_id: AllocId) -> EvalResult<'tcx, ()> {
452-
// Never freeze the zero-sized allocation. If you do that, then getting a mutable handle to
453-
// _any_ ZST becomes an error, since they all share the same allocation.
456+
// It's not possible to freeze the zero-sized allocation, because it doesn't exist.
454457
if alloc_id != ZST_ALLOC_ID {
455458
self.get_mut(alloc_id)?.immutable = true;
456459
}
457460
Ok(())
458461
}
459462

460463
pub fn copy(&mut self, src: Pointer, dest: Pointer, size: usize, align: usize) -> EvalResult<'tcx, ()> {
464+
if size == 0 {
465+
return Ok(());
466+
}
461467
self.check_relocation_edges(src, size)?;
462468

463469
let src_bytes = self.get_bytes_unchecked(src, size)?.as_ptr();
@@ -714,6 +720,9 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
714720
pub fn mark_definedness(&mut self, ptr: Pointer, size: usize, new_state: bool)
715721
-> EvalResult<'tcx, ()>
716722
{
723+
if size == 0 {
724+
return Ok(())
725+
}
717726
let mut alloc = self.get_mut(ptr.alloc_id)?;
718727
alloc.undef_mask.set_range(ptr.offset, ptr.offset + size, new_state);
719728
Ok(())

tests/compile-fail/zst.rs

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

0 commit comments

Comments
 (0)