Implement drop/deallocation for Box.

This commit is contained in:
Scott Olson 2016-04-07 03:02:02 -06:00
parent bef57b291b
commit 1f6583fe06
3 changed files with 58 additions and 5 deletions

View File

@ -360,8 +360,10 @@ impl<'a, 'tcx: 'a, 'arena> Interpreter<'a, 'tcx, 'arena> {
}
}
Drop { target, .. } => {
// TODO: Handle destructors and dynamic drop.
Drop { ref value, target, .. } => {
let ptr = try!(self.eval_lvalue(value)).to_ptr();
let ty = self.lvalue_ty(value);
try!(self.drop(ptr, ty));
TerminatorTarget::Block(target)
}
@ -371,6 +373,28 @@ impl<'a, 'tcx: 'a, 'arena> Interpreter<'a, 'tcx, 'arena> {
Ok(target)
}
fn drop(&mut self, ptr: Pointer, ty: ty::Ty<'tcx>) -> EvalResult<()> {
if !self.type_needs_drop(ty) {
self.log(1, || print!("no need to drop {:?}", ty));
return Ok(());
}
self.log(1, || print!("need to drop {:?}", ty));
match ty.sty {
ty::TyBox(contents_ty) => {
let contents_ptr = try!(self.memory.read_ptr(ptr));
try!(self.drop(contents_ptr, contents_ty));
self.log(1, || print!("deallocating box"));
try!(self.memory.deallocate(contents_ptr));
}
// TODO(tsion): Implement drop for other relevant types (e.g. aggregates).
_ => {}
}
Ok(())
}
fn call_intrinsic(
&mut self,
name: &str,
@ -847,6 +871,10 @@ impl<'a, 'tcx: 'a, 'arena> Interpreter<'a, 'tcx, 'arena> {
infer::normalize_associated_type(self.tcx, &substituted)
}
fn type_needs_drop(&self, ty: ty::Ty<'tcx>) -> bool {
self.tcx.type_needs_drop_given_env(ty, &self.tcx.empty_parameter_environment())
}
fn type_is_sized(&self, ty: ty::Ty<'tcx>) -> bool {
ty.is_sized(&self.tcx.empty_parameter_environment(), DUMMY_SP)
}

View File

@ -140,6 +140,22 @@ impl Memory {
Ok(())
}
// TODO(tsion): See comment on `reallocate`.
pub fn deallocate(&mut self, ptr: Pointer) -> EvalResult<()> {
if ptr.offset != 0 {
// TODO(tsion): Report error about non-__rust_allocate'd pointer.
panic!()
}
if self.alloc_map.remove(&ptr.alloc_id.0).is_none() {
// TODO(tsion): Report error about erroneous free. This is blocked on properly tracking
// already-dropped state since this if-statement is entered even in safe code without
// it.
}
Ok(())
}
////////////////////////////////////////////////////////////////////////////////
// Allocation accessors
////////////////////////////////////////////////////////////////////////////////

View File

@ -19,20 +19,29 @@ fn pointers_to_different_allocations_are_unorderable() -> bool {
}
#[miri_run]
fn invalid_bools_are_rejected() -> u8 {
fn invalid_bool() -> u8 {
let b = unsafe { std::mem::transmute::<u8, bool>(2) };
if b { 1 } else { 2 }
}
#[miri_run]
fn undefined_byte_reads_are_rejected() -> u8 {
fn undefined_byte_read() -> u8 {
let v: Vec<u8> = Vec::with_capacity(10);
let undef = unsafe { *v.get_unchecked(5) };
undef + 1
}
#[miri_run]
fn out_of_bounds_reads_are_rejected() -> u8 {
fn out_of_bounds_read() -> u8 {
let v: Vec<u8> = vec![1, 2];
unsafe { *v.get_unchecked(5) }
}
#[miri_run]
fn dangling_pointer_deref() -> i32 {
let p = {
let b = Box::new(42);
&*b as *const i32
};
unsafe { *p }
}