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