From: Scott Olson Date: Thu, 7 Apr 2016 09:02:02 +0000 (-0600) Subject: Implement drop/deallocation for Box. X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=1f6583fe06ecb307004a6a7744c43a26bac85e8c;p=rust.git Implement drop/deallocation for Box. --- diff --git a/src/interpreter.rs b/src/interpreter.rs index 5ea2a117b8c..324a2008e38 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -360,8 +360,10 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) } } - 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 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) 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 @@ fn monomorphize(&self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> { 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) } diff --git a/src/memory.rs b/src/memory.rs index b41cd7760b0..661f4567264 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -140,6 +140,22 @@ pub fn reallocate(&mut self, ptr: Pointer, new_size: usize) -> EvalResult<()> { 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 //////////////////////////////////////////////////////////////////////////////// diff --git a/test/errors.rs b/test/errors.rs index f6f5eae9d0f..a488d7acb43 100644 --- a/test/errors.rs +++ b/test/errors.rs @@ -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::(2) }; if b { 1 } else { 2 } } #[miri_run] -fn undefined_byte_reads_are_rejected() -> u8 { +fn undefined_byte_read() -> u8 { let v: Vec = 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 = 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 } +}