@@ -10,6 +10,21 @@ use rustc_data_structures::fx::FxHashMap;
10
10
use rustc:: ty:: layout:: Size ;
11
11
use rustc_mir:: interpret:: Pointer ;
12
12
13
+ /// Check whether an operation that writes to a target buffer was successful.
14
+ /// Accordingly select return value.
15
+ /// Local helper function to be used in Windows shims.
16
+ fn windows_check_buffer_size ( ( success, len) : ( bool , u64 ) ) -> u32 {
17
+ if success {
18
+ // If the function succeeds, the return value is the number of characters stored in the target buffer,
19
+ // not including the terminating null character.
20
+ u32:: try_from ( len) . unwrap ( )
21
+ } else {
22
+ // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters,
23
+ // required to hold the string and its terminating null character.
24
+ u32:: try_from ( len. checked_add ( 1 ) . unwrap ( ) ) . unwrap ( )
25
+ }
26
+ }
27
+
13
28
#[ derive( Default ) ]
14
29
pub struct EnvVars < ' tcx > {
15
30
/// Stores pointers to the environment variables. These variables must be stored as
@@ -105,10 +120,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
105
120
#[ allow( non_snake_case) ]
106
121
fn GetEnvironmentVariableW (
107
122
& mut self ,
108
- name_op : OpTy < ' tcx , Tag > , // LPCWSTR
109
- buf_op : OpTy < ' tcx , Tag > , // LPWSTR
110
- size_op : OpTy < ' tcx , Tag > , // DWORD
111
- ) -> InterpResult < ' tcx , u32 > {
123
+ name_op : OpTy < ' tcx , Tag > , // LPCWSTR
124
+ buf_op : OpTy < ' tcx , Tag > , // LPWSTR
125
+ size_op : OpTy < ' tcx , Tag > , // DWORD
126
+ ) -> InterpResult < ' tcx , u32 > { // Returns DWORD (u32 in Windows)
112
127
let this = self . eval_context_mut ( ) ;
113
128
this. assert_target_os ( "windows" , "GetEnvironmentVariableW" ) ;
114
129
@@ -125,21 +140,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
125
140
let buf_ptr = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
126
141
// `buf_size` represents the size in characters.
127
142
let buf_size = u64:: from ( this. read_scalar ( size_op) ?. to_u32 ( ) ?) ;
128
- let ( success, len) = this. write_os_str_to_wide_str ( & var, buf_ptr, buf_size) ?;
129
-
130
- if success {
131
- // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer,
132
- // not including the terminating null character.
133
- u32:: try_from ( len) . unwrap ( )
134
- } else {
135
- // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters,
136
- // required to hold the string and its terminating null character and the contents of lpBuffer are undefined.
137
- u32:: try_from ( len) . unwrap ( ) . checked_add ( 1 ) . unwrap ( )
138
- }
143
+ windows_check_buffer_size ( this. write_os_str_to_wide_str ( & var, buf_ptr, buf_size) ?)
139
144
}
140
145
None => {
141
- let envvar_not_found = this. eval_path_scalar ( & [ "std" , "sys" , "windows" , "c" , " ERROR_ENVVAR_NOT_FOUND"] ) ?;
142
- this. set_last_error ( envvar_not_found. not_undef ( ) ? ) ?;
146
+ let envvar_not_found = this. eval_windows ( " ERROR_ENVVAR_NOT_FOUND") ?;
147
+ this. set_last_error ( envvar_not_found) ?;
143
148
0 // return zero upon failure
144
149
}
145
150
} )
@@ -289,6 +294,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
289
294
size_op : OpTy < ' tcx , Tag > ,
290
295
) -> InterpResult < ' tcx , Scalar < Tag > > {
291
296
let this = self . eval_context_mut ( ) ;
297
+ let target_os = & this. tcx . sess . target . target . target_os ;
298
+ assert ! ( target_os == "linux" || target_os == "macos" , "`getcwd` is only available for the UNIX target family" ) ;
292
299
293
300
this. check_no_isolation ( "getcwd" ) ?;
294
301
@@ -308,8 +315,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
308
315
Ok ( Scalar :: null_ptr ( & * this. tcx ) )
309
316
}
310
317
318
+ #[ allow( non_snake_case) ]
319
+ fn GetCurrentDirectoryW (
320
+ & mut self ,
321
+ size_op : OpTy < ' tcx , Tag > , // DWORD
322
+ buf_op : OpTy < ' tcx , Tag > , // LPTSTR
323
+ ) -> InterpResult < ' tcx , u32 > {
324
+ let this = self . eval_context_mut ( ) ;
325
+ this. assert_target_os ( "windows" , "GetCurrentDirectoryW" ) ;
326
+
327
+ this. check_no_isolation ( "GetCurrentDirectoryW" ) ?;
328
+
329
+ let size = u64:: from ( this. read_scalar ( size_op) ?. to_u32 ( ) ?) ;
330
+ let buf = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
331
+
332
+ // If we cannot get the current directory, we return 0
333
+ match env:: current_dir ( ) {
334
+ Ok ( cwd) =>
335
+ return Ok ( windows_check_buffer_size ( this. write_path_to_wide_str ( & cwd, buf, size) ?) ) ,
336
+ Err ( e) => this. set_last_error_from_io_error ( e) ?,
337
+ }
338
+ Ok ( 0 )
339
+ }
340
+
311
341
fn chdir ( & mut self , path_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
312
342
let this = self . eval_context_mut ( ) ;
343
+ let target_os = & this. tcx . sess . target . target . target_os ;
344
+ assert ! ( target_os == "linux" || target_os == "macos" , "`getcwd` is only available for the UNIX target family" ) ;
313
345
314
346
this. check_no_isolation ( "chdir" ) ?;
315
347
@@ -324,6 +356,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
324
356
}
325
357
}
326
358
359
+ #[ allow( non_snake_case) ]
360
+ fn SetCurrentDirectoryW (
361
+ & mut self ,
362
+ path_op : OpTy < ' tcx , Tag > // LPCTSTR
363
+ ) -> InterpResult < ' tcx , i32 > { // Returns BOOL (i32 in Windows)
364
+ let this = self . eval_context_mut ( ) ;
365
+ this. assert_target_os ( "windows" , "SetCurrentDirectoryW" ) ;
366
+
367
+ this. check_no_isolation ( "SetCurrentDirectoryW" ) ?;
368
+
369
+ let path = this. read_path_from_wide_str ( this. read_scalar ( path_op) ?. not_undef ( ) ?) ?;
370
+
371
+ match env:: set_current_dir ( path) {
372
+ Ok ( ( ) ) => Ok ( 1 ) ,
373
+ Err ( e) => {
374
+ this. set_last_error_from_io_error ( e) ?;
375
+ Ok ( 0 )
376
+ }
377
+ }
378
+ }
379
+
327
380
/// Updates the `environ` static.
328
381
/// The first time it gets called, also initializes `extra.environ`.
329
382
fn update_environ ( & mut self ) -> InterpResult < ' tcx > {
0 commit comments