Skip to content

Commit 8b14b03

Browse files
authored
Merge pull request #473 from solson/rustup
rustup: Update for rustc validation fixes
2 parents 7fb2fa7 + 9a1dd86 commit 8b14b03

28 files changed

+167
-83
lines changed

rust-toolchain

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2018-10-11
1+
nightly-2018-10-14

rustc_tests/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
9595
if i.attrs.iter().any(|attr| attr.name() == "test") {
9696
let did = self.0.hir.body_owner_def_id(body_id);
9797
println!("running test: {}", self.0.def_path_debug_str(did));
98-
miri::eval_main(self.0, did, None);
98+
miri::eval_main(self.0, did, None, /*validate*/true);
9999
self.1.session.abort_if_errors();
100100
}
101101
}
@@ -106,7 +106,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) {
106106
state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state));
107107
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
108108
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
109-
miri::eval_main(tcx, entry_def_id, None);
109+
miri::eval_main(tcx, entry_def_id, None, /*validate*/true);
110110

111111
state.session.abort_if_errors();
112112
} else {

src/bin/miri.rs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ use std::path::PathBuf;
2525

2626
struct MiriCompilerCalls {
2727
default: Box<RustcDefaultCalls>,
28-
/// Whether to begin interpretation at the start_fn lang item or not
28+
29+
/// Whether to begin interpretation at the start_fn lang item or not.
2930
///
30-
/// If false, the interpretation begins at the `main` function
31+
/// If false, the interpretation begins at the `main` function.
3132
start_fn: bool,
33+
34+
/// Whether to enforce the validity invariant.
35+
validate: bool,
3236
}
3337

3438
impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
@@ -87,7 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
8791
let mut control = this.default.build_controller(sess, matches);
8892
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
8993
let start_fn = this.start_fn;
90-
control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
94+
let validate = this.validate;
95+
control.after_analysis.callback =
96+
Box::new(move |state| after_analysis(state, start_fn, validate));
9197
control.after_analysis.stop = Compilation::Stop;
9298
control
9399
}
@@ -101,38 +107,43 @@ fn after_hir_lowering(state: &mut CompileState) {
101107
state.session.plugin_attributes.borrow_mut().push(attr);
102108
}
103109

104-
fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) {
110+
fn after_analysis<'a, 'tcx>(
111+
state: &mut CompileState<'a, 'tcx>,
112+
use_start_fn: bool,
113+
validate: bool,
114+
) {
105115
state.session.abort_if_errors();
106116

107117
let tcx = state.tcx.unwrap();
108118

109119
if std::env::args().any(|arg| arg == "--test") {
110-
struct Visitor<'a, 'tcx: 'a>(
111-
TyCtxt<'a, 'tcx, 'tcx>,
112-
&'a CompileState<'a, 'tcx>
113-
);
120+
struct Visitor<'a, 'tcx: 'a> {
121+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
122+
state: &'a CompileState<'a, 'tcx>,
123+
validate: bool,
124+
};
114125
impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
115126
fn visit_item(&mut self, i: &'hir hir::Item) {
116127
if let hir::ItemKind::Fn(.., body_id) = i.node {
117128
if i.attrs.iter().any(|attr| {
118129
attr.name() == "test"
119130
})
120131
{
121-
let did = self.0.hir.body_owner_def_id(body_id);
132+
let did = self.tcx.hir.body_owner_def_id(body_id);
122133
println!(
123134
"running test: {}",
124-
self.0.def_path_debug_str(did),
135+
self.tcx.def_path_debug_str(did),
125136
);
126-
miri::eval_main(self.0, did, None);
127-
self.1.session.abort_if_errors();
137+
miri::eval_main(self.tcx, did, None, self.validate);
138+
self.state.session.abort_if_errors();
128139
}
129140
}
130141
}
131142
fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
132143
fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
133144
}
134145
state.hir_crate.unwrap().visit_all_item_likes(
135-
&mut Visitor(tcx, state),
146+
&mut Visitor { tcx, state, validate }
136147
);
137148
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
138149
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
@@ -142,7 +153,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo
142153
} else {
143154
None
144155
};
145-
miri::eval_main(tcx, entry_def_id, start_wrapper);
156+
miri::eval_main(tcx, entry_def_id, start_wrapper, validate);
146157

147158
state.session.abort_if_errors();
148159
} else {
@@ -221,12 +232,18 @@ fn main() {
221232
}
222233

223234
let mut start_fn = false;
235+
let mut validate = true;
224236
args.retain(|arg| {
225-
if arg == "-Zmiri-start-fn" {
226-
start_fn = true;
227-
false
228-
} else {
229-
true
237+
match arg.as_str() {
238+
"-Zmiri-start-fn" => {
239+
start_fn = true;
240+
false
241+
},
242+
"-Zmiri-disable-validation" => {
243+
validate = false;
244+
false
245+
},
246+
_ => true
230247
}
231248
});
232249

@@ -235,6 +252,7 @@ fn main() {
235252
rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
236253
default: Box::new(RustcDefaultCalls),
237254
start_fn,
255+
validate,
238256
}), None, None)
239257
});
240258
std::process::exit(result as i32);

src/fn_call.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, '
252252
// Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors,
253253
// and of course eval_main.
254254
let mir = self.load_mir(f_instance.def)?;
255-
let closure_dest = Place::null(&self);
255+
let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into();
256256
self.push_stack_frame(
257257
f_instance,
258258
mir.span,
259259
mir,
260-
closure_dest,
260+
Some(ret_place),
261261
StackPopCleanup::Goto(Some(ret)), // directly return to caller
262262
)?;
263263
let mut args = self.frame().mir.args_iter();

src/intrinsic.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
238238
"init" => {
239239
// Check fast path: we don't want to force an allocation in case the destination is a simple value,
240240
// but we also do not want to create a new allocation with 0s and then copy that over.
241-
if !dest.layout.is_zst() { // notzhing to do for ZST
241+
// FIXME: We do not properly validate in case of ZSTs and when doing it in memory!
242+
// However, this only affects direct calls of the intrinsic; calls to the stable
243+
// functions wrapping them do get their validation.
244+
if !dest.layout.is_zst() { // nothing to do for ZST
242245
match dest.layout.abi {
243246
layout::Abi::Scalar(ref s) => {
244247
let x = Scalar::from_int(0, s.value.size(&self));
@@ -338,7 +341,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
338341

339342
"size_of_val" => {
340343
let mplace = self.ref_to_mplace(self.read_value(args[0])?)?;
341-
let (size, _) = self.size_and_align_of_mplace(mplace)?;
344+
let (size, _) = self.size_and_align_of_mplace(mplace)?
345+
.expect("size_of_val called on extern type");
342346
let ptr_size = self.pointer_size();
343347
self.write_scalar(
344348
Scalar::from_uint(size.bytes() as u128, ptr_size),
@@ -349,7 +353,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
349353
"min_align_of_val" |
350354
"align_of_val" => {
351355
let mplace = self.ref_to_mplace(self.read_value(args[0])?)?;
352-
let (_, align) = self.size_and_align_of_mplace(mplace)?;
356+
let (_, align) = self.size_and_align_of_mplace(mplace)?
357+
.expect("size_of_val called on extern type");
353358
let ptr_size = self.pointer_size();
354359
self.write_scalar(
355360
Scalar::from_uint(align.abi(), ptr_size),
@@ -397,6 +402,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
397402
"uninit" => {
398403
// Check fast path: we don't want to force an allocation in case the destination is a simple value,
399404
// but we also do not want to create a new allocation with 0s and then copy that over.
405+
// FIXME: We do not properly validate in case of ZSTs and when doing it in memory!
406+
// However, this only affects direct calls of the intrinsic; calls to the stable
407+
// functions wrapping them do get their validation.
400408
if !dest.layout.is_zst() { // nothing to do for ZST
401409
match dest.layout.abi {
402410
layout::Abi::Scalar(..) => {

src/lib.rs

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
5050
tcx: TyCtxt<'a, 'tcx, 'tcx>,
5151
main_id: DefId,
5252
start_wrapper: Option<DefId>,
53+
validate: bool,
5354
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
5455
let mut ecx = EvalContext::new(
5556
tcx.at(syntax::source_map::DUMMY_SP),
5657
ty::ParamEnv::reveal_all(),
57-
Default::default(),
58+
Evaluator::new(validate),
5859
Default::default(),
5960
);
6061

@@ -67,7 +68,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
6768
.to_owned(),
6869
));
6970
}
70-
let ptr_size = ecx.memory.pointer_size();
7171

7272
if let Some(start_id) = start_wrapper {
7373
let main_ret_ty = ecx.tcx.fn_sig(main_id).output();
@@ -89,16 +89,15 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
8989
}
9090

9191
// Return value (in static memory so that it does not count as leak)
92-
let size = ecx.tcx.data_layout.pointer_size;
93-
let align = ecx.tcx.data_layout.pointer_align;
94-
let ret_ptr = ecx.memory_mut().allocate(size, align, MiriMemoryKind::MutStatic.into())?;
92+
let ret = ecx.layout_of(start_mir.return_ty())?;
93+
let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?;
9594

9695
// Push our stack frame
9796
ecx.push_stack_frame(
9897
start_instance,
9998
start_mir.span,
10099
start_mir,
101-
Place::from_ptr(ret_ptr, align),
100+
Some(ret_ptr.into()),
102101
StackPopCleanup::None { cleanup: true },
103102
)?;
104103

@@ -126,11 +125,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
126125

127126
assert!(args.next().is_none(), "start lang item has more arguments than expected");
128127
} else {
128+
let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into();
129129
ecx.push_stack_frame(
130130
main_instance,
131131
main_mir.span,
132132
main_mir,
133-
Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()),
133+
Some(ret_place),
134134
StackPopCleanup::None { cleanup: true },
135135
)?;
136136

@@ -146,8 +146,9 @@ pub fn eval_main<'a, 'tcx: 'a>(
146146
tcx: TyCtxt<'a, 'tcx, 'tcx>,
147147
main_id: DefId,
148148
start_wrapper: Option<DefId>,
149+
validate: bool,
149150
) {
150-
let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx");
151+
let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx");
151152

152153
let res: EvalResult = (|| {
153154
ecx.run()?;
@@ -222,14 +223,27 @@ impl Into<MemoryKind<MiriMemoryKind>> for MiriMemoryKind {
222223
}
223224

224225

225-
#[derive(Clone, Default, PartialEq, Eq)]
226+
#[derive(Clone, PartialEq, Eq)]
226227
pub struct Evaluator<'tcx> {
227228
/// Environment variables set by `setenv`
228229
/// Miri does not expose env vars from the host to the emulated program
229230
pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,
230231

231232
/// TLS state
232233
pub(crate) tls: TlsData<'tcx>,
234+
235+
/// Whether to enforce the validity invariant
236+
pub(crate) validate: bool,
237+
}
238+
239+
impl<'tcx> Evaluator<'tcx> {
240+
fn new(validate: bool) -> Self {
241+
Evaluator {
242+
env_vars: HashMap::default(),
243+
tls: TlsData::default(),
244+
validate,
245+
}
246+
}
233247
}
234248

235249
impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
@@ -240,7 +254,29 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
240254
type MemoryMap = MonoHashMap<AllocId, (MemoryKind<MiriMemoryKind>, Allocation<()>)>;
241255

242256
const STATIC_KIND: Option<MiriMemoryKind> = Some(MiriMemoryKind::MutStatic);
243-
const ENFORCE_VALIDITY: bool = false; // this is still WIP
257+
258+
fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
259+
if !ecx.machine.validate {
260+
return false;
261+
}
262+
263+
// Some functions are whitelisted until we figure out how to fix them.
264+
// We walk up the stack a few frames to also cover their callees.
265+
const WHITELIST: &[&str] = &[
266+
// Uses mem::uninitialized
267+
"std::ptr::read",
268+
"std::sys::windows::mutex::Mutex::",
269+
];
270+
for frame in ecx.stack().iter()
271+
.rev().take(3)
272+
{
273+
let name = frame.instance.to_string();
274+
if WHITELIST.iter().any(|white| name.starts_with(white)) {
275+
return false;
276+
}
277+
}
278+
true
279+
}
244280

245281
/// Returns Ok() when the function was handled, fail otherwise
246282
fn find_fn(
@@ -286,7 +322,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
286322
malloc,
287323
malloc_mir.span,
288324
malloc_mir,
289-
*dest,
325+
Some(dest),
290326
// Don't do anything when we are done. The statement() function will increment
291327
// the old stack frame's stmt counter to the next statement, which means that when
292328
// exchange_malloc returns, we go on evaluating exactly where we want to be.

src/tls.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use std::collections::BTreeMap;
22

3+
use rustc_target::abi::LayoutOf;
34
use rustc::{ty, ty::layout::HasDataLayout, mir};
45

5-
use super::{EvalResult, EvalErrorKind, Scalar, Evaluator,
6-
Place, StackPopCleanup, EvalContext};
6+
use super::{
7+
EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator,
8+
MPlaceTy, Scalar,
9+
};
710

811
pub type TlsKey = u128;
912

@@ -139,12 +142,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, '
139142
// TODO: Potentially, this has to support all the other possible instances?
140143
// See eval_fn_call in interpret/terminator/mod.rs
141144
let mir = self.load_mir(instance.def)?;
142-
let ret = Place::null(&self);
145+
let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into();
143146
self.push_stack_frame(
144147
instance,
145148
mir.span,
146149
mir,
147-
ret,
150+
Some(ret_place),
148151
StackPopCleanup::None { cleanup: true },
149152
)?;
150153
let arg_local = self.frame().mir.args_iter().next().ok_or_else(

tests/compile-fail/cast_box_int_to_fn_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Validation makes this fail in the wrong place
2-
// compile-flags: -Zmir-emit-validate=0
2+
// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation
33

44
fn main() {
55
let b = Box::new(42);

tests/compile-fail/cast_int_to_fn_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Validation makes this fail in the wrong place
2-
// compile-flags: -Zmir-emit-validate=0
2+
// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation
33

44
fn main() {
55
let g = unsafe {

tests/compile-fail/execute_memory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Validation makes this fail in the wrong place
2-
// compile-flags: -Zmir-emit-validate=0
2+
// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation
33

44
#![feature(box_syntax)]
55

tests/compile-fail/fn_ptr_offset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Validation makes this fail in the wrong place
2-
// compile-flags: -Zmir-emit-validate=0
2+
// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation
33

44
use std::mem;
55

0 commit comments

Comments
 (0)