Skip to content

Commit 2e17933

Browse files
committed
Auto merge of #958 - christianpoveda:getcwd-shim, r=oli-obk
Add getcwd shim
2 parents 0c77a10 + 02261e4 commit 2e17933

File tree

3 files changed

+66
-15
lines changed

3 files changed

+66
-15
lines changed

src/shims/env.rs

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use std::collections::HashMap;
2+
use std::env;
23

3-
use rustc::ty::layout::{Size};
4-
use rustc_mir::interpret::{Pointer, Memory};
54
use crate::stacked_borrows::Tag;
65
use crate::*;
6+
use rustc::ty::layout::Size;
7+
use rustc_mir::interpret::{Memory, Pointer};
78

89
#[derive(Default)]
910
pub struct EnvVars {
@@ -21,9 +22,10 @@ impl EnvVars {
2122
excluded_env_vars.push("TERM".to_owned());
2223

2324
if ecx.machine.communicate {
24-
for (name, value) in std::env::vars() {
25+
for (name, value) in env::vars() {
2526
if !excluded_env_vars.contains(&name) {
26-
let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
27+
let var_ptr =
28+
alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut());
2729
ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
2830
}
2931
}
@@ -45,17 +47,16 @@ fn alloc_env_var<'mir, 'tcx>(
4547

4648
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
4749
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
48-
fn getenv(
49-
&mut self,
50-
name_op: OpTy<'tcx, Tag>,
51-
) -> InterpResult<'tcx, Scalar<Tag>> {
50+
fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
5251
let this = self.eval_context_mut();
5352

5453
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
5554
let name = this.memory().read_c_str(name_ptr)?;
5655
Ok(match this.machine.env_vars.map.get(name) {
5756
// The offset is used to strip the "{name}=" part of the string.
58-
Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?),
57+
Some(var_ptr) => {
58+
Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?)
59+
}
5960
None => Scalar::ptr_null(&*this.tcx),
6061
})
6162
}
@@ -80,18 +81,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
8081
if let Some((name, value)) = new {
8182
let var_ptr = alloc_env_var(&name, &value, this.memory_mut());
8283
if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
83-
this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
84+
this.memory_mut()
85+
.deallocate(var, None, MiriMemoryKind::Env.into())?;
8486
}
8587
Ok(0)
8688
} else {
8789
Ok(-1)
8890
}
8991
}
9092

91-
fn unsetenv(
92-
&mut self,
93-
name_op: OpTy<'tcx, Tag>,
94-
) -> InterpResult<'tcx, i32> {
93+
fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
9594
let this = self.eval_context_mut();
9695

9796
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
@@ -104,11 +103,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
104103
}
105104
if let Some(old) = success {
106105
if let Some(var) = old {
107-
this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
106+
this.memory_mut()
107+
.deallocate(var, None, MiriMemoryKind::Env.into())?;
108108
}
109109
Ok(0)
110110
} else {
111111
Ok(-1)
112112
}
113113
}
114+
115+
fn getcwd(
116+
&mut self,
117+
buf_op: OpTy<'tcx, Tag>,
118+
size_op: OpTy<'tcx, Tag>,
119+
) -> InterpResult<'tcx, Scalar<Tag>> {
120+
let this = self.eval_context_mut();
121+
122+
if !this.machine.communicate {
123+
throw_unsup_format!("`getcwd` not available when isolation is enabled")
124+
}
125+
126+
let tcx = &{ this.tcx.tcx };
127+
128+
let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
129+
let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?;
130+
// If we cannot get the current directory, we return null
131+
match env::current_dir() {
132+
Ok(cwd) => {
133+
// It is not clear what happens with non-utf8 paths here
134+
let mut bytes = cwd.display().to_string().into_bytes();
135+
// If the buffer is smaller or equal than the path, we return null.
136+
if (bytes.len() as u64) < size {
137+
// We add a `/0` terminator
138+
bytes.push(0);
139+
// This is ok because the buffer is larger than the path with the null terminator.
140+
this.memory_mut()
141+
.get_mut(buf.alloc_id)?
142+
.write_bytes(tcx, buf, &bytes)?;
143+
return Ok(Scalar::Ptr(buf));
144+
}
145+
this.machine.last_error = this
146+
.eval_path_scalar(&["libc", "ERANGE"])?
147+
.unwrap()
148+
.to_u32()?;
149+
}
150+
Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32,
151+
}
152+
Ok(Scalar::ptr_null(&*this.tcx))
153+
}
114154
}

src/shims/foreign_items.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
436436
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
437437
}
438438

439+
"getcwd" => {
440+
let result = this.getcwd(args[0], args[1])?;
441+
this.write_scalar(result, dest)?;
442+
}
443+
439444
"write" => {
440445
let fd = this.read_scalar(args[0])?.to_i32()?;
441446
let buf = this.read_scalar(args[1])?.not_undef()?;

tests/run-pass/get_current_dir.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// ignore-windows: TODO the windows hook is not done yet
2+
// compile-flags: -Zmiri-disable-isolation
3+
4+
fn main() {
5+
std::env::current_dir().unwrap();
6+
}

0 commit comments

Comments
 (0)