Skip to content

Commit 574d81c

Browse files
committed
Auto merge of #1208 - christianpoveda:environ-shim, r=RalfJung
Environ shim Remake of #1147. There are three main problems with this: 1. For some reason `update_environ` is not updating `environ` when `setenv` or `unsetenv` are called. Even then it works during initialization. 2. I am not deallocating the old array with the variables in `update_environ`. 3. I had to store the `environ` place into `MemoryExtra` as a field to update it. I was thinking about changing `extern_statics` to store places instead of `AllocID`s to avoid this. @RalfJung
2 parents e6a0c60 + 8392a0c commit 574d81c

File tree

7 files changed

+123
-11
lines changed

7 files changed

+123
-11
lines changed

src/eval.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
7777
),
7878
);
7979
// Complete initialization.
80+
EnvVars::init(&mut ecx, config.excluded_env_vars)?;
8081
MemoryExtra::init_extern_statics(&mut ecx)?;
81-
EnvVars::init(&mut ecx, config.excluded_env_vars);
8282

8383
// Setup first stack-frame
8484
let main_instance = ty::Instance::mono(tcx, main_id);

src/machine.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub struct AllocExtra {
7070

7171
/// Extra global memory data
7272
#[derive(Clone, Debug)]
73-
pub struct MemoryExtra {
73+
pub struct MemoryExtra<'tcx> {
7474
pub stacked_borrows: Option<stacked_borrows::MemoryExtra>,
7575
pub intptrcast: intptrcast::MemoryExtra,
7676

@@ -84,9 +84,12 @@ pub struct MemoryExtra {
8484
/// An allocation ID to report when it is being allocated
8585
/// (helps for debugging memory leaks).
8686
tracked_alloc_id: Option<AllocId>,
87+
88+
/// Place where the `environ` static is stored. Lazily initialized, but then never changes.
89+
pub(crate) environ: Option<MPlaceTy<'tcx, Tag>>,
8790
}
8891

89-
impl MemoryExtra {
92+
impl<'tcx> MemoryExtra<'tcx> {
9093
pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option<PtrId>, tracked_alloc_id: Option<AllocId>) -> Self {
9194
let stacked_borrows = if stacked_borrows {
9295
Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag))))
@@ -99,14 +102,16 @@ impl MemoryExtra {
99102
extern_statics: FxHashMap::default(),
100103
rng: RefCell::new(rng),
101104
tracked_alloc_id,
105+
environ: None,
102106
}
103107
}
104108

105109
/// Sets up the "extern statics" for this machine.
106-
pub fn init_extern_statics<'mir, 'tcx>(
110+
pub fn init_extern_statics<'mir>(
107111
this: &mut MiriEvalContext<'mir, 'tcx>,
108112
) -> InterpResult<'tcx> {
109-
match this.tcx.sess.target.target.target_os.as_str() {
113+
let target_os = this.tcx.sess.target.target.target_os.as_str();
114+
match target_os {
110115
"linux" => {
111116
// "__cxa_thread_atexit_impl"
112117
// This should be all-zero, pointer-sized.
@@ -118,6 +123,12 @@ impl MemoryExtra {
118123
.extern_statics
119124
.insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id)
120125
.unwrap_none();
126+
// "environ"
127+
this.memory
128+
.extra
129+
.extern_statics
130+
.insert(Symbol::intern("environ"), this.memory.extra.environ.unwrap().ptr.assert_ptr().alloc_id)
131+
.unwrap_none();
121132
}
122133
_ => {} // No "extern statics" supported on this platform
123134
}
@@ -203,7 +214,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
203214
type MemoryKinds = MiriMemoryKind;
204215

205216
type FrameExtra = FrameData<'tcx>;
206-
type MemoryExtra = MemoryExtra;
217+
type MemoryExtra = MemoryExtra<'tcx>;
207218
type AllocExtra = AllocExtra;
208219
type PointerTag = Tag;
209220
type ExtraFnVal = Dlsym;
@@ -329,7 +340,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
329340
}
330341

331342
fn init_allocation_extra<'b>(
332-
memory_extra: &MemoryExtra,
343+
memory_extra: &MemoryExtra<'tcx>,
333344
id: AllocId,
334345
alloc: Cow<'b, Allocation>,
335346
kind: Option<MemoryKind<Self::MemoryKinds>>,
@@ -366,7 +377,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> {
366377
}
367378

368379
#[inline(always)]
369-
fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag {
380+
fn tag_static_base_pointer(memory_extra: &MemoryExtra<'tcx>, id: AllocId) -> Self::PointerTag {
370381
if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() {
371382
stacked_borrows.borrow_mut().static_base_ptr(id)
372383
} else {

src/shims/env.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::ffi::{OsString, OsStr};
22
use std::env;
33

44
use crate::stacked_borrows::Tag;
5+
use crate::rustc_target::abi::LayoutOf;
56
use crate::*;
67

78
use rustc_data_structures::fx::FxHashMap;
@@ -19,7 +20,7 @@ impl EnvVars {
1920
pub(crate) fn init<'mir, 'tcx>(
2021
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
2122
excluded_env_vars: Vec<String>,
22-
) {
23+
) -> InterpResult<'tcx> {
2324
if ecx.machine.communicate {
2425
for (name, value) in env::vars() {
2526
if !excluded_env_vars.contains(&name) {
@@ -29,6 +30,12 @@ impl EnvVars {
2930
}
3031
}
3132
}
33+
// Initialize the `environ` static
34+
let layout = ecx.layout_of(ecx.tcx.types.usize)?;
35+
let place = ecx.allocate(layout, MiriMemoryKind::Machine.into());
36+
ecx.write_scalar(Scalar::from_machine_usize(0, &*ecx.tcx), place.into())?;
37+
ecx.memory.extra.environ = Some(place);
38+
ecx.update_environ()
3239
}
3340
}
3441

@@ -82,6 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8289
this.memory
8390
.deallocate(var, None, MiriMemoryKind::Machine.into())?;
8491
}
92+
this.update_environ()?;
8593
Ok(0)
8694
} else {
8795
Ok(-1)
@@ -104,6 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
104112
this.memory
105113
.deallocate(var, None, MiriMemoryKind::Machine.into())?;
106114
}
115+
this.update_environ()?;
107116
Ok(0)
108117
} else {
109118
Ok(-1)
@@ -150,4 +159,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
150159
}
151160
}
152161
}
162+
163+
/// Updates the `environ` static. It should not be called before
164+
/// `EnvVars::init`.
165+
fn update_environ(&mut self) -> InterpResult<'tcx> {
166+
let this = self.eval_context_mut();
167+
// Deallocate the old environ value.
168+
let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?;
169+
// The pointer itself can be null because `EnvVars::init` only
170+
// initializes the place for the static but not the static itself.
171+
if !this.is_null(old_vars_ptr)? {
172+
this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?;
173+
}
174+
// Collect all the pointers to each variable in a vector.
175+
let mut vars: Vec<Scalar<Tag>> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect();
176+
// Add the trailing null pointer.
177+
vars.push(Scalar::from_int(0, this.pointer_size()));
178+
// Make an array with all these pointers inside Miri.
179+
let tcx = this.tcx;
180+
let vars_layout =
181+
this.layout_of(tcx.mk_array(tcx.types.usize, vars.len() as u64))?;
182+
let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into());
183+
for (idx, var) in vars.into_iter().enumerate() {
184+
let place = this.mplace_field(vars_place, idx as u64)?;
185+
this.write_scalar(var, place.into())?;
186+
}
187+
this.write_scalar(
188+
vars_place.ptr,
189+
this.memory.extra.environ.unwrap().into(),
190+
)?;
191+
192+
Ok(())
193+
}
153194
}

src/shims/foreign_items/posix/macos.rs

+5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5656
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
5757
}
5858

59+
// Environment related shims
60+
"_NSGetEnviron" => {
61+
this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?;
62+
}
63+
5964
// Time related shims
6065
"gettimeofday" => {
6166
let result = this.gettimeofday(args[0], args[1])?;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//ignore-windows: TODO env var emulation stubbed out on Windows
2+
3+
#[cfg(target_os="linux")]
4+
fn get_environ() -> *const *const u8 {
5+
extern "C" {
6+
static mut environ: *const *const u8;
7+
}
8+
unsafe { environ }
9+
}
10+
11+
#[cfg(target_os="macos")]
12+
fn get_environ() -> *const *const u8 {
13+
extern "C" {
14+
fn _NSGetEnviron() -> *mut *const *const u8;
15+
}
16+
unsafe { *_NSGetEnviron() }
17+
}
18+
19+
fn main() {
20+
let pointer = get_environ();
21+
let _x = unsafe { *pointer };
22+
std::env::set_var("FOO", "BAR");
23+
let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced
24+
}

tests/run-pass/env.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,26 @@
33
use std::env;
44

55
fn main() {
6+
// Test that miri environment is isolated when communication is disabled.
7+
// (`MIRI_ENV_VAR_TEST` is set by the test harness.)
8+
assert_eq!(env::var("MIRI_ENV_VAR_TEST"), Err(env::VarError::NotPresent));
9+
10+
// Test base state.
11+
println!("{:#?}", env::vars().collect::<Vec<_>>());
612
assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent));
13+
14+
// Set the variable.
715
env::set_var("MIRI_TEST", "the answer");
816
assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned()));
9-
// Test that miri environment is isolated when communication is disabled.
10-
assert!(env::var("MIRI_ENV_VAR_TEST").is_err());
17+
println!("{:#?}", env::vars().collect::<Vec<_>>());
18+
19+
// Change the variable.
20+
env::set_var("MIRI_TEST", "42");
21+
assert_eq!(env::var("MIRI_TEST"), Ok("42".to_owned()));
22+
println!("{:#?}", env::vars().collect::<Vec<_>>());
23+
24+
// Remove the variable.
25+
env::remove_var("MIRI_TEST");
26+
assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent));
27+
println!("{:#?}", env::vars().collect::<Vec<_>>());
1128
}

tests/run-pass/env.stdout

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[]
2+
[
3+
(
4+
"MIRI_TEST",
5+
"the answer",
6+
),
7+
]
8+
[
9+
(
10+
"MIRI_TEST",
11+
"42",
12+
),
13+
]
14+
[]

0 commit comments

Comments
 (0)