mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 11:53:44 +00:00
implement passing arguments to the interpreted program
This commit is contained in:
parent
df659d9ae6
commit
0802b3a108
@ -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 {
|
||||
@ -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(
|
||||
@ -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
|
||||
}
|
||||
@ -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();
|
||||
@ -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();
|
||||
}
|
||||
@ -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);
|
||||
|
46
src/lib.rs
46
src/lib.rs
@ -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);
|
||||
@ -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
|
||||
{
|
||||
@ -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(
|
||||
@ -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 = (|| {
|
||||
|
@ -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)]
|
||||
|
@ -1 +1 @@
|
||||
standard error
|
||||
main
|
||||
|
5
tests/run-pass/args.rs
Normal file
5
tests/run-pass/args.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
for arg in std::env::args() {
|
||||
println!("{}", arg);
|
||||
}
|
||||
}
|
1
tests/run-pass/args.stdout
Normal file
1
tests/run-pass/args.stdout
Normal file
@ -0,0 +1 @@
|
||||
args
|
Loading…
Reference in New Issue
Block a user