提交 8c6c6d7c 编写于 作者: O Oliver Schneider 提交者: GitHub

Merge pull request #212 from oli-obk/zero_sense_types

Remove the zst allocation
...@@ -59,6 +59,8 @@ pub enum EvalError<'tcx> { ...@@ -59,6 +59,8 @@ pub enum EvalError<'tcx> {
ReallocatedStaticMemory, ReallocatedStaticMemory,
DeallocatedStaticMemory, DeallocatedStaticMemory,
Layout(layout::LayoutError<'tcx>), Layout(layout::LayoutError<'tcx>),
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
Unreachable, Unreachable,
Panic, Panic,
} }
...@@ -89,7 +91,7 @@ fn description(&self) -> &str { ...@@ -89,7 +91,7 @@ fn description(&self) -> &str {
EvalError::ReadBytesAsPointer => EvalError::ReadBytesAsPointer =>
"a memory access tried to interpret some bytes as a pointer", "a memory access tried to interpret some bytes as a pointer",
EvalError::InvalidPointerMath => EvalError::InvalidPointerMath =>
"attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. compating pointers into different allocations", "attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations",
EvalError::ReadUndefBytes => EvalError::ReadUndefBytes =>
"attempted to read undefined bytes", "attempted to read undefined bytes",
EvalError::DeadLocal => EvalError::DeadLocal =>
...@@ -146,6 +148,10 @@ fn description(&self) -> &str { ...@@ -146,6 +148,10 @@ fn description(&self) -> &str {
"rustc layout computation failed", "rustc layout computation failed",
EvalError::UnterminatedCString(_) => EvalError::UnterminatedCString(_) =>
"attempted to get length of a null terminated string, but no null found before end of allocation", "attempted to get length of a null terminated string, but no null found before end of allocation",
EvalError::HeapAllocZeroBytes =>
"tried to re-, de- or allocate zero bytes on the heap",
EvalError::HeapAllocNonPowerOfTwoAlignment(_) =>
"tried to re-, de-, or allocate heap memory with alignment that is not a power of two",
EvalError::Unreachable => EvalError::Unreachable =>
"entered unreachable code", "entered unreachable code",
EvalError::Panic => EvalError::Panic =>
......
...@@ -362,7 +362,11 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { ...@@ -362,7 +362,11 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
StackPopCleanup::None => {}, StackPopCleanup::None => {},
StackPopCleanup::Tls(key) => { StackPopCleanup::Tls(key) => {
// either fetch the next dtor or start new from the beginning, if any are left with a non-null data // either fetch the next dtor or start new from the beginning, if any are left with a non-null data
if let Some((instance, ptr, key)) = self.memory.fetch_tls_dtor(key).or_else(|| self.memory.fetch_tls_dtor(None)) { let dtor = match self.memory.fetch_tls_dtor(key)? {
dtor @ Some(_) => dtor,
None => self.memory.fetch_tls_dtor(None)?,
};
if let Some((instance, ptr, key)) = dtor {
trace!("Running TLS dtor {:?} on {:?}", instance, ptr); trace!("Running TLS dtor {:?} on {:?}", instance, ptr);
// TODO: Potentially, this has to support all the other possible instances? See eval_fn_call in terminator/mod.rs // TODO: Potentially, this has to support all the other possible instances? See eval_fn_call in terminator/mod.rs
let mir = self.load_mir(instance.def)?; let mir = self.load_mir(instance.def)?;
...@@ -370,7 +374,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { ...@@ -370,7 +374,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
instance, instance,
mir.span, mir.span,
mir, mir,
Lvalue::zst(), Lvalue::undef(),
StackPopCleanup::Tls(Some(key)), StackPopCleanup::Tls(Some(key)),
)?; )?;
let arg_local = self.frame().mir.args_iter().next().ok_or(EvalError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()))?; let arg_local = self.frame().mir.args_iter().next().ok_or(EvalError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()))?;
...@@ -673,8 +677,14 @@ pub(super) fn eval_rvalue_into_lvalue( ...@@ -673,8 +677,14 @@ pub(super) fn eval_rvalue_into_lvalue(
} }
NullaryOp(mir::NullOp::Box, ty) => { NullaryOp(mir::NullOp::Box, ty) => {
let ptr = self.alloc_ptr(ty)?; // FIXME: call the `exchange_malloc` lang item if available
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; if self.type_size(ty)?.expect("box only works with sized types") == 0 {
let align = self.type_align(ty)?;
self.write_primval(dest, PrimVal::Bytes(align.into()), dest_ty)?;
} else {
let ptr = self.alloc_ptr(ty)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
}
} }
NullaryOp(mir::NullOp::SizeOf, ty) => { NullaryOp(mir::NullOp::SizeOf, ty) => {
...@@ -904,11 +914,9 @@ pub(super) fn pointer_offset(&self, ptr: PrimVal, pointee_ty: Ty<'tcx>, offset: ...@@ -904,11 +914,9 @@ pub(super) fn pointer_offset(&self, ptr: PrimVal, pointee_ty: Ty<'tcx>, offset:
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64; let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
return if let Some(offset) = offset.checked_mul(pointee_size) { return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset, self.memory.layout)?; let ptr = ptr.signed_offset(offset, self.memory.layout)?;
// Do not do bounds-checking for integers or ZST; they can never alias a normal pointer anyway. // Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
if let PrimVal::Ptr(ptr) = ptr { if let PrimVal::Ptr(ptr) = ptr {
if !(ptr.points_to_zst() && (offset == 0 || pointee_size == 0)) { self.memory.check_bounds(ptr, false)?;
self.memory.check_bounds(ptr, false)?;
}
} else if ptr.is_null()? { } else if ptr.is_null()? {
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
return Err(EvalError::NullPointerOutOfBounds); return Err(EvalError::NullPointerOutOfBounds);
...@@ -1697,7 +1705,7 @@ fn run_main<'a, 'tcx: 'a>( ...@@ -1697,7 +1705,7 @@ fn run_main<'a, 'tcx: 'a>(
main_instance, main_instance,
main_mir.span, main_mir.span,
main_mir, main_mir,
Lvalue::zst(), Lvalue::undef(),
StackPopCleanup::Tls(None), StackPopCleanup::Tls(None),
)?; )?;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
use memory::Pointer; use memory::Pointer;
use value::{PrimVal, Value}; use value::{PrimVal, Value};
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug)]
pub enum Lvalue<'tcx> { pub enum Lvalue<'tcx> {
/// An lvalue referring to a value allocated in the `Memory` system. /// An lvalue referring to a value allocated in the `Memory` system.
Ptr { Ptr {
...@@ -73,10 +73,6 @@ fn from_primval_ptr(ptr: PrimVal) -> Self { ...@@ -73,10 +73,6 @@ fn from_primval_ptr(ptr: PrimVal) -> Self {
Lvalue::Ptr { ptr, extra: LvalueExtra::None } Lvalue::Ptr { ptr, extra: LvalueExtra::None }
} }
pub fn zst() -> Self {
Self::from_ptr(Pointer::zst_ptr())
}
pub fn from_ptr(ptr: Pointer) -> Self { pub fn from_ptr(ptr: Pointer) -> Self {
Self::from_primval_ptr(PrimVal::Ptr(ptr)) Self::from_primval_ptr(PrimVal::Ptr(ptr))
} }
......
...@@ -81,14 +81,6 @@ pub fn overflowing_offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> (Sel ...@@ -81,14 +81,6 @@ pub fn overflowing_offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> (Sel
pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> { pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
Ok(Pointer::new(self.alloc_id, value::offset(self.offset, i, layout)?)) Ok(Pointer::new(self.alloc_id, value::offset(self.offset, i, layout)?))
} }
pub fn points_to_zst(&self) -> bool {
self.alloc_id == ZST_ALLOC_ID
}
pub fn zst_ptr() -> Self {
Pointer::new(ZST_ALLOC_ID, 0)
}
} }
pub type TlsKey = usize; pub type TlsKey = usize;
...@@ -157,15 +149,13 @@ pub struct Memory<'a, 'tcx> { ...@@ -157,15 +149,13 @@ pub struct Memory<'a, 'tcx> {
next_thread_local: TlsKey, next_thread_local: TlsKey,
} }
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: u64) -> Self { pub fn new(layout: &'a TargetDataLayout, max_memory: u64) -> Self {
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(),
next_id: AllocId(2), next_id: AllocId(0),
layout, layout,
memory_size: max_memory, memory_size: max_memory,
memory_usage: 0, memory_usage: 0,
...@@ -206,10 +196,8 @@ pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, Pointer> { ...@@ -206,10 +196,8 @@ pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, Pointer> {
} }
pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, Pointer> { pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, Pointer> {
if size == 0 {
return Ok(Pointer::zst_ptr());
}
assert_ne!(align, 0); assert_ne!(align, 0);
assert!(align.is_power_of_two());
if self.memory_size - self.memory_usage < size { if self.memory_size - self.memory_usage < size {
return Err(EvalError::OutOfMemory { return Err(EvalError::OutOfMemory {
...@@ -236,13 +224,11 @@ pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, Pointer> { ...@@ -236,13 +224,11 @@ pub fn allocate(&mut self, size: u64, align: u64) -> EvalResult<'tcx, Pointer> {
// TODO(solson): Track which allocations were returned from __rust_allocate and report an error // TODO(solson): Track which allocations were returned from __rust_allocate and report an error
// when reallocating/deallocating any others. // when reallocating/deallocating any others.
pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalResult<'tcx, Pointer> { pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalResult<'tcx, Pointer> {
assert!(align.is_power_of_two());
// TODO(solson): Report error about non-__rust_allocate'd pointer. // TODO(solson): Report error about non-__rust_allocate'd pointer.
if ptr.offset != 0 { if ptr.offset != 0 {
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
} }
if ptr.points_to_zst() {
return self.allocate(new_size, align);
}
if self.get(ptr.alloc_id).ok().map_or(false, |alloc| alloc.static_kind != StaticKind::NotStatic) { if self.get(ptr.alloc_id).ok().map_or(false, |alloc| alloc.static_kind != StaticKind::NotStatic) {
return Err(EvalError::ReallocatedStaticMemory); return Err(EvalError::ReallocatedStaticMemory);
} }
...@@ -253,6 +239,7 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes ...@@ -253,6 +239,7 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes
let amount = new_size - size; let amount = new_size - size;
self.memory_usage += amount; self.memory_usage += amount;
let alloc = self.get_mut(ptr.alloc_id)?; let alloc = self.get_mut(ptr.alloc_id)?;
// FIXME: check alignment here
assert_eq!(amount as usize as u64, amount); assert_eq!(amount as usize as u64, amount);
alloc.bytes.extend(iter::repeat(0).take(amount as usize)); alloc.bytes.extend(iter::repeat(0).take(amount as usize));
alloc.undef_mask.grow(amount, false); alloc.undef_mask.grow(amount, false);
...@@ -260,6 +247,7 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes ...@@ -260,6 +247,7 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes
self.memory_usage -= size - new_size; self.memory_usage -= size - new_size;
self.clear_relocations(ptr.offset(new_size, self.layout)?, size - new_size)?; self.clear_relocations(ptr.offset(new_size, self.layout)?, size - new_size)?;
let alloc = self.get_mut(ptr.alloc_id)?; let alloc = self.get_mut(ptr.alloc_id)?;
// FIXME: check alignment here
// `as usize` is fine here, since it is smaller than `size`, which came from a usize // `as usize` is fine here, since it is smaller than `size`, which came from a usize
alloc.bytes.truncate(new_size as usize); alloc.bytes.truncate(new_size as usize);
alloc.bytes.shrink_to_fit(); alloc.bytes.shrink_to_fit();
...@@ -271,9 +259,6 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes ...@@ -271,9 +259,6 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: u64, align: u64) -> EvalRes
// TODO(solson): See comment on `reallocate`. // TODO(solson): See comment on `reallocate`.
pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<'tcx> { pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<'tcx> {
if ptr.points_to_zst() {
return Ok(());
}
if ptr.offset != 0 { if ptr.offset != 0 {
// TODO(solson): Report error about non-__rust_allocate'd pointer. // TODO(solson): Report error about non-__rust_allocate'd pointer.
return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset))); return Err(EvalError::Unimplemented(format!("bad pointer offset: {}", ptr.offset)));
...@@ -419,22 +404,22 @@ pub(crate) fn store_tls(&mut self, key: TlsKey, new_data: PrimVal) -> EvalResult ...@@ -419,22 +404,22 @@ pub(crate) fn store_tls(&mut self, key: TlsKey, new_data: PrimVal) -> EvalResult
/// with associated destructors, implementations may stop calling destructors, /// with associated destructors, implementations may stop calling destructors,
/// or they may continue calling destructors until no non-NULL values with /// or they may continue calling destructors until no non-NULL values with
/// associated destructors exist, even though this might result in an infinite loop. /// associated destructors exist, even though this might result in an infinite loop.
pub(crate) fn fetch_tls_dtor(&mut self, key: Option<TlsKey>) -> Option<(ty::Instance<'tcx>, PrimVal, TlsKey)> { pub(crate) fn fetch_tls_dtor(&mut self, key: Option<TlsKey>) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, PrimVal, TlsKey)>> {
use std::collections::Bound::*; use std::collections::Bound::*;
let start = match key { let start = match key {
Some(key) => Excluded(key), Some(key) => Excluded(key),
None => Unbounded, None => Unbounded,
}; };
for (&key, &mut TlsEntry { ref mut data, dtor }) in self.thread_local.range_mut((start, Unbounded)) { for (&key, &mut TlsEntry { ref mut data, dtor }) in self.thread_local.range_mut((start, Unbounded)) {
if *data != PrimVal::Bytes(0) { if !data.is_null()? {
if let Some(dtor) = dtor { if let Some(dtor) = dtor {
let ret = Some((dtor, *data, key)); let ret = Some((dtor, *data, key));
*data = PrimVal::Bytes(0); *data = PrimVal::Bytes(0);
return ret; return Ok(ret);
} }
} }
} }
return None; return Ok(None);
} }
} }
...@@ -459,7 +444,6 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> { ...@@ -459,7 +444,6 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
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::InvalidMemoryAccess),
None => Err(EvalError::DanglingPointerDeref), None => Err(EvalError::DanglingPointerDeref),
} }
} }
...@@ -474,7 +458,6 @@ pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> { ...@@ -474,7 +458,6 @@ pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
}, },
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::InvalidMemoryAccess),
None => Err(EvalError::DanglingPointerDeref), None => Err(EvalError::DanglingPointerDeref),
} }
} }
...@@ -508,7 +491,6 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { ...@@ -508,7 +491,6 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
let mut allocs_seen = HashSet::new(); let mut allocs_seen = HashSet::new();
while let Some(id) = allocs_to_print.pop_front() { while let Some(id) = allocs_to_print.pop_front() {
if id == ZST_ALLOC_ID { continue; }
let mut msg = format!("Alloc {:<5} ", format!("{}:", id)); let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
let prefix_len = msg.len(); let prefix_len = msg.len();
let mut relocations = vec![]; let mut relocations = vec![];
...@@ -556,10 +538,7 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { ...@@ -556,10 +538,7 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
for (i, target_id) in relocations { for (i, target_id) in relocations {
// this `as usize` is fine, since we can't print more chars than `usize::MAX` // this `as usize` is fine, since we can't print more chars than `usize::MAX`
write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap(); write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap();
let target = match target_id { let target = format!("({})", target_id);
ZST_ALLOC_ID => String::from("zst"),
_ => format!("({})", target_id),
};
// this `as usize` is fine, since we can't print more chars than `usize::MAX` // this `as usize` is fine, since we can't print more chars than `usize::MAX`
write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap(); write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
pos = i + self.pointer_size(); pos = i + self.pointer_size();
...@@ -637,7 +616,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> { ...@@ -637,7 +616,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
/// mark an allocation as being the entry point to a static (see `static_alloc` field) /// mark an allocation as being the entry point to a static (see `static_alloc` field)
pub fn mark_static(&mut self, alloc_id: AllocId) { pub fn mark_static(&mut self, alloc_id: AllocId) {
trace!("mark_static: {:?}", alloc_id); trace!("mark_static: {:?}", alloc_id);
if alloc_id != ZST_ALLOC_ID && !self.static_alloc.insert(alloc_id) { if !self.static_alloc.insert(alloc_id) {
bug!("tried to mark an allocation ({:?}) as static twice", alloc_id); bug!("tried to mark an allocation ({:?}) as static twice", alloc_id);
} }
} }
...@@ -667,7 +646,6 @@ pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutable: bool) -> Ev ...@@ -667,7 +646,6 @@ pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutable: bool) -> Ev
// mark recursively // mark recursively
mem::replace(relocations, Default::default()) mem::replace(relocations, Default::default())
}, },
None if alloc_id == ZST_ALLOC_ID => return Ok(()),
None if !self.functions.contains_key(&alloc_id) => return Err(EvalError::DanglingPointerDeref), None if !self.functions.contains_key(&alloc_id) => return Err(EvalError::DanglingPointerDeref),
_ => return Ok(()), _ => return Ok(()),
}; };
......
...@@ -159,10 +159,22 @@ pub fn binary_op( ...@@ -159,10 +159,22 @@ pub fn binary_op(
}, },
// These work on anything // These work on anything
Eq if left_kind == right_kind => { Eq if left_kind == right_kind => {
return Ok((PrimVal::from_bool(left == right), false)); let result = match (left, right) {
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right,
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right,
(PrimVal::Undef, _) | (_, PrimVal::Undef) => return Err(EvalError::ReadUndefBytes),
_ => false,
};
return Ok((PrimVal::from_bool(result), false));
} }
Ne if left_kind == right_kind => { Ne if left_kind == right_kind => {
return Ok((PrimVal::from_bool(left != right), false)); let result = match (left, right) {
(PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right,
(PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right,
(PrimVal::Undef, _) | (_, PrimVal::Undef) => return Err(EvalError::ReadUndefBytes),
_ => true,
};
return Ok((PrimVal::from_bool(result), false));
} }
// These need both pointers to be in the same allocation // These need both pointers to be in the same allocation
Lt | Le | Gt | Ge | Sub Lt | Le | Gt | Ge | Sub
......
...@@ -49,7 +49,7 @@ pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty: ...@@ -49,7 +49,7 @@ pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty:
instance, instance,
span, span,
mir, mir,
Lvalue::zst(), Lvalue::undef(),
StackPopCleanup::None, StackPopCleanup::None,
)?; )?;
......
...@@ -596,6 +596,12 @@ fn call_c_abi( ...@@ -596,6 +596,12 @@ fn call_c_abi(
"__rust_allocate" => { "__rust_allocate" => {
let size = self.value_to_primval(args[0], usize)?.to_u64()?; let size = self.value_to_primval(args[0], usize)?.to_u64()?;
let align = self.value_to_primval(args[1], usize)?.to_u64()?; let align = self.value_to_primval(args[1], usize)?.to_u64()?;
if size == 0 {
return Err(EvalError::HeapAllocZeroBytes);
}
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = self.memory.allocate(size, align)?; let ptr = self.memory.allocate(size, align)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
} }
...@@ -603,6 +609,12 @@ fn call_c_abi( ...@@ -603,6 +609,12 @@ fn call_c_abi(
"__rust_allocate_zeroed" => { "__rust_allocate_zeroed" => {
let size = self.value_to_primval(args[0], usize)?.to_u64()?; let size = self.value_to_primval(args[0], usize)?.to_u64()?;
let align = self.value_to_primval(args[1], usize)?.to_u64()?; let align = self.value_to_primval(args[1], usize)?.to_u64()?;
if size == 0 {
return Err(EvalError::HeapAllocZeroBytes);
}
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
let ptr = self.memory.allocate(size, align)?; let ptr = self.memory.allocate(size, align)?;
self.memory.write_repeat(ptr, 0, size)?; self.memory.write_repeat(ptr, 0, size)?;
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
...@@ -611,8 +623,14 @@ fn call_c_abi( ...@@ -611,8 +623,14 @@ fn call_c_abi(
"__rust_deallocate" => { "__rust_deallocate" => {
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?; let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
// FIXME: insert sanity check for size and align? // FIXME: insert sanity check for size and align?
let _old_size = self.value_to_primval(args[1], usize)?.to_u64()?; let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
let _align = self.value_to_primval(args[2], usize)?.to_u64()?; let align = self.value_to_primval(args[2], usize)?.to_u64()?;
if old_size == 0 {
return Err(EvalError::HeapAllocZeroBytes);
}
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
self.memory.deallocate(ptr)?; self.memory.deallocate(ptr)?;
}, },
...@@ -620,6 +638,12 @@ fn call_c_abi( ...@@ -620,6 +638,12 @@ fn call_c_abi(
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?; let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
let size = self.value_to_primval(args[2], usize)?.to_u64()?; let size = self.value_to_primval(args[2], usize)?.to_u64()?;
let align = self.value_to_primval(args[3], usize)?.to_u64()?; let align = self.value_to_primval(args[3], usize)?.to_u64()?;
if size == 0 {
return Err(EvalError::HeapAllocZeroBytes);
}
if !align.is_power_of_two() {
return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
}
let new_ptr = self.memory.reallocate(ptr, size, align)?; let new_ptr = self.memory.reallocate(ptr, size, align)?;
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
} }
...@@ -640,7 +664,7 @@ fn call_c_abi( ...@@ -640,7 +664,7 @@ fn call_c_abi(
f_instance, f_instance,
mir.span, mir.span,
mir, mir,
Lvalue::zst(), Lvalue::undef(),
StackPopCleanup::Goto(dest_block), StackPopCleanup::Goto(dest_block),
)?; )?;
......
...@@ -42,7 +42,7 @@ pub enum Value { ...@@ -42,7 +42,7 @@ pub enum Value {
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
/// of a simple value, a pointer into another `Allocation`, or be undefined. /// of a simple value, a pointer into another `Allocation`, or be undefined.
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug)]
pub enum PrimVal { pub enum PrimVal {
/// The raw bytes of a simple value. /// The raw bytes of a simple value.
Bytes(u128), Bytes(u128),
......
fn main() { fn main() {
let x = &() as *const () as *const i32; let x = &() as *const () as *const i32;
let _ = unsafe { *x }; //~ ERROR: tried to access memory through an invalid pointer let _ = unsafe { *x }; //~ ERROR: tried to access memory with alignment 1, but alignment 4 is required
} }
// error-pattern: the evaluated program panicked
#[derive(Debug)]
struct A;
fn main() {
// can't use assert_eq, b/c that will try to print the pointer addresses with full MIR enabled
if &A as *const A as *const () != &() as *const _ {
panic!()
}
}
// error-pattern: the evaluated program panicked
#[derive(Debug)]
struct A;
fn main() {
// can't use assert_eq, b/c that will try to print the pointer addresses with full MIR enabled
if &A as *const A != &A as *const A {
panic!();
}
}
...@@ -13,8 +13,6 @@ fn use_zst() -> A { ...@@ -13,8 +13,6 @@ fn use_zst() -> A {
fn main() { fn main() {
assert_eq!(zst_ret(), A); assert_eq!(zst_ret(), A);
assert_eq!(use_zst(), A); assert_eq!(use_zst(), A);
assert_eq!(&A as *const A as *const (), &() as *const _);
assert_eq!(&A as *const A, &A as *const A);
let x = 42 as *mut (); let x = 42 as *mut ();
unsafe { *x = (); } unsafe { *x = (); }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册