1use std::ffi::{OsStr, OsString};
2
3use rustc_data_structures::fx::FxHashMap;
4use rustc_target::spec::Os;
5
6use self::shims::unix::UnixEnvVars;
7use self::shims::windows::WindowsEnvVars;
8use crate::*;
9
10#[derive(Default)]
11pub enum EnvVars<'tcx> {
12 #[default]
13 Uninit,
14 Unix(UnixEnvVars<'tcx>),
15 Windows(WindowsEnvVars),
16}
17
18impl VisitProvenance for EnvVars<'_> {
19 fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
20 match self {
21 EnvVars::Uninit => {}
22 EnvVars::Unix(env) => env.visit_provenance(visit),
23 EnvVars::Windows(env) => env.visit_provenance(visit),
24 }
25 }
26}
27
28impl<'tcx> EnvVars<'tcx> {
29 pub(crate) fn init(
30 ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
31 config: &MiriConfig,
32 ) -> InterpResult<'tcx> {
33 let mut env_vars = FxHashMap::default();
36 if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() {
37 for (name, value) in &config.env {
38 let forward = ecx.machine.communicate()
39 || config.forwarded_env_vars.iter().any(|v| **v == *name);
40 if forward {
41 env_vars.insert(OsString::from(name), OsString::from(value));
42 }
43 }
44 }
45
46 for (name, value) in &config.set_env_vars {
47 env_vars.insert(OsString::from(name), OsString::from(value));
48 }
49
50 let env_vars = if ecx.target_os_is_unix() {
51 EnvVars::Unix(UnixEnvVars::new(ecx, env_vars)?)
52 } else if ecx.tcx.sess.target.os == Os::Windows {
53 EnvVars::Windows(WindowsEnvVars::new(ecx, env_vars)?)
54 } else {
55 EnvVars::Uninit
57 };
58 ecx.machine.env_vars = env_vars;
59
60 interp_ok(())
61 }
62
63 pub(crate) fn unix(&self) -> &UnixEnvVars<'tcx> {
64 match self {
65 EnvVars::Unix(env) => env,
66 _ => unreachable!(),
67 }
68 }
69
70 pub(crate) fn unix_mut(&mut self) -> &mut UnixEnvVars<'tcx> {
71 match self {
72 EnvVars::Unix(env) => env,
73 _ => unreachable!(),
74 }
75 }
76
77 pub(crate) fn windows(&self) -> &WindowsEnvVars {
78 match self {
79 EnvVars::Windows(env) => env,
80 _ => unreachable!(),
81 }
82 }
83
84 pub(crate) fn windows_mut(&mut self) -> &mut WindowsEnvVars {
85 match self {
86 EnvVars::Windows(env) => env,
87 _ => unreachable!(),
88 }
89 }
90}
91
92impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
93pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
94 fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option<OsString>> {
97 let this = self.eval_context_ref();
98 match &this.machine.env_vars {
99 EnvVars::Uninit => interp_ok(None),
100 EnvVars::Unix(vars) => vars.get(this, name),
101 EnvVars::Windows(vars) => vars.get(name),
102 }
103 }
104
105 fn get_pid(&self) -> u32 {
107 let this = self.eval_context_ref();
108 if this.machine.communicate() { std::process::id() } else { 1000 }
109 }
110
111 fn get_current_tid(&self) -> u32 {
113 let this = self.eval_context_ref();
114 self.get_tid(this.machine.threads.active_thread())
115 }
116
117 fn get_tid(&self, thread: ThreadId) -> u32 {
119 let this = self.eval_context_ref();
120 let index = thread.to_u32();
121 let target_os = &this.tcx.sess.target.os;
122 if matches!(target_os, Os::Linux | Os::NetBsd) {
123 this.get_pid().strict_add(index)
126 } else {
127 index
129 }
130 }
131}