-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[TEST] Don't allow constant eval to access generator layouts #115359
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -267,6 +267,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
|
||
NullaryOp(ref null_op, ty) => { | ||
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; | ||
|
||
// Ensure we don't need the layout of any generators if applicable. | ||
// This prevents typeck from depending on MIR optimizations. | ||
self.validate_generator_layout_access(ty)?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this the one place where the layout is checked? That seems odd, aren't there tons of ways the layout could become relevant? |
||
|
||
let layout = self.layout_of(ty)?; | ||
if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() { | ||
span_bug!( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,8 +16,8 @@ use rustc_middle::mir::interpret::{ | |
ExpectedKind, InterpError, InvalidMetaKind, PointerKind, ValidationErrorInfo, | ||
ValidationErrorKind, ValidationErrorKind::*, | ||
}; | ||
use rustc_middle::ty; | ||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; | ||
use rustc_middle::ty::{self, Ty}; | ||
use rustc_span::symbol::{sym, Symbol}; | ||
use rustc_target::abi::{ | ||
Abi, FieldIdx, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange, | ||
|
@@ -950,4 +950,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | |
// recurse through references which, for now, we don't want here, either. | ||
self.validate_operand_internal(op, vec![], None, None) | ||
} | ||
|
||
/// This function checks if the given `ty`'s layout depends on generators. | ||
#[inline(always)] | ||
pub fn validate_generator_layout_access(&self, ty: Ty<'tcx>) -> InterpResult<'tcx> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "validity.rs" is for checking that a value is valid. Please don't put unrelated functions here. |
||
if !M::ACCESS_GENERATOR_LAYOUT { | ||
let generators = self.tcx.layout_generators(ty); | ||
if !generators.is_empty() { | ||
throw_validation_failure!(Vec::new(), GeneratorLayoutAccess { ty, generators }); | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; | |
|
||
use crate::mir::interpret::ConstValue; | ||
use crate::query::TyCtxtAt; | ||
use crate::ty::{layout, tls, Ty, ValTree}; | ||
use crate::ty::{layout, tls, List, Ty, ValTree}; | ||
|
||
use rustc_data_structures::sync::Lock; | ||
use rustc_errors::{ | ||
|
@@ -404,6 +404,7 @@ pub enum ValidationErrorKind<'tcx> { | |
InvalidBool { value: String }, | ||
InvalidChar { value: String }, | ||
InvalidFnPtr { value: String }, | ||
GeneratorLayoutAccess { ty: Ty<'tcx>, generators: &'tcx List<Ty<'tcx>> }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "ValidationErrorKind" is for when a value doesn't satisfy its validity invariant. This is unrelated, please don't put that here. Sound more like an |
||
} | ||
|
||
/// Error information for when the program did something that might (or might not) be correct | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use rustc_middle::query::Providers; | ||
use rustc_middle::ty::{self, Ty, TyCtxt}; | ||
|
||
pub fn provide(providers: &mut Providers) { | ||
*providers = Providers { layout_generators, ..*providers }; | ||
} | ||
|
||
/// Computes the generators present in the layout of a type. | ||
/// This expects a normalized input type with regions erased. | ||
fn layout_generators<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::List<Ty<'tcx>> { | ||
let mut generators = Vec::new(); | ||
|
||
let inner = |generators: &mut Vec<_>, ty: Ty<'tcx>| { | ||
let list = tcx.layout_generators(ty); | ||
for generator in list.iter() { | ||
generators.push(generator); | ||
} | ||
}; | ||
|
||
match *ty.kind() { | ||
// These can't contain generators in their layout | ||
ty::Bool | ||
| ty::Char | ||
| ty::Int(_) | ||
| ty::Uint(_) | ||
| ty::Float(_) | ||
| ty::FnPtr(_) | ||
| ty::FnDef(..) | ||
| ty::Never | ||
| ty::Ref(..) | ||
| ty::RawPtr(..) | ||
| ty::Str => {} | ||
|
||
ty::Array(element, _) => { | ||
inner(&mut generators, element); | ||
} | ||
|
||
ty::Generator(..) => { | ||
generators.push(ty); | ||
} | ||
|
||
ty::Closure(_, ref args) => { | ||
let tys = args.as_closure().upvar_tys(); | ||
tys.iter().for_each(|ty| inner(&mut generators, ty)); | ||
} | ||
|
||
ty::Tuple(tys) => { | ||
tys.iter().for_each(|ty| inner(&mut generators, ty)); | ||
} | ||
|
||
ty::Adt(def, args) => { | ||
def.variants().iter().for_each(|v| { | ||
v.fields.iter().for_each(|field| { | ||
let ty = field.ty(tcx, args); | ||
let ty = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty); | ||
inner(&mut generators, ty) | ||
}) | ||
}); | ||
} | ||
|
||
ty::Slice(..) | ty::Dynamic(..) | ty::Foreign(..) => { | ||
bug!("these are unsized") | ||
} | ||
|
||
ty::Alias(..) | ||
| ty::Bound(..) | ||
| ty::GeneratorWitness(..) | ||
| ty::GeneratorWitnessMIR(..) | ||
| ty::Infer(_) | ||
| ty::Error(_) | ||
| ty::Placeholder(..) | ||
| ty::Param(_) => { | ||
bug!("unexpected type") | ||
} | ||
} | ||
|
||
tcx.mk_type_list(&generators) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -884,6 +884,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { | |
const GLOBAL_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::Global); | ||
|
||
const PANIC_ON_ALLOC_FAIL: bool = false; | ||
const ACCESS_GENERATOR_LAYOUT: bool = true; | ||
|
||
#[inline(always)] | ||
fn enforce_alignment(ecx: &MiriInterpCx<'mir, 'tcx>) -> CheckAlignment { | ||
|
@@ -1410,17 +1411,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { | |
ecx: &mut InterpCx<'mir, 'tcx, Self>, | ||
frame: usize, | ||
local: mir::Local, | ||
mplace: &MPlaceTy<'tcx, Provenance> | ||
mplace: &MPlaceTy<'tcx, Provenance>, | ||
) -> InterpResult<'tcx> { | ||
let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr.provenance else { | ||
panic!("after_local_allocated should only be called on fresh allocations"); | ||
}; | ||
let local_decl = &ecx.active_thread_stack()[frame].body.local_decls[local]; | ||
let span = local_decl.source_info.span; | ||
ecx.machine | ||
.allocation_spans | ||
.borrow_mut() | ||
.insert(alloc_id, (span, None)); | ||
ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't format these files, they'll have to be reformatted when syncing changes back to Miri. (Miri has a different rustfmt.toml.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why doesn't rustfmt use those settings? :/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's up to RA to tell it the config file to use (rustfmt isn't invoked on a file, it is fed data via stdin and returned via stdout). Not sure if there's an open RA bug for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like RA changes the current directory to match the file for |
||
Ok(()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// error-pattern: evaluation of constant value failed | ||
|
||
#![feature(generators)] | ||
#![feature(generator_trait)] | ||
#![feature(type_alias_impl_trait)] | ||
#![allow(dead_code)] | ||
|
||
type Gen = impl std::ops::Generator; | ||
|
||
const A: usize = std::mem::size_of::<Gen>(); | ||
|
||
const B: usize = std::mem::size_of::<Option<Gen>>(); | ||
|
||
fn gen() -> Gen { | ||
move || { | ||
yield; | ||
} | ||
} | ||
|
||
fn main() {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
error[E0080]: evaluation of constant value failed | ||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL | ||
| | ||
= note: cannot compute layout of `[generator@$DIR/const-eval-size.rs:15:5: 15:12]` | ||
| | ||
note: inside `std::mem::size_of::<[generator@$DIR/const-eval-size.rs:15:5: 15:12]>` | ||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL | ||
note: inside `A` | ||
--> $DIR/const-eval-size.rs:10:18 | ||
| | ||
LL | const A: usize = std::mem::size_of::<Gen>(); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0080]: evaluation of constant value failed | ||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL | ||
| | ||
= note: cannot compute layout of `Option<[generator@$DIR/const-eval-size.rs:15:5: 15:12]>` | ||
| | ||
note: inside `std::mem::size_of::<Option<[generator@$DIR/const-eval-size.rs:15:5: 15:12]>>` | ||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL | ||
note: inside `B` | ||
--> $DIR/const-eval-size.rs:12:18 | ||
| | ||
LL | const B: usize = std::mem::size_of::<Option<Gen>>(); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
= help: because of contained type `[generator@$DIR/const-eval-size.rs:15:5: 15:12]` | ||
|
||
error: aborting due to 2 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0080`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the default value here, and move it to the compile_time_machine macro below. After all this is also shared with Miri, so we don't set defaults here based on "being compile-time".