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 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 EnvVars::Uninit
56 };
57 ecx.machine.env_vars = env_vars;
58
59 interp_ok(())
60 }
61
62 pub(crate) fn unix(&self) -> &UnixEnvVars<'tcx> {
63 match self {
64 EnvVars::Unix(env) => env,
65 _ => unreachable!(),
66 }
67 }
68
69 pub(crate) fn unix_mut(&mut self) -> &mut UnixEnvVars<'tcx> {
70 match self {
71 EnvVars::Unix(env) => env,
72 _ => unreachable!(),
73 }
74 }
75
76 pub(crate) fn windows(&self) -> &WindowsEnvVars {
77 match self {
78 EnvVars::Windows(env) => env,
79 _ => unreachable!(),
80 }
81 }
82
83 pub(crate) fn windows_mut(&mut self) -> &mut WindowsEnvVars {
84 match self {
85 EnvVars::Windows(env) => env,
86 _ => unreachable!(),
87 }
88 }
89}
90
91impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
92pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
93 fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option<OsString>> {
96 let this = self.eval_context_ref();
97 match &this.machine.env_vars {
98 EnvVars::Uninit => interp_ok(None),
99 EnvVars::Unix(vars) => vars.get(this, name),
100 EnvVars::Windows(vars) => vars.get(name),
101 }
102 }
103
104 fn get_pid(&self) -> u32 {
106 let this = self.eval_context_ref();
107 if this.machine.communicate() { std::process::id() } else { 1000 }
108 }
109
110 fn get_current_tid(&self) -> u32 {
112 let this = self.eval_context_ref();
113 self.get_tid(this.machine.threads.active_thread())
114 }
115
116 fn get_tid(&self, thread: ThreadId) -> u32 {
118 let this = self.eval_context_ref();
119 let index = thread.to_u32();
120 let target_os = &this.tcx.sess.target.os;
121 if target_os == "linux" || target_os == "netbsd" {
122 this.get_pid().strict_add(index)
125 } else {
126 index
128 }
129 }
130}