Skip to content

Commit 98f3480

Browse files
committed
Auto merge of #3493 - eduardosm:env-set, r=oli-obk
Add `-Zmiri-env-set` to set environment variables without modifying the host environment This option allows to pass environment variables to the interpreted program without needing to modify the host environment (which may have undesired effects in some cases).
2 parents bafa392 + 506ffc9 commit 98f3480

File tree

5 files changed

+43
-12
lines changed

5 files changed

+43
-12
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ environment variable. We first document the most relevant and most commonly used
321321
* `-Zmiri-env-forward=<var>` forwards the `var` environment variable to the interpreted program. Can
322322
be used multiple times to forward several variables. Execution will still be deterministic if the
323323
value of forwarded variables stays the same. Has no effect if `-Zmiri-disable-isolation` is set.
324+
* `-Zmiri-env-set=<var>=<value>` sets the `var` environment variable to `value` in the interpreted program.
325+
It can be used to pass environment variables without needing to alter the host environment. It can
326+
be used multiple times to set several variables. If `-Zmiri-disable-isolation` or `-Zmiri-env-forward`
327+
is set, values set with this option will have priority over values from the host environment.
324328
* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some
325329
remaining threads to exist when the main thread exits.
326330
* `-Zmiri-isolation-error=<action>` configures Miri's response to operations

src/bin/miri.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,11 @@ fn main() {
506506
);
507507
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") {
508508
miri_config.forwarded_env_vars.push(param.to_owned());
509+
} else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") {
510+
let Some((name, value)) = param.split_once('=') else {
511+
show_error!("-Zmiri-env-set requires an argument of the form <name>=<value>");
512+
};
513+
miri_config.set_env_vars.insert(name.to_owned(), value.to_owned());
509514
} else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") {
510515
let ids: Vec<u64> = parse_comma_list(param).unwrap_or_else(|err| {
511516
show_error!("-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {err}")

src/eval.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::thread;
99

1010
use crate::concurrency::thread::TlsAllocAction;
1111
use crate::diagnostics::report_leaks;
12-
use rustc_data_structures::fx::FxHashSet;
12+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1313
use rustc_hir::def::Namespace;
1414
use rustc_hir::def_id::DefId;
1515
use rustc_middle::ty::{
@@ -100,6 +100,8 @@ pub struct MiriConfig {
100100
pub ignore_leaks: bool,
101101
/// Environment variables that should always be forwarded from the host.
102102
pub forwarded_env_vars: Vec<String>,
103+
/// Additional environment variables that should be set in the interpreted program.
104+
pub set_env_vars: FxHashMap<String, String>,
103105
/// Command-line arguments passed to the interpreted program.
104106
pub args: Vec<String>,
105107
/// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`).
@@ -167,6 +169,7 @@ impl Default for MiriConfig {
167169
isolated_op: IsolatedOp::Reject(RejectOpWith::Abort),
168170
ignore_leaks: false,
169171
forwarded_env_vars: vec![],
172+
set_env_vars: FxHashMap::default(),
170173
args: vec![],
171174
seed: None,
172175
tracked_pointer_tags: FxHashSet::default(),

src/shims/env.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,15 @@ impl<'tcx> EnvVars<'tcx> {
4444
let forward = ecx.machine.communicate()
4545
|| config.forwarded_env_vars.iter().any(|v| **v == *name);
4646
if forward {
47-
let var_ptr = match ecx.tcx.sess.target.os.as_ref() {
48-
_ if ecx.target_os_is_unix() =>
49-
alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?,
50-
"windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?,
51-
unsupported =>
52-
throw_unsup_format!(
53-
"environment support for target OS `{}` not yet available",
54-
unsupported
55-
),
56-
};
57-
ecx.machine.env_vars.map.insert(name.clone(), var_ptr);
47+
add_env_var(ecx, name, value)?;
5848
}
5949
}
6050
}
6151

52+
for (name, value) in &config.set_env_vars {
53+
add_env_var(ecx, OsStr::new(name), OsStr::new(value))?;
54+
}
55+
6256
// Initialize the `environ` pointer when needed.
6357
if ecx.target_os_is_unix() {
6458
// This is memory backing an extern static, hence `ExternStatic`, not `Env`.
@@ -89,6 +83,24 @@ impl<'tcx> EnvVars<'tcx> {
8983
}
9084
}
9185

86+
fn add_env_var<'mir, 'tcx>(
87+
ecx: &mut InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
88+
name: &OsStr,
89+
value: &OsStr,
90+
) -> InterpResult<'tcx, ()> {
91+
let var_ptr = match ecx.tcx.sess.target.os.as_ref() {
92+
_ if ecx.target_os_is_unix() => alloc_env_var_as_c_str(name, value, ecx)?,
93+
"windows" => alloc_env_var_as_wide_str(name, value, ecx)?,
94+
unsupported =>
95+
throw_unsup_format!(
96+
"environment support for target OS `{}` not yet available",
97+
unsupported
98+
),
99+
};
100+
ecx.machine.env_vars.map.insert(name.to_os_string(), var_ptr);
101+
Ok(())
102+
}
103+
92104
fn alloc_env_var_as_c_str<'mir, 'tcx>(
93105
name: &OsStr,
94106
value: &OsStr,

tests/pass/shims/env/var-set.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Test a value set on the host (MIRI_ENV_VAR_TEST) and one that is not.
2+
//@compile-flags: -Zmiri-env-set=MIRI_ENV_VAR_TEST=test_value_1 -Zmiri-env-set=TEST_VAR_2=test_value_2
3+
4+
fn main() {
5+
assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("test_value_1".to_owned()));
6+
assert_eq!(std::env::var("TEST_VAR_2"), Ok("test_value_2".to_owned()));
7+
}

0 commit comments

Comments
 (0)