1
Fork 0

Move alignment failure error reporting to machine

This commit is contained in:
Oli Scherer 2022-11-22 11:16:33 +00:00
parent d66824dbc4
commit d9d92ed7da
6 changed files with 78 additions and 44 deletions

View file

@ -1,9 +1,10 @@
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::LangItem; use rustc_hir::{LangItem, CRATE_HIR_ID};
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::mir::interpret::PointerArithmetic; use rustc_middle::mir::interpret::{PointerArithmetic, UndefinedBehaviorInfo};
use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::hash::Hash; use std::hash::Hash;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -338,6 +339,40 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
} }
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
match check {
CheckAlignment::Error => {
throw_ub!(AlignmentCheckFailed { has, required })
}
CheckAlignment::No => span_bug!(
ecx.cur_span(),
"`alignment_check_failed` called when no alignment check requested"
),
CheckAlignment::FutureIncompat => ecx.tcx.struct_span_lint_hir(
INVALID_ALIGNMENT,
ecx.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
ecx.cur_span(),
UndefinedBehaviorInfo::AlignmentCheckFailed { has, required }.to_string(),
|db| {
let mut stacktrace = ecx.generate_stacktrace();
// Filter out `requires_caller_location` frames.
stacktrace
.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx));
for frame in stacktrace {
db.span_label(frame.span, format!("inside `{}`", frame.instance));
}
db
},
),
}
Ok(())
}
fn load_mir( fn load_mir(
ecx: &InterpCx<'mir, 'tcx, Self>, ecx: &InterpCx<'mir, 'tcx, Self>,
instance: ty::InstanceDef<'tcx>, instance: ty::InstanceDef<'tcx>,

View file

@ -10,7 +10,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_target::abi::Size; use rustc_target::abi::{Align, Size};
use rustc_target::spec::abi::Abi as CallAbi; use rustc_target::spec::abi::Abi as CallAbi;
use crate::const_eval::CheckAlignment; use crate::const_eval::CheckAlignment;
@ -132,6 +132,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// If this returns true, Provenance::OFFSET_IS_ADDR must be true. /// If this returns true, Provenance::OFFSET_IS_ADDR must be true.
fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; fn use_addr_for_alignment_check(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
check: CheckAlignment,
) -> InterpResult<'tcx, ()>;
/// Whether to enforce the validity invariant /// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

View file

@ -14,11 +14,8 @@ use std::ptr;
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::mir::display_allocation; use rustc_middle::mir::display_allocation;
use rustc_middle::mir::interpret::UndefinedBehaviorInfo;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
use rustc_target::abi::{Align, HasDataLayout, Size}; use rustc_target::abi::{Align, HasDataLayout, Size};
use crate::const_eval::CheckAlignment; use crate::const_eval::CheckAlignment;
@ -448,7 +445,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
// Check allocation alignment and offset alignment. // Check allocation alignment and offset alignment.
if alloc_align.bytes() < align.bytes() { if alloc_align.bytes() < align.bytes() {
self.alignment_check_failed(alloc_align, align, check)?; M::alignment_check_failed(self, alloc_align, align, check)?;
} }
self.check_offset_align(offset.bytes(), align, check)?; self.check_offset_align(offset.bytes(), align, check)?;
} }
@ -472,43 +469,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
// The biggest power of two through which `offset` is divisible. // The biggest power of two through which `offset` is divisible.
let offset_pow2 = 1 << offset.trailing_zeros(); let offset_pow2 = 1 << offset.trailing_zeros();
self.alignment_check_failed(Align::from_bytes(offset_pow2).unwrap(), align, check) M::alignment_check_failed(self, Align::from_bytes(offset_pow2).unwrap(), align, check)
} }
} }
fn alignment_check_failed(
&self,
has: Align,
required: Align,
check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
match check {
CheckAlignment::Error => {
throw_ub!(AlignmentCheckFailed { has, required })
}
CheckAlignment::No => span_bug!(
self.cur_span(),
"`alignment_check_failed` called when no alignment check requested"
),
CheckAlignment::FutureIncompat => self.tcx.struct_span_lint_hir(
INVALID_ALIGNMENT,
self.stack().iter().find_map(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID),
self.cur_span(),
UndefinedBehaviorInfo::AlignmentCheckFailed { has, required }.to_string(),
|db| {
let mut stacktrace = self.generate_stacktrace();
// Filter out `requires_caller_location` frames.
stacktrace
.retain(|frame| !frame.instance.def.requires_caller_location(*self.tcx));
for frame in stacktrace {
db.span_label(frame.span, format!("inside `{}`", frame.instance));
}
db
},
),
}
Ok(())
}
} }
/// Allocation accessors /// Allocation accessors

View file

@ -23,7 +23,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayo
use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_span::{def_id::DefId, Span}; use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout}; use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi; use rustc_target::spec::abi::Abi as CallAbi;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
@ -197,6 +197,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
false // for now, we don't enforce validity false // for now, we don't enforce validity
} }
fn alignment_check_failed(
ecx: &InterpCx<'mir, 'tcx, Self>,
_has: Align,
_required: Align,
_check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
span_bug!(
ecx.cur_span(),
"`alignment_check_failed` called when no alignment check requested"
)
}
fn load_mir( fn load_mir(
_ecx: &InterpCx<'mir, 'tcx, Self>, _ecx: &InterpCx<'mir, 'tcx, Self>,

View file

@ -11,6 +11,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace}; use rustc_mir_dataflow::value_analysis::{Map, State, TrackElem, ValueAnalysis, ValueOrPlace};
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects}; use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_target::abi::Align;
use crate::MirPass; use crate::MirPass;
@ -456,6 +457,14 @@ impl<'mir, 'tcx> rustc_const_eval::interpret::Machine<'mir, 'tcx> for DummyMachi
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
unimplemented!() unimplemented!()
} }
fn alignment_check_failed(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_has: Align,
_required: Align,
_check: CheckAlignment,
) -> interpret::InterpResult<'tcx, ()> {
unimplemented!()
}
fn find_mir_or_eval_fn( fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ecx: &mut InterpCx<'mir, 'tcx, Self>,

View file

@ -22,7 +22,7 @@ use rustc_middle::{
}; };
use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Symbol; use rustc_span::Symbol;
use rustc_target::abi::Size; use rustc_target::abi::{Size, Align};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_const_eval::const_eval::CheckAlignment; use rustc_const_eval::const_eval::CheckAlignment;
@ -766,6 +766,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
ecx.machine.check_alignment == AlignmentCheck::Int ecx.machine.check_alignment == AlignmentCheck::Int
} }
fn alignment_check_failed(
_ecx: &InterpCx<'mir, 'tcx, Self>,
has: Align,
required: Align,
_check: CheckAlignment,
) -> InterpResult<'tcx, ()> {
throw_ub!(AlignmentCheckFailed { has, required })
}
#[inline(always)] #[inline(always)]
fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool { fn enforce_validity(ecx: &MiriInterpCx<'mir, 'tcx>) -> bool {
ecx.machine.validate ecx.machine.validate