Implement drop/deallocation for Box.
This commit is contained in:
parent
bef57b291b
commit
1f6583fe06
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user