Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EXPERIMENT] Record an allowed byte range in pointer provenance for miri #105264

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// second borrowed place for the same union and an access to a different field.
for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
match elem {
ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
ProjectionElem::Field(field, _, _) if union_ty(place_base).is_some() => {
return Some((place_base, field));
}
_ => {}
Expand All @@ -1305,7 +1305,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for an access to a different field of the same union.
for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
if let ProjectionElem::Field(field, _) = elem {
if let ProjectionElem::Field(field, _, _) = elem {
if let Some(union_ty) = union_ty(place_base) {
if field != target_field && place_base == target_base {
return Some((
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ProjectionElem::Downcast(..) if opt.including_downcast => return None,
ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Field(field, _ty) => {
ProjectionElem::Field(field, _, _) => {
// FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
local,
Expand Down Expand Up @@ -321,7 +321,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
ProjectionElem::Field(_, field_type, _) => PlaceTy::from_ty(*field_type),
},
};
self.describe_field_from_ty(
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {

PlaceRef {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _, _)],
} => {
debug_assert!(is_closure_or_generator(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
Expand Down Expand Up @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
&[
ref proj_base @ ..,
ProjectionElem::Deref,
ProjectionElem::Field(field, _),
ProjectionElem::Field(field, _, _),
ProjectionElem::Deref,
],
} => {
Expand Down Expand Up @@ -349,7 +349,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// Also suggest adding mut for upvars
PlaceRef {
local,
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)],
projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _, _)],
} => {
debug_assert!(is_closure_or_generator(
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/path_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>(
}

match place_ref.last_projection() {
Some((place_base, ProjectionElem::Field(field, _ty))) => {
Some((place_base, ProjectionElem::Field(field, _, _))) => {
let base_ty = place_base.ty(body, tcx).ty;
if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || upvars[field.index()].by_ref)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/places_conflict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ fn place_projection_conflict<'tcx>(
debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
Overlap::EqualOrDisjoint
}
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
(ProjectionElem::Field(f1, _, _), ProjectionElem::Field(f2, _, _)) => {
if f1 == f2 {
// same field (e.g., `a.y` vs. `a.y`) - recur.
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/prefixes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
}
Some((cursor_base, elem)) => {
match elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
ProjectionElem::Field(..) => {
// FIXME: add union handling
self.next = Some(cursor_base);
return Some(cursor);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
PlaceTy::from_ty(ty)
}
},
ProjectionElem::Field(field, fty) => {
ProjectionElem::Field(field, fty, _) => {
let fty = self.sanitize_type(place, fty);
let fty = self.cx.normalize(fty, location);
match self.field_ty(place, base, field, location) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,7 @@ pub(crate) fn codegen_place<'tcx>(
cplace = cplace.place_deref(fx);
}
PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
PlaceElem::Field(field, _ty) => {
PlaceElem::Field(field, _, _) => {
cplace = cplace.place_field(fx, field);
}
PlaceElem::Index(local) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ fn generator_layout_and_saved_local_names<'tcx>(
mir::ProjectionElem::Deref,
// Field of a variant of the state.
mir::ProjectionElem::Downcast(_, variant),
mir::ProjectionElem::Field(field, _),
mir::ProjectionElem::Field(field, _, _),
] => {
let name = &mut generator_saved_local_names
[generator_layout.variant_fields[variant][field]];
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
indirect_offsets.push(Size::ZERO);
place = bx.load_operand(place).deref(bx.cx());
}
mir::ProjectionElem::Field(field, _) => {
mir::ProjectionElem::Field(field, _, _) => {
let i = field.index();
let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
*offset += place.layout.fields.offset(i);
Expand Down Expand Up @@ -439,7 +439,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

for elem in &fragment.projection {
match *elem {
mir::ProjectionElem::Field(field, _) => {
mir::ProjectionElem::Field(field, _, _) => {
let i = field.index();
fragment_start += fragment_layout.fields.offset(i);
fragment_layout = fragment_layout.field(self.cx, i);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Moves out of scalar and scalar pair fields are trivial.
for elem in place_ref.projection.iter() {
match elem {
mir::ProjectionElem::Field(ref f, _) => {
mir::ProjectionElem::Field(ref f, _, _) => {
o = o.extract_field(bx, f.index());
}
mir::ProjectionElem::Index(_)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
for elem in place_ref.projection[base..].iter() {
cg_base = match *elem {
mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
mir::ProjectionElem::Field(ref field, _) => {
mir::ProjectionElem::Field(ref field, _, _) => {
cg_base.project_field(bx, field.index())
}
mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(

let fields_iter = (0..field_count)
.map(|i| {
let field_op = ecx.operand_field(&down, i)?;
let field_op = ecx.operand_field(&down, i, mir::ProjectionMode::Strong)?;
let val = op_to_const(&ecx, &field_op);
Ok(mir::ConstantKind::Val(val, field_op.layout.ty))
})
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/valtrees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::interpret::{
MemoryKind, PlaceTy, Scalar,
};
use crate::interpret::{MPlaceTy, Value};
use rustc_middle::mir::ProjectionMode;
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_span::source_map::DUMMY_SP;
use rustc_target::abi::{Align, VariantIdx};
Expand All @@ -27,7 +28,7 @@ fn branches<'tcx>(

let mut fields = Vec::with_capacity(n);
for i in 0..n {
let field = ecx.mplace_field(&place, i).unwrap();
let field = ecx.mplace_field(&place, i, ProjectionMode::Strong).unwrap();
let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?;
fields.push(Some(valtree));
}
Expand Down Expand Up @@ -436,7 +437,7 @@ fn valtree_into_mplace<'tcx>(
)
.unwrap()
}
_ => ecx.mplace_field(&place_adjusted, i).unwrap(),
_ => ecx.mplace_field(&place_adjusted, i, ProjectionMode::Strong).unwrap(),
};

debug!(?place_inner);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::convert::TryFrom;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::{Float, FloatConvert};
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::mir::CastKind;
use rustc_middle::mir::{CastKind, ProjectionMode};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
Expand Down Expand Up @@ -385,8 +385,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
if cast_ty_field.is_zst() {
continue;
}
let src_field = self.operand_field(src, i)?;
let dst_field = self.place_field(dest, i)?;
let src_field = self.operand_field(src, i, ProjectionMode::Strong)?;
let dst_field = self.place_field(dest, i, ProjectionMode::Strong)?;
if src_field.layout.ty == cast_ty_field.ty {
self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::convert::TryFrom;

use rustc_ast::Mutability;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::TerminatorKind;
use rustc_middle::mir::{ProjectionMode, TerminatorKind};
use rustc_middle::ty::layout::LayoutOf;
use rustc_span::{Span, Symbol};

Expand Down Expand Up @@ -102,12 +102,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let location = self.allocate(loc_layout, MemoryKind::CallerLocation).unwrap();

// Initialize fields.
self.write_immediate(file.to_ref(self), &self.mplace_field(&location, 0).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
.expect("writing to memory we just allocated cannot fail");
self.write_immediate(
file.to_ref(self),
&self.mplace_field(&location, 0, ProjectionMode::Strong).unwrap().into(),
)
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(
line,
&self.mplace_field(&location, 1, ProjectionMode::Strong).unwrap().into(),
)
.expect("writing to memory we just allocated cannot fail");
self.write_scalar(
col,
&self.mplace_field(&location, 2, ProjectionMode::Strong).unwrap().into(),
)
.expect("writing to memory we just allocated cannot fail");

location
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_const_eval/src/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,16 @@ pub trait Machine<'mir, 'tcx>: Sized {
throw_unsup_format!("inline assembly is not supported")
}

#[inline(always)]
fn ptr_check_range(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_range: AllocRange,
(_alloc_id, _prov_extra): (AllocId, Self::ProvenanceExtra),
_msg: super::CheckInAllocMsg,
) -> InterpResult<'tcx> {
Ok(())
}

/// Hook for performing extra checks on a memory read access.
///
/// Takes read-only access to the allocation so we can keep all the memory read
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_const_eval/src/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
msg,
})
}
M::ptr_check_range(self, alloc_range(offset, size), (alloc_id, prov), msg)?;
// Ensure we never consider the null pointer dereferenceable.
if M::Provenance::OFFSET_IS_ADDR {
assert_ne!(ptr.addr(), Size::ZERO);
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?;

// Read tag and sanity-check `tag_layout`.
let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
let tag_val = self.read_immediate(&self.operand_field(
op,
tag_field,
mir::ProjectionMode::Strong,
)?)?;
assert_eq!(tag_layout.size, tag_val.layout.size);
assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
trace!("tag value: {}", tag_val);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// With randomized layout, `(int, bool)` might cease to be a `ScalarPair`, so we have to
// do a component-wise write here. This code path is slower than the above because
// `place_field` will have to `force_allocate` locals here.
let val_field = self.place_field(&dest, 0)?;
let val_field = self.place_field(&dest, 0, mir::ProjectionMode::Strong)?;
self.write_scalar(val, &val_field)?;
let overflowed_field = self.place_field(&dest, 1)?;
let overflowed_field = self.place_field(&dest, 1, mir::ProjectionMode::Strong)?;
self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?;
}
Ok(())
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ impl<'tcx, Prov: Provenance> MPlaceTy<'tcx, Prov> {
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
}
}

/// Adjust the provenance of the main pointer (metadata is unaffected).
pub fn map_provenance(self, f: impl FnOnce(Option<Prov>) -> Option<Prov>) -> Self {
MPlaceTy { mplace: self.mplace.map_provenance(f), ..self }
}
}

// These are defined here because they produce a place.
Expand Down Expand Up @@ -820,7 +825,7 @@ where
let size = tag_layout.size(self);
let tag_val = size.truncate(discr_val);

let tag_dest = self.place_field(dest, tag_field)?;
let tag_dest = self.place_field(dest, tag_field, mir::ProjectionMode::Strong)?;
self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
}
abi::Variants::Multiple {
Expand Down Expand Up @@ -851,7 +856,8 @@ where
&niche_start_val,
)?;
// Write result.
let niche_dest = self.place_field(dest, tag_field)?;
let niche_dest =
self.place_field(dest, tag_field, mir::ProjectionMode::Strong)?;
self.write_immediate(*tag_val, &niche_dest)?;
}
}
Expand Down
21 changes: 16 additions & 5 deletions compiler/rustc_const_eval/src/interpret/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ where
&self,
base: &MPlaceTy<'tcx, M::Provenance>,
field: usize,
strength: mir::ProjectionMode,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let offset = base.layout.fields.offset(field);
let field_layout = base.layout.field(self, field);
Expand All @@ -63,7 +64,15 @@ where

// We do not look at `base.layout.align` nor `field_layout.align`, unlike
// codegen -- mostly to see if we can get away with that
base.offset_with_meta(offset, meta, field_layout, self)
let mut place = base.offset_with_meta(offset, meta, field_layout, self)?;

if let mir::ProjectionMode::Strong = strength {
place = place.map_provenance(|prov| {
prov.map(|prov| prov.restrict_to_range(place.ptr, field_layout.layout))
});
}

Ok(place)
}

/// Gets the place of a field inside the place, and also the field's type.
Expand All @@ -74,22 +83,24 @@ where
&mut self,
base: &PlaceTy<'tcx, M::Provenance>,
field: usize,
strength: mir::ProjectionMode,
) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
// FIXME: We could try to be smarter and avoid allocation for fields that span the
// entire place.
let base = self.force_allocation(base)?;
Ok(self.mplace_field(&base, field)?.into())
Ok(self.mplace_field(&base, field, strength)?.into())
}

pub fn operand_field(
&self,
base: &OpTy<'tcx, M::Provenance>,
field: usize,
strength: mir::ProjectionMode,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let base = match base.as_mplace_or_imm() {
Left(ref mplace) => {
// We can reuse the mplace field computation logic for indirect operands.
let field = self.mplace_field(mplace, field)?;
let field = self.mplace_field(mplace, field, strength)?;
return Ok(field.into());
}
Right(value) => value,
Expand Down Expand Up @@ -357,7 +368,7 @@ where
place.layout = self.layout_of(ty)?;
place
}
Field(field, _) => self.place_field(base, field.index())?,
Field(field, _, strength) => self.place_field(base, field.index(), strength)?,
Downcast(_, variant) => self.place_downcast(base, variant)?,
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
Index(local) => {
Expand Down Expand Up @@ -386,7 +397,7 @@ where
op.layout = self.layout_of(ty)?;
op
}
Field(field, _) => self.operand_field(base, field.index())?,
Field(field, _, strength) => self.operand_field(base, field.index(), strength)?,
Downcast(_, variant) => self.operand_downcast(base, variant)?,
Deref => self.deref_operand(base)?.into(),
Index(local) => {
Expand Down
Loading