Skip to content

Commit cbffb3b

Browse files
authored
Merge pull request rust-lang#93 from oli-obk/always_encode_mir
rustup to rustc 1.15.0-dev (ace092f 2016-12-13)
2 parents ee0dc45 + 0a79304 commit cbffb3b

File tree

8 files changed

+97
-78
lines changed

8 files changed

+97
-78
lines changed

Diff for: src/bin/miri.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extern crate syntax;
1010
#[macro_use] extern crate log;
1111

1212
use rustc::session::Session;
13-
use rustc_driver::{CompilerCalls, Compilation};
13+
use rustc_driver::CompilerCalls;
1414
use rustc_driver::driver::{CompileState, CompileController};
1515
use syntax::ast::{MetaItemKind, NestedMetaItemKind};
1616

@@ -21,7 +21,6 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
2121
let mut control = CompileController::basic();
2222
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
2323
control.after_analysis.callback = Box::new(after_analysis);
24-
control.after_analysis.stop = Compilation::Stop;
2524
control
2625
}
2726
}
@@ -35,14 +34,16 @@ fn after_analysis(state: &mut CompileState) {
3534
state.session.abort_if_errors();
3635

3736
let tcx = state.tcx.unwrap();
38-
let (entry_node_id, _) = state.session.entry_fn.borrow()
39-
.expect("no main or start function found");
40-
let entry_def_id = tcx.map.local_def_id(entry_node_id);
41-
let limits = resource_limits_from_attributes(state);
42-
miri::run_mir_passes(tcx);
43-
miri::eval_main(tcx, entry_def_id, limits);
44-
45-
state.session.abort_if_errors();
37+
if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
38+
let entry_def_id = tcx.map.local_def_id(entry_node_id);
39+
let limits = resource_limits_from_attributes(state);
40+
miri::run_mir_passes(tcx);
41+
miri::eval_main(tcx, entry_def_id, limits);
42+
43+
state.session.abort_if_errors();
44+
} else {
45+
println!("no main function found, assuming auxiliary build");
46+
}
4647
}
4748

4849
fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
@@ -134,6 +135,7 @@ fn main() {
134135
args.push(sysroot_flag);
135136
args.push(find_sysroot());
136137
}
138+
args.push("-Zalways-encode-mir".to_owned());
137139

138140
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None);
139141
}

Diff for: src/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use syntax::codemap::Span;
1111
pub enum EvalError<'tcx> {
1212
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
1313
NoMirFor(String),
14+
UnterminatedCString(Pointer),
1415
DanglingPointerDeref,
1516
InvalidMemoryAccess,
1617
InvalidFunctionPointer,
@@ -119,6 +120,8 @@ impl<'tcx> Error for EvalError<'tcx> {
119120
"tried to deallocate frozen memory",
120121
EvalError::Layout(_) =>
121122
"rustc layout computation failed",
123+
EvalError::UnterminatedCString(_) =>
124+
"attempted to get length of a null terminated string, but no null found before end of allocation",
122125
}
123126
}
124127

Diff for: src/memory.rs

+16
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,22 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
530530
Ok(())
531531
}
532532

533+
pub fn read_c_str(&self, ptr: Pointer) -> EvalResult<'tcx, &[u8]> {
534+
let alloc = self.get(ptr.alloc_id)?;
535+
assert_eq!(ptr.offset as usize as u64, ptr.offset);
536+
let offset = ptr.offset as usize;
537+
match alloc.bytes[offset..].iter().position(|&c| c == 0) {
538+
Some(size) => {
539+
if self.relocations(ptr, (size + 1) as u64)?.count() != 0 {
540+
return Err(EvalError::ReadPointerAsBytes);
541+
}
542+
self.check_defined(ptr, (size + 1) as u64)?;
543+
Ok(&alloc.bytes[offset..offset + size])
544+
},
545+
None => Err(EvalError::UnterminatedCString(ptr)),
546+
}
547+
}
548+
533549
pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> {
534550
self.get_bytes(ptr, size, 1)
535551
}

Diff for: src/terminator/intrinsic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
5757
}
5858

5959
"atomic_load" |
60+
"atomic_load_relaxed" |
6061
"atomic_load_acq" |
6162
"volatile_load" => {
6263
let ty = substs.type_at(0);

Diff for: src/terminator/mod.rs

+45-10
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9090
ty::TyFnPtr(bare_fn_ty) => {
9191
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
9292
let (def_id, substs, abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
93-
if abi != bare_fn_ty.abi || sig != bare_fn_ty.sig.skip_binder() {
93+
let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig);
94+
let bare_sig = self.tcx.erase_regions(&bare_sig);
95+
// transmuting function pointers in miri is fine as long as the number of
96+
// arguments and the abi don't change.
97+
// FIXME: also check the size of the arguments' type and the return type
98+
// Didn't get it to work, since that triggers an assertion in rustc which
99+
// checks whether the type has escaping regions
100+
if abi != bare_fn_ty.abi ||
101+
sig.variadic != bare_sig.variadic ||
102+
sig.inputs().len() != bare_sig.inputs().len() {
94103
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty));
95104
}
96105
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
@@ -189,15 +198,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
189198
use syntax::abi::Abi;
190199
match fn_ty.abi {
191200
Abi::RustIntrinsic => {
192-
let ty = fn_ty.sig.0.output;
201+
let ty = fn_ty.sig.0.output();
193202
let layout = self.type_layout(ty)?;
194203
let (ret, target) = destination.unwrap();
195204
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?;
196205
Ok(())
197206
}
198207

199208
Abi::C => {
200-
let ty = fn_ty.sig.0.output;
209+
let ty = fn_ty.sig.0.output();
201210
let (ret, target) = destination.unwrap();
202211
self.call_c_abi(def_id, arg_operands, ret, ty)?;
203212
self.goto_block(target);
@@ -320,11 +329,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
320329
.collect();
321330
let args = args_res?;
322331

323-
if link_name.starts_with("pthread_") {
324-
warn!("ignoring C ABI call: {}", link_name);
325-
return Ok(());
326-
}
327-
328332
let usize = self.tcx.types.usize;
329333

330334
match &link_name[..] {
@@ -371,6 +375,37 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
371375
self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?;
372376
}
373377

378+
"memchr" => {
379+
let ptr = args[0].read_ptr(&self.memory)?;
380+
let val = self.value_to_primval(args[1], usize)?.to_u64() as u8;
381+
let num = self.value_to_primval(args[2], usize)?.to_u64();
382+
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
383+
let new_ptr = ptr.offset(idx as u64);
384+
self.write_value(Value::ByVal(PrimVal::from_ptr(new_ptr)), dest, dest_ty)?;
385+
} else {
386+
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
387+
}
388+
}
389+
390+
"getenv" => {
391+
{
392+
let name_ptr = args[0].read_ptr(&self.memory)?;
393+
let name = self.memory.read_c_str(name_ptr)?;
394+
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
395+
}
396+
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
397+
}
398+
399+
// unix panic code inside libstd will read the return value of this function
400+
"pthread_rwlock_rdlock" => {
401+
self.write_primval(dest, PrimVal::new(0), dest_ty)?;
402+
}
403+
404+
link_name if link_name.starts_with("pthread_") => {
405+
warn!("ignoring C ABI call: {}", link_name);
406+
return Ok(());
407+
},
408+
374409
_ => {
375410
return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
376411
}
@@ -520,7 +555,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
520555
let offset = idx * self.memory.pointer_size();
521556
let fn_ptr = self.memory.read_ptr(vtable.offset(offset))?;
522557
let (def_id, substs, _abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
523-
*first_ty = sig.inputs[0];
558+
*first_ty = sig.inputs()[0];
524559
Ok((def_id, substs, Vec::new()))
525560
} else {
526561
Err(EvalError::VtableForArgumentlessMethod)
@@ -664,7 +699,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
664699
// some values don't need to call a drop impl, so the value is null
665700
if drop_fn != Pointer::from_int(0) {
666701
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?;
667-
let real_ty = sig.inputs[0];
702+
let real_ty = sig.inputs()[0];
668703
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
669704
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs));
670705
} else {

Diff for: tests/compiletest.rs

+12-58
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ fn run_pass() {
2727
compiletest::run_tests(&config);
2828
}
2929

30+
fn miri_pass(path: &str, target: &str) {
31+
let mut config = compiletest::default_config();
32+
config.mode = "mir-opt".parse().expect("Invalid mode");
33+
config.src_base = PathBuf::from(path);
34+
config.target = target.to_owned();
35+
config.rustc_path = PathBuf::from("target/debug/miri");
36+
compiletest::run_tests(&config);
37+
}
38+
3039
fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
3140
for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
3241
let target = target.unwrap();
@@ -57,65 +66,10 @@ fn compile_test() {
5766
};
5867
run_pass();
5968
for_all_targets(&sysroot, |target| {
60-
let files = std::fs::read_dir("tests/run-pass").unwrap();
61-
let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
62-
Box::new(files.chain(std::fs::read_dir(path).unwrap()))
63-
} else {
64-
Box::new(files)
65-
};
66-
let mut mir_not_found = 0;
67-
let mut crate_not_found = 0;
68-
let mut success = 0;
69-
let mut failed = 0;
70-
for file in files {
71-
let file = file.unwrap();
72-
let path = file.path();
73-
74-
if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
75-
continue;
76-
}
77-
78-
let stderr = std::io::stderr();
79-
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
80-
let mut cmd = std::process::Command::new("target/debug/miri");
81-
cmd.arg(path);
82-
cmd.arg(format!("--target={}", target));
83-
let libs = Path::new(&sysroot).join("lib");
84-
let sysroot = libs.join("rustlib").join(&target).join("lib");
85-
let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
86-
cmd.env(compiletest::procsrv::dylib_env_var(), paths);
87-
88-
match cmd.output() {
89-
Ok(ref output) if output.status.success() => {
90-
success += 1;
91-
writeln!(stderr.lock(), "ok").unwrap()
92-
},
93-
Ok(output) => {
94-
let output_err = std::str::from_utf8(&output.stderr).unwrap();
95-
if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
96-
mir_not_found += 1;
97-
let end = text.find('`').unwrap();
98-
writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
99-
} else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
100-
crate_not_found += 1;
101-
let end = text.find('`').unwrap();
102-
writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
103-
} else {
104-
failed += 1;
105-
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
106-
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
107-
writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
108-
}
109-
}
110-
Err(e) => {
111-
writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
112-
panic!("failed to execute miri");
113-
},
114-
}
69+
miri_pass("tests/run-pass", &target);
70+
if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
71+
miri_pass(&path, &target);
11572
}
116-
let stderr = std::io::stderr();
117-
writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap();
118-
assert_eq!(failed, 0, "some tests failed");
11973
});
12074
compile_fail(&sysroot);
12175
}

Diff for: tests/run-pass/aux_test.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// aux-build:dep.rs
2+
3+
extern crate dep;
4+
5+
fn main() {
6+
dep::foo();
7+
}

Diff for: tests/run-pass/auxiliary/dep.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn foo() {}

0 commit comments

Comments
 (0)