@@ -13,7 +13,7 @@ use rustc_mir::interpret::Pointer;
13
13
#[ derive( Default ) ]
14
14
pub struct EnvVars < ' tcx > {
15
15
/// 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.
17
17
map : FxHashMap < OsString , Pointer < Tag > > ,
18
18
19
19
/// 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>(
46
46
let mut name_osstring = name. to_os_string ( ) ;
47
47
name_osstring. push ( "=" ) ;
48
48
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 ( ) ) ?)
53
50
}
54
51
55
52
impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
56
53
pub 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 ( ) ;
59
56
60
57
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
61
58
let name = this. read_os_str_from_target_str ( name_ptr) ?;
62
59
Ok ( match this. machine . env_vars . map . get ( & name) {
63
- // The offset is used to strip the "{name}=" part of the string.
64
60
Some ( var_ptr) => {
65
61
Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( u64:: try_from ( name. len ( ) ) . unwrap ( ) . checked_add ( 1 ) . unwrap ( ) ) , this) ?)
66
62
}
@@ -69,8 +65,57 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
69
65
}
70
66
71
67
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
+ }
73
95
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
+ } )
74
119
}
75
120
76
121
fn setenv (
@@ -97,14 +142,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
97
142
. deallocate ( var, None , MiriMemoryKind :: Machine . into ( ) ) ?;
98
143
}
99
144
this. update_environ ( ) ?;
100
- Ok ( 0 )
145
+ Ok ( 0 ) // return zero on success
101
146
} else {
102
147
Ok ( -1 )
103
148
}
104
149
}
105
150
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 )
108
158
}
109
159
110
160
fn unsetenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
0 commit comments