Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 10 additions & 12 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extern crate syntax;
#[macro_use] extern crate log;

use rustc::session::Session;
use rustc_driver::CompilerCalls;
use rustc_driver::{CompilerCalls, Compilation};
use rustc_driver::driver::{CompileState, CompileController};
use syntax::ast::{MetaItemKind, NestedMetaItemKind};

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

let tcx = state.tcx.unwrap();
if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.map.local_def_id(entry_node_id);
let limits = resource_limits_from_attributes(state);
miri::run_mir_passes(tcx);
miri::eval_main(tcx, entry_def_id, limits);

state.session.abort_if_errors();
} else {
println!("no main function found, assuming auxiliary build");
}
let (entry_node_id, _) = state.session.entry_fn.borrow()
.expect("no main or start function found");
let entry_def_id = tcx.map.local_def_id(entry_node_id);
let limits = resource_limits_from_attributes(state);
miri::run_mir_passes(tcx);
miri::eval_main(tcx, entry_def_id, limits);

state.session.abort_if_errors();
}

fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits {
Expand Down Expand Up @@ -135,7 +134,6 @@ fn main() {
args.push(sysroot_flag);
args.push(find_sysroot());
}
args.push("-Zalways-encode-mir".to_owned());

rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None);
}
3 changes: 0 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use syntax::codemap::Span;
pub enum EvalError<'tcx> {
FunctionPointerTyMismatch(Abi, &'tcx FnSig<'tcx>, &'tcx BareFnTy<'tcx>),
NoMirFor(String),
UnterminatedCString(Pointer),
DanglingPointerDeref,
InvalidMemoryAccess,
InvalidFunctionPointer,
Expand Down Expand Up @@ -120,8 +119,6 @@ impl<'tcx> Error for EvalError<'tcx> {
"tried to deallocate frozen memory",
EvalError::Layout(_) =>
"rustc layout computation failed",
EvalError::UnterminatedCString(_) =>
"attempted to get length of a null terminated string, but no null found before end of allocation",
}
}

Expand Down
16 changes: 0 additions & 16 deletions src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,22 +530,6 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
Ok(())
}

pub fn read_c_str(&self, ptr: Pointer) -> EvalResult<'tcx, &[u8]> {
let alloc = self.get(ptr.alloc_id)?;
assert_eq!(ptr.offset as usize as u64, ptr.offset);
let offset = ptr.offset as usize;
match alloc.bytes[offset..].iter().position(|&c| c == 0) {
Some(size) => {
if self.relocations(ptr, (size + 1) as u64)?.count() != 0 {
return Err(EvalError::ReadPointerAsBytes);
}
self.check_defined(ptr, (size + 1) as u64)?;
Ok(&alloc.bytes[offset..offset + size])
},
None => Err(EvalError::UnterminatedCString(ptr)),
}
}

pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> {
self.get_bytes(ptr, size, 1)
}
Expand Down
1 change: 0 additions & 1 deletion src/terminator/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
}

"atomic_load" |
"atomic_load_relaxed" |
"atomic_load_acq" |
"volatile_load" => {
let ty = substs.type_at(0);
Expand Down
55 changes: 10 additions & 45 deletions src/terminator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::TyFnPtr(bare_fn_ty) => {
let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr();
let (def_id, substs, abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
let bare_sig = self.tcx.erase_late_bound_regions_and_normalize(&bare_fn_ty.sig);
let bare_sig = self.tcx.erase_regions(&bare_sig);
// transmuting function pointers in miri is fine as long as the number of
// arguments and the abi don't change.
// FIXME: also check the size of the arguments' type and the return type
// Didn't get it to work, since that triggers an assertion in rustc which
// checks whether the type has escaping regions
if abi != bare_fn_ty.abi ||
sig.variadic != bare_sig.variadic ||
sig.inputs().len() != bare_sig.inputs().len() {
if abi != bare_fn_ty.abi || sig != bare_fn_ty.sig.skip_binder() {
return Err(EvalError::FunctionPointerTyMismatch(abi, sig, bare_fn_ty));
}
self.eval_fn_call(def_id, substs, bare_fn_ty, destination, args,
Expand Down Expand Up @@ -198,15 +189,15 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
use syntax::abi::Abi;
match fn_ty.abi {
Abi::RustIntrinsic => {
let ty = fn_ty.sig.0.output();
let ty = fn_ty.sig.0.output;
let layout = self.type_layout(ty)?;
let (ret, target) = destination.unwrap();
self.call_intrinsic(def_id, substs, arg_operands, ret, ty, layout, target)?;
Ok(())
}

Abi::C => {
let ty = fn_ty.sig.0.output();
let ty = fn_ty.sig.0.output;
let (ret, target) = destination.unwrap();
self.call_c_abi(def_id, arg_operands, ret, ty)?;
self.goto_block(target);
Expand Down Expand Up @@ -329,6 +320,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
.collect();
let args = args_res?;

if link_name.starts_with("pthread_") {
warn!("ignoring C ABI call: {}", link_name);
return Ok(());
}

let usize = self.tcx.types.usize;

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

"memchr" => {
let ptr = args[0].read_ptr(&self.memory)?;
let val = self.value_to_primval(args[1], usize)?.to_u64() as u8;
let num = self.value_to_primval(args[2], usize)?.to_u64();
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
let new_ptr = ptr.offset(idx as u64);
self.write_value(Value::ByVal(PrimVal::from_ptr(new_ptr)), dest, dest_ty)?;
} else {
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
}
}

"getenv" => {
{
let name_ptr = args[0].read_ptr(&self.memory)?;
let name = self.memory.read_c_str(name_ptr)?;
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
}
self.write_value(Value::ByVal(PrimVal::new(0)), dest, dest_ty)?;
}

// unix panic code inside libstd will read the return value of this function
"pthread_rwlock_rdlock" => {
self.write_primval(dest, PrimVal::new(0), dest_ty)?;
}

link_name if link_name.starts_with("pthread_") => {
warn!("ignoring C ABI call: {}", link_name);
return Ok(());
},

_ => {
return Err(EvalError::Unimplemented(format!("can't call C ABI function: {}", link_name)));
}
Expand Down Expand Up @@ -555,7 +520,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let offset = idx * self.memory.pointer_size();
let fn_ptr = self.memory.read_ptr(vtable.offset(offset))?;
let (def_id, substs, _abi, sig) = self.memory.get_fn(fn_ptr.alloc_id)?;
*first_ty = sig.inputs()[0];
*first_ty = sig.inputs[0];
Ok((def_id, substs, Vec::new()))
} else {
Err(EvalError::VtableForArgumentlessMethod)
Expand Down Expand Up @@ -699,7 +664,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// some values don't need to call a drop impl, so the value is null
if drop_fn != Pointer::from_int(0) {
let (def_id, substs, _abi, sig) = self.memory.get_fn(drop_fn.alloc_id)?;
let real_ty = sig.inputs()[0];
let real_ty = sig.inputs[0];
self.drop(Lvalue::from_ptr(ptr), real_ty, drop)?;
drop.push((def_id, Value::ByVal(PrimVal::from_ptr(ptr)), substs));
} else {
Expand Down
70 changes: 58 additions & 12 deletions tests/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@ fn run_pass() {
compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str) {
let mut config = compiletest::default_config();
config.mode = "mir-opt".parse().expect("Invalid mode");
config.src_base = PathBuf::from(path);
config.target = target.to_owned();
config.rustc_path = PathBuf::from("target/debug/miri");
compiletest::run_tests(&config);
}

fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
let target = target.unwrap();
Expand Down Expand Up @@ -66,10 +57,65 @@ fn compile_test() {
};
run_pass();
for_all_targets(&sysroot, |target| {
miri_pass("tests/run-pass", &target);
if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
miri_pass(&path, &target);
let files = std::fs::read_dir("tests/run-pass").unwrap();
let files: Box<Iterator<Item=_>> = if let Ok(path) = std::env::var("MIRI_RUSTC_TEST") {
Box::new(files.chain(std::fs::read_dir(path).unwrap()))
} else {
Box::new(files)
};
let mut mir_not_found = 0;
let mut crate_not_found = 0;
let mut success = 0;
let mut failed = 0;
for file in files {
let file = file.unwrap();
let path = file.path();

if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") {
continue;
}

let stderr = std::io::stderr();
write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap();
let mut cmd = std::process::Command::new("target/debug/miri");
cmd.arg(path);
cmd.arg(format!("--target={}", target));
let libs = Path::new(&sysroot).join("lib");
let sysroot = libs.join("rustlib").join(&target).join("lib");
let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
cmd.env(compiletest::procsrv::dylib_env_var(), paths);

match cmd.output() {
Ok(ref output) if output.status.success() => {
success += 1;
writeln!(stderr.lock(), "ok").unwrap()
},
Ok(output) => {
let output_err = std::str::from_utf8(&output.stderr).unwrap();
if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) {
mir_not_found += 1;
let end = text.find('`').unwrap();
writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap();
} else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) {
crate_not_found += 1;
let end = text.find('`').unwrap();
writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap();
} else {
failed += 1;
writeln!(stderr.lock(), "FAILED with exit code {:?}", output.status.code()).unwrap();
writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap();
}
}
Err(e) => {
writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
panic!("failed to execute miri");
},
}
}
let stderr = std::io::stderr();
writeln!(stderr.lock(), "{} success, {} mir not found, {} crate not found, {} failed", success, mir_not_found, crate_not_found, failed).unwrap();
assert_eq!(failed, 0, "some tests failed");
});
compile_fail(&sysroot);
}
7 changes: 0 additions & 7 deletions tests/run-pass/aux_test.rs

This file was deleted.

1 change: 0 additions & 1 deletion tests/run-pass/auxiliary/dep.rs

This file was deleted.