From: Scott Olson Date: Sat, 30 Apr 2016 07:04:17 +0000 (-0600) Subject: Fully handle RawNullablePointer layout. X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=9e289fa0aa93d3a3ea80c7edd0b6e035fa360387;p=rust.git Fully handle RawNullablePointer layout. --- diff --git a/src/interpreter.rs b/src/interpreter.rs index 66a75dd4d56..4ab2413e0ff 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -256,18 +256,34 @@ fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) Switch { ref discr, ref targets, adt_def } => { let adt_ptr = try!(self.eval_lvalue(discr)).to_ptr(); let adt_layout = self.type_layout(self.lvalue_ty(discr)); - let discr_size = match *adt_layout { - Layout::General { discr, .. } => discr.size().bytes(), - _ => panic!("attmpted to switch on non-aggregate type"), - }; - let discr_val = try!(self.memory.read_uint(adt_ptr, discr_size as usize)); - let matching = adt_def.variants.iter() - .position(|v| discr_val == v.disr_val.to_u64_unchecked()); + match *adt_layout { + Layout::General { discr, .. } => { + let discr_size = discr.size().bytes(); + let discr_val = try!(self.memory.read_uint(adt_ptr, discr_size as usize)); + + let matching = adt_def.variants.iter() + .position(|v| discr_val == v.disr_val.to_u64_unchecked()); - match matching { - Some(i) => TerminatorTarget::Block(targets[i]), - None => return Err(EvalError::InvalidDiscriminant), + match matching { + Some(i) => TerminatorTarget::Block(targets[i]), + None => return Err(EvalError::InvalidDiscriminant), + } + } + + Layout::RawNullablePointer { nndiscr, .. } => { + let is_null = match self.memory.read_usize(adt_ptr) { + Ok(0) => true, + Ok(_) | Err(EvalError::ReadPointerAsBytes) => false, + Err(e) => return Err(e), + }; + + assert!(nndiscr == 0 || nndiscr == 1); + let target = if is_null { 1 - nndiscr } else { nndiscr }; + TerminatorTarget::Block(targets[target as usize]) + } + + _ => panic!("attmpted to switch on non-aggregate type"), } } @@ -633,7 +649,7 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<' Layout::Array { .. } => { let elem_size = match dest_ty.sty { ty::TyArray(elem_ty, _) => self.type_size(elem_ty) as u64, - _ => panic!("tried to assign {:?} aggregate to non-array type {:?}", + _ => panic!("tried to assign {:?} to non-array type {:?}", kind, dest_ty), }; let offsets = (0..).map(|i| i * elem_size); @@ -650,7 +666,24 @@ fn eval_assignment(&mut self, lvalue: &mir::Lvalue<'tcx>, rvalue: &mir::Rvalue<' .map(|s| s.bytes()); try!(self.assign_fields(dest, offsets, operands)); } else { - panic!("tried to assign {:?} aggregate to Layout::General dest", kind); + panic!("tried to assign {:?} to Layout::General", kind); + } + } + + Layout::RawNullablePointer { nndiscr, .. } => { + if let mir::AggregateKind::Adt(_, variant, _) = *kind { + if nndiscr == variant as u64 { + assert_eq!(operands.len(), 1); + let operand = &operands[0]; + let src = try!(self.eval_operand(operand)); + let src_ty = self.operand_ty(operand); + try!(self.move_(src, dest, src_ty)); + } else { + assert_eq!(operands.len(), 0); + try!(self.memory.write_isize(dest, 0)); + } + } else { + panic!("tried to assign {:?} to Layout::RawNullablePointer", kind); } } @@ -788,6 +821,10 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult { panic!("field access on enum had no variant index"); } } + Layout::RawNullablePointer { .. } => { + assert_eq!(field.index(), 0); + return Ok(base); + } _ => panic!("field access on non-product type: {:?}", base_layout), }; @@ -802,6 +839,7 @@ fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult { extra: LvalueExtra::DowncastVariant(variant), }); } + Layout::RawNullablePointer { .. } => return Ok(base), _ => panic!("variant downcast on non-aggregate type: {:?}", base_layout), }, diff --git a/src/memory.rs b/src/memory.rs index 9f4e2691bcc..f48d5a9b8e8 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -403,7 +403,7 @@ fn copy_relocations(&mut self, src: Pointer, dest: Pointer, size: usize) -> Eval // Undefined bytes //////////////////////////////////////////////////////////////////////////////// - // FIXME(tsino): This is a very naive, slow version. + // FIXME(tsion): This is a very naive, slow version. fn copy_undef_mask(&mut self, src: Pointer, dest: Pointer, size: usize) -> EvalResult<()> { // The bits have to be saved locally before writing to dest in case src and dest overlap. let mut v = Vec::with_capacity(size); diff --git a/tests/compile-fail/bugs/option_box_transmute_ptr.rs b/tests/compile-fail/bugs/option_box_transmute_ptr.rs deleted file mode 100644 index 84161daf88d..00000000000 --- a/tests/compile-fail/bugs/option_box_transmute_ptr.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(custom_attribute)] -#![allow(dead_code, unused_attributes)] - -#[miri_run] -fn option_box_deref() -> i32 { - let val = Some(Box::new(42)); - unsafe { - let ptr: *const i32 = std::mem::transmute(val); //~ ERROR: pointer offset outside bounds of allocation - *ptr - } -} - -fn main() {} diff --git a/tests/run-pass/option_box_transmute_ptr.rs b/tests/run-pass/option_box_transmute_ptr.rs new file mode 100644 index 00000000000..55beb11edd4 --- /dev/null +++ b/tests/run-pass/option_box_transmute_ptr.rs @@ -0,0 +1,15 @@ +#![feature(custom_attribute)] +#![allow(dead_code, unused_attributes)] + +// This tests that the size of Option> is the same as *const i32. + +#[miri_run] +fn option_box_deref() -> i32 { + let val = Some(Box::new(42)); + unsafe { + let ptr: *const i32 = std::mem::transmute::>, *const i32>(val); + *ptr + } +} + +fn main() {}