@@ -26,10 +26,14 @@ impl<'tcx> EnvVars<'tcx> {
26
26
excluded_env_vars : Vec < String > ,
27
27
) -> InterpResult < ' tcx > {
28
28
if ecx. machine . communicate {
29
+ let target_os = ecx. tcx . sess . target . target . target_os . as_str ( ) ;
29
30
for ( name, value) in env:: vars ( ) {
30
31
if !excluded_env_vars. contains ( & name) {
31
- let var_ptr =
32
- alloc_env_var_as_target_str ( name. as_ref ( ) , value. as_ref ( ) , ecx) ?;
32
+ let var_ptr = match target_os {
33
+ "linux" | "macos" => alloc_env_var_as_c_str ( name. as_ref ( ) , value. as_ref ( ) , ecx) ?,
34
+ "windows" => alloc_env_var_as_wide_str ( name. as_ref ( ) , value. as_ref ( ) , ecx) ?,
35
+ unsupported => throw_unsup_format ! ( "environment support for target OS `{}` not yet available" , unsupported) ,
36
+ } ;
33
37
ecx. machine . env_vars . map . insert ( OsString :: from ( name) , var_ptr) ;
34
38
}
35
39
}
@@ -38,30 +42,41 @@ impl<'tcx> EnvVars<'tcx> {
38
42
}
39
43
}
40
44
41
- fn alloc_env_var_as_target_str < ' mir , ' tcx > (
45
+ fn alloc_env_var_as_c_str < ' mir , ' tcx > (
42
46
name : & OsStr ,
43
47
value : & OsStr ,
44
48
ecx : & mut InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > ,
45
49
) -> InterpResult < ' tcx , Pointer < Tag > > {
46
50
let mut name_osstring = name. to_os_string ( ) ;
47
51
name_osstring. push ( "=" ) ;
48
52
name_osstring. push ( value) ;
49
- Ok ( ecx. alloc_os_str_as_target_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) ?)
53
+ Ok ( ecx. alloc_os_str_as_c_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) )
54
+ }
55
+
56
+ fn alloc_env_var_as_wide_str < ' mir , ' tcx > (
57
+ name : & OsStr ,
58
+ value : & OsStr ,
59
+ ecx : & mut InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > ,
60
+ ) -> InterpResult < ' tcx , Pointer < Tag > > {
61
+ let mut name_osstring = name. to_os_string ( ) ;
62
+ name_osstring. push ( "=" ) ;
63
+ name_osstring. push ( value) ;
64
+ Ok ( ecx. alloc_os_str_as_wide_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) )
50
65
}
51
66
52
67
impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
53
68
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
54
69
fn getenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , Scalar < Tag > > {
55
70
let this = self . eval_context_mut ( ) ;
56
- let target_os = this. tcx . sess . target . target . target_os . as_str ( ) ;
57
- assert ! ( target_os == "linux" || target_os == "macos" , "`{} ` is only available for the UNIX target family" ) ;
71
+ let target_os = & this. tcx . sess . target . target . target_os ;
72
+ assert ! ( target_os == "linux" || target_os == "macos" , "`getenv ` is only available for the UNIX target family" ) ;
58
73
59
74
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
60
75
let name = this. read_os_str_from_c_str ( name_ptr) ?;
61
76
Ok ( match this. machine . env_vars . map . get ( name) {
62
- // The offset is used to strip the "{name}=" part of the string.
63
77
Some ( var_ptr) => {
64
- Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( name. len ( ) ) + Size :: from_bytes ( 1 ) , this) ?)
78
+ // The offset is used to strip the "{name}=" part of the string.
79
+ Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( u64:: try_from ( name. len ( ) ) . unwrap ( ) . checked_add ( 1 ) . unwrap ( ) ) , this) ?)
65
80
}
66
81
None => Scalar :: ptr_null ( & * this. tcx ) ,
67
82
} )
@@ -73,32 +88,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
73
88
value_op : OpTy < ' tcx , Tag > ,
74
89
) -> InterpResult < ' tcx , i32 > {
75
90
let mut this = self . eval_context_mut ( ) ;
91
+ let target_os = & this. tcx . sess . target . target . target_os ;
92
+ assert ! ( target_os == "linux" || target_os == "macos" , "`setenv` is only available for the UNIX target family" ) ;
76
93
77
94
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
78
95
let value_ptr = this. read_scalar ( value_op) ?. not_undef ( ) ?;
79
- let value = this . read_os_str_from_target_str ( value_ptr ) ? ;
96
+
80
97
let mut new = None ;
81
98
if !this. is_null ( name_ptr) ? {
82
- let name = this. read_os_str_from_target_str ( name_ptr) ?;
99
+ let name = this. read_os_str_from_c_str ( name_ptr) ?;
83
100
if !name. is_empty ( ) && !name. to_string_lossy ( ) . contains ( '=' ) {
101
+ let value = this. read_os_str_from_c_str ( value_ptr) ?;
84
102
new = Some ( ( name. to_owned ( ) , value. to_owned ( ) ) ) ;
85
103
}
86
104
}
87
105
if let Some ( ( name, value) ) = new {
88
- let var_ptr = alloc_env_var_as_target_str ( & name, & value, & mut this) ?;
106
+ let var_ptr = alloc_env_var_as_c_str ( & name, & value, & mut this) ?;
89
107
if let Some ( var) = this. machine . env_vars . map . insert ( name, var_ptr) {
90
108
this. memory
91
109
. deallocate ( var, None , MiriMemoryKind :: Machine . into ( ) ) ?;
92
110
}
93
111
this. update_environ ( ) ?;
94
- Ok ( 0 )
112
+ Ok ( 0 ) // return zero on success
95
113
} else {
114
+ // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
115
+ let einval = this. eval_libc ( "EINVAL" ) ?;
116
+ this. set_last_error ( einval) ?;
96
117
Ok ( -1 )
97
118
}
98
119
}
99
120
100
121
fn unsetenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
101
122
let this = self . eval_context_mut ( ) ;
123
+ let target_os = & this. tcx . sess . target . target . target_os ;
124
+ assert ! ( target_os == "linux" || target_os == "macos" , "`unsetenv` is only available for the UNIX target family" ) ;
102
125
103
126
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
104
127
let mut success = None ;
@@ -116,6 +139,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
116
139
this. update_environ ( ) ?;
117
140
Ok ( 0 )
118
141
} else {
142
+ // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
143
+ let einval = this. eval_libc ( "EINVAL" ) ?;
144
+ this. set_last_error ( einval) ?;
119
145
Ok ( -1 )
120
146
}
121
147
}
0 commit comments