only count deref_operand as actual deref, but not all ref-to-place conversions

This commit is contained in:
Ralf Jung 2018-11-07 10:07:50 +01:00
parent f174099885
commit 154835e5e7
5 changed files with 31 additions and 32 deletions

View File

@ -183,8 +183,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
} else if Some(def_id) == self.tcx.lang_items().panic_fn() { } else if Some(def_id) == self.tcx.lang_items().panic_fn() {
assert!(args.len() == 1); assert!(args.len() == 1);
// &(&'static str, &'static str, u32, u32) // &(&'static str, &'static str, u32, u32)
let ptr = self.read_immediate(args[0])?; let place = self.deref_operand(args[0])?;
let place = self.ref_to_mplace(ptr)?;
let (msg, file, line, col) = ( let (msg, file, line, col) = (
self.mplace_field(place, 0)?, self.mplace_field(place, 0)?,
self.mplace_field(place, 1)?, self.mplace_field(place, 1)?,
@ -192,9 +191,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
self.mplace_field(place, 3)?, self.mplace_field(place, 3)?,
); );
let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?; let msg_place = self.deref_operand(msg.into())?;
let msg = Symbol::intern(self.read_str(msg_place)?); let msg = Symbol::intern(self.read_str(msg_place)?);
let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?; let file_place = self.deref_operand(file.into())?;
let file = Symbol::intern(self.read_str(file_place)?); let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?; let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?;
@ -203,17 +202,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
assert!(args.len() == 2); assert!(args.len() == 2);
// &'static str, &(&'static str, u32, u32) // &'static str, &(&'static str, u32, u32)
let msg = args[0]; let msg = args[0];
let ptr = self.read_immediate(args[1])?; let place = self.deref_operand(args[1])?;
let place = self.ref_to_mplace(ptr)?;
let (file, line, col) = ( let (file, line, col) = (
self.mplace_field(place, 0)?, self.mplace_field(place, 0)?,
self.mplace_field(place, 1)?, self.mplace_field(place, 1)?,
self.mplace_field(place, 2)?, self.mplace_field(place, 2)?,
); );
let msg_place = self.ref_to_mplace(self.read_immediate(msg.into())?)?; let msg_place = self.deref_operand(msg.into())?;
let msg = Symbol::intern(self.read_str(msg_place)?); let msg = Symbol::intern(self.read_str(msg_place)?);
let file_place = self.ref_to_mplace(self.read_immediate(file.into())?)?; let file_place = self.deref_operand(file.into())?;
let file = Symbol::intern(self.read_str(file_place)?); let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?; let line = self.read_scalar(line.into())?.to_u32()?;
let col = self.read_scalar(col.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?;

View File

@ -555,17 +555,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}) })
} }
// Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace.
pub(super) fn deref_operand(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
Ok(self.ref_to_mplace(val)?)
}
pub fn operand_projection( pub fn operand_projection(
&self, &self,
base: OpTy<'tcx, M::PointerTag>, base: OpTy<'tcx, M::PointerTag>,

View File

@ -277,6 +277,8 @@ where
{ {
/// Take a value, which represents a (thin or fat) reference, and make it a place. /// Take a value, which represents a (thin or fat) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`.
/// This does NOT call the "deref" machine hook, so it does NOT count as a
/// deref as far as Stacked Borrows is concerned. Use `deref_operand` for that!
pub fn ref_to_mplace( pub fn ref_to_mplace(
&self, &self,
val: ImmTy<'tcx, M::PointerTag>, val: ImmTy<'tcx, M::PointerTag>,
@ -284,11 +286,25 @@ where
let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty; let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
let layout = self.layout_of(pointee_type)?; let layout = self.layout_of(pointee_type)?;
let align = layout.align; let mplace = MemPlace {
let meta = val.to_meta()?; ptr: val.to_scalar_ptr()?,
let ptr = val.to_scalar_ptr()?; align: layout.align,
let mplace = MemPlace { ptr, align, meta }; meta: val.to_meta()?,
let mut mplace = MPlaceTy { mplace, layout }; };
Ok(MPlaceTy { mplace, layout })
}
// Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace. Lives in `place.rs` because it creates a place.
// This calls the "deref" machine hook, and counts as a deref as far as
// Stacked Borrows is concerned.
pub fn deref_operand(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
let mut place = self.ref_to_mplace(val)?;
// Pointer tag tracking might want to adjust the tag. // Pointer tag tracking might want to adjust the tag.
let mutbl = match val.layout.ty.sty { let mutbl = match val.layout.ty.sty {
// `builtin_deref` considers boxes immutable, that's useless for our purposes // `builtin_deref` considers boxes immutable, that's useless for our purposes
@ -297,9 +313,8 @@ where
ty::RawPtr(_) => None, ty::RawPtr(_) => None,
_ => bug!("Unexpected pointer type {}", val.layout.ty.sty), _ => bug!("Unexpected pointer type {}", val.layout.ty.sty),
}; };
mplace.mplace.ptr = M::tag_dereference(self, mplace, mutbl)?; place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
// Done Ok(place)
Ok(mplace)
} }
/// Offset a pointer to project to a field. Unlike place_field, this is always /// Offset a pointer to project to a field. Unlike place_field, this is always

View File

@ -402,7 +402,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
ty::InstanceDef::Virtual(_, idx) => { ty::InstanceDef::Virtual(_, idx) => {
let ptr_size = self.pointer_size(); let ptr_size = self.pointer_size();
let ptr_align = self.tcx.data_layout.pointer_align; let ptr_align = self.tcx.data_layout.pointer_align;
let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let ptr = self.deref_operand(args[0])?;
let vtable = ptr.vtable()?; let vtable = ptr.vtable()?;
let fn_ptr = self.memory.read_ptr_sized( let fn_ptr = self.memory.read_ptr_sized(
vtable.offset(ptr_size * (idx as u64 + 3), self)?, vtable.offset(ptr_size * (idx as u64 + 3), self)?,

View File

@ -322,13 +322,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
} }
} }
} }
// Turn ptr into place.
// `ref_to_mplace` also calls the machine hook for (re)activating the tag,
// which in turn will (in full miri) check if the pointer is dereferencable.
let place = self.ecx.ref_to_mplace(value)?;
// Recursive checking // Recursive checking
if let Some(ref mut ref_tracking) = self.ref_tracking { if let Some(ref mut ref_tracking) = self.ref_tracking {
assert!(self.const_mode, "We should only do recursie checking in const mode"); assert!(self.const_mode, "We should only do recursie checking in const mode");
let place = self.ecx.ref_to_mplace(value)?;
if size != Size::ZERO { if size != Size::ZERO {
// Non-ZST also have to be dereferencable // Non-ZST also have to be dereferencable
let ptr = try_validation!(place.ptr.to_ptr(), let ptr = try_validation!(place.ptr.to_ptr(),