miri/shims/
env.rs

1use std::ffi::{OsStr, OsString};
2
3use rustc_data_structures::fx::FxHashMap;
4
5use self::shims::unix::UnixEnvVars;
6use self::shims::windows::WindowsEnvVars;
7use crate::*;
8
9#[derive(Default)]
10pub enum EnvVars<'tcx> {
11    #[default]
12    Uninit,
13    Unix(UnixEnvVars<'tcx>),
14    Windows(WindowsEnvVars),
15}
16
17impl VisitProvenance for EnvVars<'_> {
18    fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
19        match self {
20            EnvVars::Uninit => {}
21            EnvVars::Unix(env) => env.visit_provenance(visit),
22            EnvVars::Windows(env) => env.visit_provenance(visit),
23        }
24    }
25}
26
27impl<'tcx> EnvVars<'tcx> {
28    pub(crate) fn init(
29        ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
30        config: &MiriConfig,
31    ) -> InterpResult<'tcx> {
32        // Initialize the `env_vars` map.
33        // Skip the loop entirely if we don't want to forward anything.
34        let mut env_vars = FxHashMap::default();
35        if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() {
36            for (name, value) in &config.env {
37                let forward = ecx.machine.communicate()
38                    || config.forwarded_env_vars.iter().any(|v| **v == *name);
39                if forward {
40                    env_vars.insert(OsString::from(name), OsString::from(value));
41                }
42            }
43        }
44
45        for (name, value) in &config.set_env_vars {
46            env_vars.insert(OsString::from(name), OsString::from(value));
47        }
48
49        let env_vars = if ecx.target_os_is_unix() {
50            EnvVars::Unix(UnixEnvVars::new(ecx, env_vars)?)
51        } else if ecx.tcx.sess.target.os == "windows" {
52            EnvVars::Windows(WindowsEnvVars::new(ecx, env_vars)?)
53        } else {
54            // Used e.g. for wasi
55            EnvVars::Uninit
56        };
57        ecx.machine.env_vars = env_vars;
58
59        interp_ok(())
60    }
61
62    pub(crate) fn cleanup(ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx> {
63        let this = ecx.eval_context_mut();
64        match this.machine.env_vars {
65            EnvVars::Unix(_) => UnixEnvVars::cleanup(this),
66            EnvVars::Windows(_) => interp_ok(()), // no cleanup needed
67            EnvVars::Uninit => interp_ok(()),
68        }
69    }
70
71    pub(crate) fn unix(&self) -> &UnixEnvVars<'tcx> {
72        match self {
73            EnvVars::Unix(env) => env,
74            _ => unreachable!(),
75        }
76    }
77
78    pub(crate) fn unix_mut(&mut self) -> &mut UnixEnvVars<'tcx> {
79        match self {
80            EnvVars::Unix(env) => env,
81            _ => unreachable!(),
82        }
83    }
84
85    pub(crate) fn windows(&self) -> &WindowsEnvVars {
86        match self {
87            EnvVars::Windows(env) => env,
88            _ => unreachable!(),
89        }
90    }
91
92    pub(crate) fn windows_mut(&mut self) -> &mut WindowsEnvVars {
93        match self {
94            EnvVars::Windows(env) => env,
95            _ => unreachable!(),
96        }
97    }
98}
99
100impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
101pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
102    /// Try to get an environment variable from the interpreted program's environment. This is
103    /// useful for implementing shims which are documented to read from the environment.
104    fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option<OsString>> {
105        let this = self.eval_context_ref();
106        match &this.machine.env_vars {
107            EnvVars::Uninit => interp_ok(None),
108            EnvVars::Unix(vars) => vars.get(this, name),
109            EnvVars::Windows(vars) => vars.get(name),
110        }
111    }
112
113    fn get_pid(&self) -> u32 {
114        let this = self.eval_context_ref();
115        if this.machine.communicate() { std::process::id() } else { 1000 }
116    }
117}