diff --git a/README.md b/README.md index f073cde7764e..3c5af59d3f07 100644 --- a/README.md +++ b/README.md @@ -236,10 +236,13 @@ environment variable: execution with a "permission denied" error being returned to the program. `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. -* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host so that it cannot be accessed by the program. Can be used multiple - times to exclude several variables. On Windows, the `TERM` environment - variable is excluded by default. +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it + cannot be accessed by the program. Can be used multiple times to exclude several variables. On + Windows, the `TERM` environment variable is excluded by default. This has no effect unless + `-Zmiri-disable-validation` is also set. +* `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can + be used multiple times to forward several variables. This has no effect if + `-Zmiri-disable-validation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 333ff6af889f..dd7b0b54f488 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -399,6 +399,11 @@ fn main() { .excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } + arg if arg.starts_with("-Zmiri-env-forward=") => { + miri_config + .forwarded_env_vars + .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); + } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { diff --git a/src/eval.rs b/src/eval.rs index e2e85e3e7572..97856d92020b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -86,6 +86,8 @@ pub struct MiriConfig { pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, + /// Environment variables that should always be forwarded from the host. + pub forwarded_env_vars: Vec, /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). @@ -122,6 +124,7 @@ impl Default for MiriConfig { isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, excluded_env_vars: vec![], + forwarded_env_vars: vec![], args: vec![], seed: None, tracked_pointer_tag: None, @@ -157,7 +160,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(&config), ); // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars)?; + EnvVars::init(&mut ecx, config.excluded_env_vars, config.forwarded_env_vars)?; MemoryExtra::init_extern_statics(&mut ecx)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. diff --git a/src/shims/env.rs b/src/shims/env.rs index 4d297fd935d5..dfd1ef207d96 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -39,6 +39,7 @@ impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, + forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_str(); if target_os == "windows" { @@ -47,9 +48,14 @@ impl<'tcx> EnvVars<'tcx> { excluded_env_vars.push("TERM".to_owned()); } - if ecx.machine.communicate() { - for (name, value) in env::vars() { - if !excluded_env_vars.contains(&name) { + // Skip the loop entirely if we don't want to forward anything. + if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { + for (name, value) in env::vars_os() { + let forward = match ecx.machine.communicate() { + true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), + false => forwarded_env_vars.iter().any(|v| v.as_str() == &name), + }; + if forward { let var_ptr = match target_os { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, diff --git a/tests/run-pass/env-forward.rs b/tests/run-pass/env-forward.rs new file mode 100644 index 000000000000..8eebc45f55a7 --- /dev/null +++ b/tests/run-pass/env-forward.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST + +fn main() { + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); +}