@@ -13,7 +13,7 @@ use rustc_mir::interpret::Pointer;
1313#[ derive( Default ) ]
1414pub struct EnvVars < ' tcx > {
1515 /// Stores pointers to the environment variables. These variables must be stored as
16- /// null-terminated C strings with the `"{name}={value}"` format.
16+ /// null-terminated target strings(c_str or wide_str) with the `"{name}={value}"` format.
1717 map : FxHashMap < OsString , Pointer < Tag > > ,
1818
1919 /// Place where the `environ` static is stored. Lazily initialized, but then never changes.
@@ -46,21 +46,17 @@ fn alloc_env_var_as_target_str<'mir, 'tcx>(
4646 let mut name_osstring = name. to_os_string ( ) ;
4747 name_osstring. push ( "=" ) ;
4848 name_osstring. push ( value) ;
49- Ok ( ecx
50- . alloc_os_str_as_target_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) ?
51- . ptr
52- . assert_ptr ( ) )
49+ Ok ( ecx. alloc_os_str_as_target_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) ?)
5350}
5451
5552impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
5653pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
57- fn getenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , Scalar < Tag > > {
58- let this = self . eval_context_mut ( ) ;
54+ fn getenv ( & self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , Scalar < Tag > > {
55+ let this = self . eval_context_ref ( ) ;
5956
6057 let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
6158 let name = this. read_os_str_from_target_str ( name_ptr) ?;
6259 Ok ( match this. machine . env_vars . map . get ( & name) {
63- // The offset is used to strip the "{name}=" part of the string.
6460 Some ( var_ptr) => {
6561 Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( u64:: try_from ( name. len ( ) ) . unwrap ( ) . checked_add ( 1 ) . unwrap ( ) ) , this) ?)
6662 }
@@ -69,8 +65,57 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6965 }
7066
7167
72- fn getenvironmentvariablew ( ) {
68+ fn getenvironmentvariablew (
69+ & mut self ,
70+ name_op : OpTy < ' tcx , Tag > , // LPCWSTR lpName
71+ buf_op : OpTy < ' tcx , Tag > , // LPWSTR lpBuffer
72+ size_op : OpTy < ' tcx , Tag > , // DWORD nSize
73+ ) -> InterpResult < ' tcx , u32 > {
74+ let this = self . eval_context_mut ( ) ;
75+
76+ let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
77+ let name = this. read_os_str_from_target_str ( name_ptr) ?;
78+ Ok ( match this. machine . env_vars . map . get ( & name) {
79+ Some ( var_ptr) => {
80+ // The offset is used to strip the "{name}=" part of the string.
81+ let var_ptr = Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( ( name. len ( ) as u64 + 1 ) * 2 ) , this) ?) ;
82+ let buf_size = this. read_scalar ( size_op) ?. to_i32 ( ) ? as u64 ;
83+ let buf_ptr = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
84+ let size_u16 = Size :: from_bytes ( 2 ) ;
85+
86+ // The following loop attempts to figure out the length of env_var (`var_size`)
87+ let mut var_size = 0u64 ;
88+ loop {
89+ let temp_var_ptr = var_ptr. ptr_offset ( Size :: from_bytes ( var_size * 2 ) , this) ?;
90+ let bytes = this. memory . read_bytes ( temp_var_ptr, size_u16) ?;
91+ var_size += 1 ;
92+ // encountered 0x0000 terminator
93+ if bytes[ 0 ] == 0 && bytes[ 1 ] == 0 { break ; }
94+ }
7395
96+ let return_val = if var_size > buf_size {
97+ // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters,
98+ // required to hold the string and its terminating null character and the contents of lpBuffer are undefined.
99+ var_size
100+ } else {
101+ for i in 0 ..var_size {
102+ this. memory . copy (
103+ this. force_ptr ( var_ptr. ptr_offset ( Size :: from_bytes ( i * 2 ) , this) ?) ?,
104+ this. force_ptr ( buf_ptr. ptr_offset ( Size :: from_bytes ( i * 2 ) , this) ?) ?,
105+ size_u16,
106+ true ,
107+ ) ?;
108+ }
109+ // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer,
110+ // not including the terminating null character.
111+ var_size - 1
112+ } ;
113+ assert_eq ! ( return_val as u32 as u64 , return_val) ;
114+ return_val as u32
115+ }
116+ // return zero upon failure
117+ None => 0u32
118+ } )
74119 }
75120
76121 fn setenv (
@@ -97,14 +142,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
97142 . deallocate ( var, None , MiriMemoryKind :: Machine . into ( ) ) ?;
98143 }
99144 this. update_environ ( ) ?;
100- Ok ( 0 )
145+ Ok ( 0 ) // return zero on success
101146 } else {
102147 Ok ( -1 )
103148 }
104149 }
105150
106- fn setenvironmentvariablew ( ) {
107-
151+ fn setenvironmentvariablew (
152+ & mut self ,
153+ name_op : OpTy < ' tcx , Tag > , // LPCWSTR lpName,
154+ value_op : OpTy < ' tcx , Tag > , // LPCWSTR lpValue,
155+ ) -> InterpResult < ' tcx , i32 > {
156+ // return non-zero on success
157+ self . setenv ( name_op, value_op) . map ( |x| x + 1 )
108158 }
109159
110160 fn unsetenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
0 commit comments