Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable env communication #894

Merged
merged 12 commits into from
Aug 14, 2019
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ Several `-Z` flags are relevant for Miri:
is enforced by default. This is mostly useful for debugging; it means Miri
will miss bugs in your program. However, this can also help to make Miri run
faster.
* `-Zmiri-enable-communication` enables communication between the host
environment and Miri, i.e., all the host environment variables are available
during Miri runtime.
* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri
overrides the default to be `0`; be advised that using any higher level can
make Miri miss bugs in your program because they got optimized away.
Expand Down
7 changes: 6 additions & 1 deletion benches/helpers/miri_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> {
);

self.bencher.iter(|| {
let config = miri::MiriConfig { validate: true, args: vec![], seed: None };
let config = miri::MiriConfig {
validate: true,
communicate: false,
args: vec![],
seed: None,
};
eval_main(tcx, entry_def_id, config);
});
});
Expand Down
15 changes: 13 additions & 2 deletions src/bin/miri-rustc-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
fn visit_item(&mut self, i: &'hir hir::Item) {
if let hir::ItemKind::Fn(.., body_id) = i.node {
if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) {
let config = MiriConfig { validate: true, args: vec![], seed: None };
let config = MiriConfig {
validate: true,
communicate: false,
args: vec![],
seed: None,
};
let did = self.0.hir().body_owner_def_id(body_id);
println!("running test: {}", self.0.def_path_debug_str(did));
miri::eval_main(self.0, did, config);
Expand All @@ -61,7 +66,13 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
}
tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
} else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
let config = MiriConfig { validate: true, args: vec![], seed: None };

pvdrz marked this conversation as resolved.
Show resolved Hide resolved
let config = MiriConfig {
validate: true,
communicate: false,
args: vec![],
seed: None
};
miri::eval_main(tcx, entry_def_id, config);

compiler.session().abort_if_errors();
Expand Down
6 changes: 5 additions & 1 deletion src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ fn main() {

// Parse our arguments and split them across `rustc` and `miri`.
let mut validate = true;
let mut communicate = false;
let mut seed: Option<u64> = None;
let mut rustc_args = vec![];
let mut miri_args = vec![];
Expand All @@ -147,6 +148,9 @@ fn main() {
"-Zmiri-disable-validation" => {
validate = false;
},
"-Zmiri-enable-communication" => {
communicate = true;
},
"--" => {
after_dashdash = true;
}
Expand Down Expand Up @@ -196,7 +200,7 @@ fn main() {

debug!("rustc arguments: {:?}", rustc_args);
debug!("miri arguments: {:?}", miri_args);
let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
let miri_config = miri::MiriConfig { validate, communicate, args: miri_args, seed };
let result = rustc_driver::report_ices_to_stderr_if_any(move || {
rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
}).and_then(|result| result);
Expand Down
18 changes: 14 additions & 4 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,18 @@ use crate::{
Scalar, Tag, Pointer, FnVal,
MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt,
};
use crate::shims::env::alloc_env_value;

/// Configuration needed to spawn a Miri instance.
#[derive(Clone)]
pub struct MiriConfig {
pub validate: bool,
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
/// Determines if communication with the host environment is enabled.
pub communicate: bool,
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
pub args: Vec<String>,

pvdrz marked this conversation as resolved.
Show resolved Hide resolved
// The seed to use when non-determinism is required (e.g. getrandom())
pub seed: Option<u64>
/// The seed to use when non-determinism is required (e.g. getrandom())
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
pub seed: Option<u64>,
}

// Used by priroda.
Expand All @@ -33,7 +36,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
let mut ecx = InterpCx::new(
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
Evaluator::new(),
Evaluator::new(config.communicate),
MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate),
);

Expand Down Expand Up @@ -158,9 +161,16 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
cur_ptr = cur_ptr.offset(char_size, tcx)?;
}
}

assert!(args.next().is_none(), "start lang item has more arguments than expected");

if config.communicate {
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
for (name, value) in std::env::vars() {
let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), &tcx);
ecx.machine.env_vars.insert(name.into_bytes(), value);
}
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
}
pvdrz marked this conversation as resolved.
Show resolved Hide resolved

Ok(ecx)
}

Expand Down
6 changes: 5 additions & 1 deletion src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,21 @@ pub struct Evaluator<'tcx> {

/// TLS state.
pub(crate) tls: TlsData<'tcx>,

/// If enabled, the `env_vars` field is populated with the host env vars during initialization.
pub(crate) communicate: bool,
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
}

impl<'tcx> Evaluator<'tcx> {
pub(crate) fn new() -> Self {
pub(crate) fn new(communicate: bool) -> Self {
Evaluator {
env_vars: HashMap::default(),
argc: None,
argv: None,
cmd_line: None,
last_error: 0,
tls: TlsData::default(),
communicate,
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/shims/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use rustc::ty::{layout::{Size, Align}, TyCtxt};
use rustc_mir::interpret::Memory;

use crate::*;

pvdrz marked this conversation as resolved.
Show resolved Hide resolved
pub(crate) fn alloc_env_value<'mir, 'tcx>(bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>) -> Pointer<Tag> {
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
let length = bytes.len() as u64;
// `+1` for the null terminator.
let ptr = memory.allocate(
Size::from_bytes(length + 1),
Align::from_bytes(1).unwrap(),
MiriMemoryKind::Env.into(),
);
// We just allocated these, so the write cannot fail.
let alloc = memory.get_mut(ptr.alloc_id).unwrap();
alloc.write_bytes(tcx, ptr, &bytes).unwrap();
let trailing_zero_ptr = ptr.offset(
Size::from_bytes(length),
tcx,
).unwrap();
alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap();
ptr
}
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
23 changes: 3 additions & 20 deletions src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use syntax::attr;
use syntax::symbol::sym;

use crate::*;
use crate::shims::env::alloc_env_value;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
Expand Down Expand Up @@ -465,26 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
}
if let Some((name, value)) = new {
// `+1` for the null terminator.
let value_copy = this.memory_mut().allocate(
Size::from_bytes((value.len() + 1) as u64),
Align::from_bytes(1).unwrap(),
MiriMemoryKind::Env.into(),
);
// We just allocated these, so the write cannot fail.
let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap();
alloc.write_bytes(tcx, value_copy, &value).unwrap();
let trailing_zero_ptr = value_copy.offset(
Size::from_bytes(value.len() as u64),
tcx,
).unwrap();
alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap();

if let Some(var) = this.machine.env_vars.insert(
name.to_owned(),
value_copy,
)
{
let value_copy = alloc_env_value(&value, this.memory_mut(), tcx);
if let Some(var) = this.machine.env_vars.insert(name.to_owned(), value_copy) {
this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
}
this.write_null(dest)?;
Expand Down
1 change: 1 addition & 0 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
pub mod dlsym;
pub mod env;

use rustc::{ty, mir};

Expand Down
6 changes: 6 additions & 0 deletions tests/run-pass/communication.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// ignore-windows: TODO env var emulation stubbed out on Windows
// compile-flags: -Zmiri-enable-communication

fn main() {
assert!(std::env::var("PWD").is_ok());
pvdrz marked this conversation as resolved.
Show resolved Hide resolved
}