Skip to content

Commit

Permalink
implement passing arguments to the interpreted program
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Feb 8, 2019
1 parent 77d12bb commit 0d97e27
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 40 deletions.
67 changes: 43 additions & 24 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc::hir::def_id::LOCAL_CRATE;
use syntax::ast;

use miri::MiriConfig;

struct MiriCompilerCalls {
default: Box<RustcDefaultCalls>,

/// Whether to enforce the validity invariant.
validate: bool,
miri_config: MiriConfig,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
Expand Down Expand Up @@ -79,6 +79,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
) -> Compilation {
// Called *before* build_controller. Add filename to miri arguments.
self.miri_config.args.insert(0, input.filestem().to_string());
self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
}
fn build_controller(
Expand All @@ -89,9 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
let this = *self;
let mut control = this.default.build_controller(sess, matches);
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
let validate = this.validate;
let miri_config = this.miri_config;
control.after_analysis.callback =
Box::new(move |state| after_analysis(state, validate));
Box::new(move |state| after_analysis(state, miri_config.clone()));
control.after_analysis.stop = Compilation::Stop;
control
}
Expand All @@ -107,7 +109,7 @@ fn after_hir_lowering(state: &mut CompileState) {

fn after_analysis<'a, 'tcx>(
state: &mut CompileState<'a, 'tcx>,
validate: bool,
miri_config: MiriConfig,
) {
init_late_loggers();
state.session.abort_if_errors();
Expand All @@ -117,7 +119,7 @@ fn after_analysis<'a, 'tcx>(

let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");

miri::eval_main(tcx, entry_def_id, validate);
miri::eval_main(tcx, entry_def_id, miri_config);

state.session.abort_if_errors();
}
Expand Down Expand Up @@ -188,34 +190,51 @@ fn find_sysroot() -> String {

fn main() {
init_early_loggers();
let mut args: Vec<String> = std::env::args().collect();

// Parse our own -Z flags and remove them before rustc gets their hand on them.
// Parse our arguments and split them across rustc and miri
let mut validate = true;
args.retain(|arg| {
match arg.as_str() {
"-Zmiri-disable-validation" => {
validate = false;
false
},
_ => true
let mut rustc_args = vec![];
let mut miri_args = vec![];
let mut after_dashdash = false;
for arg in std::env::args() {
if rustc_args.is_empty() {
// Very first arg: for rustc
rustc_args.push(arg);
}
});
else if after_dashdash {
// Everything that comes is Miri args
miri_args.push(arg);
} else {
match arg.as_str() {
"-Zmiri-disable-validation" => {
validate = false;
},
"--" => {
after_dashdash = true;
}
_ => {
rustc_args.push(arg);
}
}
}
}

// Determine sysroot and let rustc know about it
let sysroot_flag = String::from("--sysroot");
if !args.contains(&sysroot_flag) {
args.push(sysroot_flag);
args.push(find_sysroot());
if !rustc_args.contains(&sysroot_flag) {
rustc_args.push(sysroot_flag);
rustc_args.push(find_sysroot());
}
// Finally, add the default flags all the way in the beginning, but after the binary name.
args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));
rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

trace!("rustc arguments: {:?}", args);
debug!("rustc arguments: {:?}", rustc_args);
debug!("miri arguments: {:?}", miri_args);
let miri_config = MiriConfig { validate, args: miri_args };
let result = rustc_driver::run(move || {
rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls {
default: Box::new(RustcDefaultCalls),
validate,
miri_config,
}), None, None)
});
std::process::exit(result as i32);
Expand Down
46 changes: 32 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,23 @@ pub fn miri_default_args() -> &'static [&'static str] {
&["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"]
}

/// Configuration needed to spawn a Miri instance
#[derive(Clone)]
pub struct MiriConfig {
pub validate: bool,
pub args: Vec<String>,
}

// Used by priroda
pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
main_id: DefId,
validate: bool,
config: MiriConfig,
) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> {
let mut ecx = EvalContext::new(
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(validate),
Evaluator::new(config.validate),
);

let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
Expand Down Expand Up @@ -120,7 +127,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(

// Second argument (argc): 1
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let argc = Scalar::from_int(1, dest.layout.size);
let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size);
ecx.write_scalar(argc, dest)?;
// Store argc for macOS _NSGetArgc
{
Expand All @@ -130,24 +137,35 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
}

// FIXME: extract main source file path
// Third argument (argv): &[b"foo"]
const CMD: &str = "running-in-miri\0";
// Third argument (argv): Created from config.args
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag();
let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?;
let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into());
ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?;
ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?;
// Collect the pointers to the individual strings.
let mut argvs = Vec::<Pointer<Borrow>>::new();
for arg in config.args {
let mut arg = arg.into_bytes();
arg.push(0);
argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag());
}
// Make an array with all these pointers, in the Miri memory.
let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?;
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into());
for (idx, arg) in argvs.into_iter().enumerate() {
let place = ecx.mplace_field(argvs_place, idx as u64)?;
ecx.write_scalar(Scalar::Ptr(arg), place.into())?;
}
ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?;
// Write a pointe to that place as the argument.
let argv = argvs_place.ptr;
ecx.write_scalar(argv, dest)?;
// Store argv for macOS _NSGetArgv
{
let argv = cmd_place.ptr;
ecx.write_scalar(argv, dest)?;
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into());
ecx.write_scalar(argv, argv_place.into())?;
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
}
// Store cmdline as UTF-16 for Windows GetCommandLineW
{
const CMD: &str = "running-in-miri\0";
let tcx = &{ecx.tcx.tcx};
let cmd_utf16: Vec<u16> = CMD.encode_utf16().collect();
let cmd_ptr = ecx.memory_mut().allocate(
Expand Down Expand Up @@ -179,9 +197,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
pub fn eval_main<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
main_id: DefId,
validate: bool,
config: MiriConfig,
) {
let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx");
let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx");

// Run! The main execution.
let res: EvalResult = (|| {
Expand Down
4 changes: 3 additions & 1 deletion test-cargo-miri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ fn main() {
let n = <BigEndian as ByteOrder>::read_u32(buf);
assert_eq!(n, 0x01020304);
println!("{:#010x}", n);
eprintln!("standard error");
for arg in std::env::args() {
eprintln!("{}", arg);
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion test-cargo-miri/stderr.ref
Original file line number Diff line number Diff line change
@@ -1 +1 @@
standard error
main
5 changes: 5 additions & 0 deletions tests/run-pass/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
for arg in std::env::args() {
println!("{}", arg);
}
}
1 change: 1 addition & 0 deletions tests/run-pass/args.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
args

0 comments on commit 0d97e27

Please sign in to comment.