Skip to content

Rollup of 7 pull requests #69845

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

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7ca1b2f
Don't use static crt by default when build proc-macro.
12101111 Mar 3, 2020
7996df9
Run format.
12101111 Mar 3, 2020
89aebbd
Only run this test on musl
12101111 Mar 3, 2020
84349cc
Remove trailing whitespace.
12101111 Mar 3, 2020
a755d8d
Support type search for arguments and returned types
GuillaumeGomez Feb 23, 2020
612d375
Update JS results tester
GuillaumeGomez Feb 23, 2020
5892d0d
Add tests for new of variables
GuillaumeGomez Feb 23, 2020
71b9512
formatting
GuillaumeGomez Feb 23, 2020
6ffe9f3
Rename render::Type to improve naming
GuillaumeGomez Mar 3, 2020
f63b88c
Permit attributes on 'if' expressions
Aaron1011 Feb 16, 2020
e912d9d
Test #[allow(unused)] on `if` expression
Aaron1011 Feb 16, 2020
e9ec47b
Test that stmt_expr_attrs properly gates if-attrs
Aaron1011 Feb 19, 2020
9a299e4
Test trying to cfg-remove an `if` expression
Aaron1011 Feb 19, 2020
b00f674
Remove recovery test
Aaron1011 Feb 19, 2020
e11cdfd
Add run-pass test suggested by @joshtriplett
Aaron1011 Feb 19, 2020
7f19358
Move if-attr tests to their own directory
Aaron1011 Feb 19, 2020
1b681d6
Test that cfg-gated if-exprs are not type-checked
Aaron1011 Feb 19, 2020
37c2c38
Extent pretty-print test
Aaron1011 Feb 19, 2020
66b152c
Fix tabs
Aaron1011 Feb 19, 2020
e50fd5a
Update stderr
Aaron1011 Mar 4, 2020
22ee27b
update backtrace crate
RalfJung Mar 5, 2020
dbed65a
Simplify checking of crt_static_feature()
12101111 Mar 8, 2020
7a89bf1
override flags from compiletest
12101111 Mar 8, 2020
0468929
move error allocation test to error.rs
RalfJung Mar 4, 2020
938f852
miri validation: debug-complain about unexpected errors
RalfJung Mar 4, 2020
4971d03
fix some cases of unexpected exceptions leaving validation
RalfJung Mar 5, 2020
85e1466
Fix typo
RalfJung Mar 6, 2020
ed3014a
use static strings instead of tcx
RalfJung Mar 6, 2020
75e6cfc
run crt-static test on all target
12101111 Mar 9, 2020
58303b7
Use slices in preference to 0-terminated strings
tmiasko Mar 6, 2020
e54a829
Avoid unnecessary interning of enum variant part id
tmiasko Mar 6, 2020
676b9bc
unix: Don't override existing SIGSEGV/BUS handlers
cuviper Mar 3, 2020
7718ae3
Rollup merge of #69201 - Aaron1011:feature/permit-if-attr, r=Centril
Centril Mar 9, 2020
5ac1fba
Rollup merge of #69402 - GuillaumeGomez:extend-search, r=kinnison
Centril Mar 9, 2020
2f59631
Rollup merge of #69519 - 12101111:remove-proc-macro-check, r=nagisa,s…
Centril Mar 9, 2020
369afc8
Rollup merge of #69685 - cuviper:soft-segv, r=sfackler
Centril Mar 9, 2020
8301e32
Rollup merge of #69729 - RalfJung:backtrace, r=Mark-Simulacrum
Centril Mar 9, 2020
867104a
Rollup merge of #69762 - RalfJung:validity-errors, r=oli-obk
Centril Mar 9, 2020
51ff921
Rollup merge of #69779 - tmiasko:di-cstr, r=nagisa
Centril Mar 9, 2020
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
27 changes: 23 additions & 4 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ fn print_backtrace(backtrace: &mut Backtrace) {
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
}

impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
match err {
ErrorHandled::Reported => err_inval!(ReferencedConstant),
Expand Down Expand Up @@ -291,7 +291,7 @@ pub enum InvalidProgramInfo<'tcx> {
Layout(layout::LayoutError<'tcx>),
}

impl fmt::Debug for InvalidProgramInfo<'tcx> {
impl fmt::Debug for InvalidProgramInfo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InvalidProgramInfo::*;
match self {
Expand Down Expand Up @@ -321,6 +321,8 @@ pub enum UndefinedBehaviorInfo {
RemainderByZero,
/// Overflowing inbounds pointer arithmetic.
PointerArithOverflow,
/// Invalid metadata in a wide pointer (using `str` to avoid allocations).
InvalidMeta(&'static str),
}

impl fmt::Debug for UndefinedBehaviorInfo {
Expand All @@ -338,6 +340,7 @@ impl fmt::Debug for UndefinedBehaviorInfo {
DivisionByZero => write!(f, "dividing by zero"),
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
}
}
}
Expand All @@ -354,8 +357,8 @@ pub enum UnsupportedOpInfo<'tcx> {
Unsupported(String),

/// When const-prop encounters a situation it does not support, it raises this error.
/// This must not allocate for performance reasons.
ConstPropUnsupported(&'tcx str),
/// This must not allocate for performance reasons (hence `str`, not `String`).
ConstPropUnsupported(&'static str),

// -- Everything below is not categorized yet --
FunctionAbiMismatch(Abi, Abi),
Expand Down Expand Up @@ -612,3 +615,19 @@ impl fmt::Debug for InterpError<'_> {
}
}
}

impl InterpError<'_> {
/// Some errors allocate to be created as they contain free-form strings.
/// And sometimes we want to be sure that did not happen as it is a
/// waste of resources.
pub fn allocates(&self) -> bool {
match self {
InterpError::MachineStop(_)
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true,
_ => false,
}
}
}
7 changes: 6 additions & 1 deletion src/librustc_mir/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,12 @@ fn validate_and_turn_into_const<'tcx>(
if cid.promoted.is_none() {
let mut ref_tracking = RefTracking::new(mplace);
while let Some((mplace, path)) = ref_tracking.todo.pop() {
ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?;
ecx.const_validate_operand(
mplace.into(),
path,
&mut ref_tracking,
/*may_ref_to_static*/ is_static,
)?;
}
}
// Now that we validated, turn this into a proper constant.
Expand Down
12 changes: 3 additions & 9 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

// Check if this brought us over the size limit.
if size.bytes() >= self.tcx.data_layout().obj_size_bound() {
throw_ub_format!(
"wide pointer metadata contains invalid information: \
total size is bigger than largest supported object"
);
throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
}
Ok(Some((size, align)))
}
Expand All @@ -476,10 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

// Make sure the slice is not too big.
let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| {
err_ub_format!(
"invalid slice: \
total size is bigger than largest supported object"
)
err_ub!(InvalidMeta("slice is bigger than largest supported object"))
})?;
Ok(Some((size, elem.align.abi)))
}
Expand Down Expand Up @@ -685,7 +679,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// invariant -- that is, unless a function somehow has a ptr to
// its return place... but the way MIR is currently generated, the
// return place is always a local and then this cannot happen.
self.validate_operand(self.place_to_op(return_place)?, vec![], None)?;
self.validate_operand(self.place_to_op(return_place)?)?;
}
} else {
// Uh, that shouldn't happen... the function did not intend to return
Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ where

if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
self.validate_operand(self.place_to_op(dest)?, vec![], None)?;
self.validate_operand(self.place_to_op(dest)?)?;
}

Ok(())
Expand All @@ -706,7 +706,7 @@ where

if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
self.validate_operand(dest.into(), vec![], None)?;
self.validate_operand(dest.into())?;
}

Ok(())
Expand Down Expand Up @@ -843,7 +843,7 @@ where

if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
self.validate_operand(self.place_to_op(dest)?, vec![], None)?;
self.validate_operand(self.place_to_op(dest)?)?;
}

Ok(())
Expand Down Expand Up @@ -951,7 +951,7 @@ where

if M::enforce_validity(self) {
// Data got changed, better make sure it matches the type!
self.validate_operand(dest.into(), vec![], None)?;
self.validate_operand(dest.into())?;
}

Ok(())
Expand Down
91 changes: 71 additions & 20 deletions src/librustc_mir/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ macro_rules! try_validation {
($e:expr, $what:expr, $where:expr, $details:expr) => {{
match $e {
Ok(x) => x,
// We re-throw the error, so we are okay with allocation:
// this can only slow down builds that fail anyway.
Err(_) => throw_validation_failure!($what, $where, $details),
}
}};

($e:expr, $what:expr, $where:expr) => {{
match $e {
Ok(x) => x,
// We re-throw the error, so we are okay with allocation:
// this can only slow down builds that fail anyway.
Err(_) => throw_validation_failure!($what, $where),
}
}};
Expand Down Expand Up @@ -167,6 +171,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
path: Vec<PathElem>,
ref_tracking_for_consts:
Option<&'rt mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
may_ref_to_static: bool,
ecx: &'rt InterpCx<'mir, 'tcx, M>,
}

Expand Down Expand Up @@ -320,9 +325,17 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
self.check_wide_ptr_meta(place.meta, place.layout)?;
}
// Make sure this is dereferenceable and all.
let (size, align) = self
.ecx
.size_and_align_of(place.meta, place.layout)?
let size_and_align = match self.ecx.size_and_align_of(place.meta, place.layout) {
Ok(res) => res,
Err(err) => match err.kind {
err_ub!(InvalidMeta(msg)) => throw_validation_failure!(
format_args!("invalid {} metadata: {}", kind, msg),
self.path
),
_ => bug!("Unexpected error during ptr size_and_align_of: {}", err),
},
};
let (size, align) = size_and_align
// for the purpose of validity, consider foreign types to have
// alignment and size determined by the layout (size will be 0,
// alignment should take attributes into account).
Expand Down Expand Up @@ -359,10 +372,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
format_args!("a dangling {} (created from integer)", kind),
self.path
),
_ => throw_validation_failure!(
format_args!("a dangling {} (not entirely in bounds)", kind),
self.path
),
err_unsup!(PointerOutOfBounds { .. }) | err_unsup!(DanglingPointerDeref) => {
throw_validation_failure!(
format_args!("a dangling {} (not entirely in bounds)", kind),
self.path
)
}
_ => bug!("Unexpected error during ptr inbounds test: {}", err),
}
}
};
Expand All @@ -380,6 +396,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
return Ok(());
}
if !self.may_ref_to_static && self.ecx.tcx.is_static(did) {
throw_validation_failure!(
format_args!("a {} pointing to a static variable", kind),
self.path
);
}
}
}
// Proceed recursively even for ZST, no reason to skip them!
Expand Down Expand Up @@ -638,6 +660,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
err_unsup!(ReadPointerAsBytes) => {
throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes")
}
// Propagate upwards (that will also check for unexpected errors).
_ => return Err(err),
},
}
Expand Down Expand Up @@ -773,31 +796,59 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
}

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// This function checks the data at `op`. `op` is assumed to cover valid memory if it
/// is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
///
/// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references.
/// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion)
/// validation (e.g., pointer values are fine in integers at runtime) and various other const
/// specific validation checks.
pub fn validate_operand(
fn validate_operand_internal(
&self,
op: OpTy<'tcx, M::PointerTag>,
path: Vec<PathElem>,
ref_tracking_for_consts: Option<
&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
>,
may_ref_to_static: bool,
) -> InterpResult<'tcx> {
trace!("validate_operand: {:?}, {:?}", *op, op.layout.ty);
trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty);

// Construct a visitor
let mut visitor = ValidityVisitor { path, ref_tracking_for_consts, ecx: self };
let mut visitor =
ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self };

// Try to cast to ptr *once* instead of all the time.
let op = self.force_op_ptr(op).unwrap_or(op);

// Run it
visitor.visit_value(op)
// Run it.
match visitor.visit_value(op) {
Ok(()) => Ok(()),
Err(err) if matches!(err.kind, err_unsup!(ValidationFailure { .. })) => Err(err),
Err(err) if cfg!(debug_assertions) => {
bug!("Unexpected error during validation: {}", err)
}
Err(err) => Err(err),
}
}

/// This function checks the data at `op` to be const-valid.
/// `op` is assumed to cover valid memory if it is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
///
/// `ref_tracking` is used to record references that we encounter so that they
/// can be checked recursively by an outside driving loop.
///
/// `may_ref_to_static` controls whether references are allowed to point to statics.
#[inline(always)]
pub fn const_validate_operand(
&self,
op: OpTy<'tcx, M::PointerTag>,
path: Vec<PathElem>,
ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
may_ref_to_static: bool,
) -> InterpResult<'tcx> {
self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static)
}

/// This function checks the data at `op` to be runtime-valid.
/// `op` is assumed to cover valid memory if it is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
#[inline(always)]
pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
self.validate_operand_internal(op, vec![], None, false)
}
}
40 changes: 12 additions & 28 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,32 +404,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let r = match f(self) {
Ok(val) => Some(val),
Err(error) => {
use rustc::mir::interpret::{
InterpError::*, UndefinedBehaviorInfo, UnsupportedOpInfo,
};
match error.kind {
MachineStop(_) => bug!("ConstProp does not stop"),

// Some error shouldn't come up because creating them causes
// an allocation, which we should avoid. When that happens,
// dedicated error variants should be introduced instead.
// Only test this in debug builds though to avoid disruptions.
Unsupported(UnsupportedOpInfo::Unsupported(_))
| Unsupported(UnsupportedOpInfo::ValidationFailure(_))
| UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
| UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_))
if cfg!(debug_assertions) =>
{
bug!("const-prop encountered allocating error: {:?}", error.kind);
}

Unsupported(_)
| UndefinedBehavior(_)
| InvalidProgram(_)
| ResourceExhaustion(_) => {
// Ignore these errors.
}
}
// Some errors shouldn't come up because creating them causes
// an allocation, which we should avoid. When that happens,
// dedicated error variants should be introduced instead.
// Only test this in debug builds though to avoid disruptions.
debug_assert!(
!error.kind.allocates(),
"const-prop encountered allocating error: {}",
error
);
None
}
};
Expand Down Expand Up @@ -654,11 +637,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
source_info: SourceInfo,
) {
trace!("attepting to replace {:?} with {:?}", rval, value);
if let Err(e) = self.ecx.validate_operand(
if let Err(e) = self.ecx.const_validate_operand(
value,
vec![],
// FIXME: is ref tracking too expensive?
Some(&mut interpret::RefTracking::empty()),
&mut interpret::RefTracking::empty(),
/*may_ref_to_static*/ true,
) {
trace!("validation error, attempt failed: {:?}", e);
return;
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/dangling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{mem, usize};
const TEST: () = { unsafe { //~ NOTE
let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
let _val = &*slice; //~ ERROR: any use of this value will cause an error
//~^ NOTE: total size is bigger than largest supported object
//~^ NOTE: slice is bigger than largest supported object
//~^^ on by default
} };

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/dangling.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error: any use of this value will cause an error
LL | / const TEST: () = { unsafe {
LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX));
LL | | let _val = &*slice;
| | ^^^^^^^ invalid slice: total size is bigger than largest supported object
| | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object
LL | |
LL | |
LL | | } };
Expand Down
Loading