11use std:: collections:: HashMap ;
2+ use std:: env;
23
3- use rustc:: ty:: layout:: { Size } ;
4- use rustc_mir:: interpret:: { Pointer , Memory } ;
54use crate :: stacked_borrows:: Tag ;
65use crate :: * ;
6+ use rustc:: ty:: layout:: Size ;
7+ use rustc_mir:: interpret:: { Memory , Pointer } ;
78
89#[ derive( Default ) ]
910pub 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
4648impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
4749pub 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}
0 commit comments