@@ -23,8 +23,12 @@ pub struct EnvVars<'tcx> {
23
23
impl < ' tcx > EnvVars < ' tcx > {
24
24
pub ( crate ) fn init < ' mir > (
25
25
ecx : & mut InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > ,
26
- excluded_env_vars : Vec < String > ,
26
+ mut excluded_env_vars : Vec < String > ,
27
27
) -> InterpResult < ' tcx > {
28
+ if ecx. tcx . sess . target . target . target_os == "windows" {
29
+ // Exclude `TERM` var to avoid terminfo trying to open the termcap file.
30
+ excluded_env_vars. push ( "TERM" . to_owned ( ) ) ;
31
+ }
28
32
if ecx. machine . communicate {
29
33
for ( name, value) in env:: vars ( ) {
30
34
if !excluded_env_vars. contains ( & name) {
@@ -49,19 +53,41 @@ fn alloc_env_var_as_target_str<'mir, 'tcx>(
49
53
Ok ( ecx. alloc_os_str_as_target_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) ?)
50
54
}
51
55
56
+ fn alloc_env_var_as_c_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_c_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) )
65
+ }
66
+
67
+ fn alloc_env_var_as_wide_str < ' mir , ' tcx > (
68
+ name : & OsStr ,
69
+ value : & OsStr ,
70
+ ecx : & mut InterpCx < ' mir , ' tcx , Evaluator < ' tcx > > ,
71
+ ) -> InterpResult < ' tcx , Pointer < Tag > > {
72
+ let mut name_osstring = name. to_os_string ( ) ;
73
+ name_osstring. push ( "=" ) ;
74
+ name_osstring. push ( value) ;
75
+ Ok ( ecx. alloc_os_str_as_wide_str ( name_osstring. as_os_str ( ) , MiriMemoryKind :: Machine . into ( ) ) )
76
+ }
77
+
52
78
impl < ' mir , ' tcx > EvalContextExt < ' mir , ' tcx > for crate :: MiriEvalContext < ' mir , ' tcx > { }
53
79
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
54
80
fn getenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , Scalar < Tag > > {
55
81
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" ) ;
82
+ let target_os = & this. tcx . sess . target . target . target_os ;
83
+ assert ! ( target_os == "linux" || target_os == "macos" , "`getenv ` is only available for the UNIX target family" ) ;
58
84
59
85
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
60
86
let name = this. read_os_str_from_c_str ( name_ptr) ?;
61
87
Ok ( match this. machine . env_vars . map . get ( name) {
62
- // The offset is used to strip the "{name}=" part of the string.
63
88
Some ( var_ptr) => {
64
- Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( name. len ( ) ) + Size :: from_bytes ( 1 ) , this) ?)
89
+ // The offset is used to strip the "{name}=" part of the string.
90
+ Scalar :: from ( var_ptr. offset ( Size :: from_bytes ( u64:: try_from ( name. len ( ) ) . unwrap ( ) . checked_add ( 1 ) . unwrap ( ) ) , this) ?)
65
91
}
66
92
None => Scalar :: ptr_null ( & * this. tcx ) ,
67
93
} )
@@ -73,32 +99,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
73
99
value_op : OpTy < ' tcx , Tag > ,
74
100
) -> InterpResult < ' tcx , i32 > {
75
101
let mut this = self . eval_context_mut ( ) ;
102
+ let target_os = & this. tcx . sess . target . target . target_os ;
103
+ assert ! ( target_os == "linux" || target_os == "macos" , "`setenv` is only available for the UNIX target family" ) ;
76
104
77
105
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
78
106
let value_ptr = this. read_scalar ( value_op) ?. not_undef ( ) ?;
79
- let value = this . read_os_str_from_target_str ( value_ptr ) ? ;
107
+
80
108
let mut new = None ;
81
109
if !this. is_null ( name_ptr) ? {
82
- let name = this. read_os_str_from_target_str ( name_ptr) ?;
110
+ let name = this. read_os_str_from_c_str ( name_ptr) ?;
83
111
if !name. is_empty ( ) && !name. to_string_lossy ( ) . contains ( '=' ) {
112
+ let value = this. read_os_str_from_c_str ( value_ptr) ?;
84
113
new = Some ( ( name. to_owned ( ) , value. to_owned ( ) ) ) ;
85
114
}
86
115
}
87
116
if let Some ( ( name, value) ) = new {
88
- let var_ptr = alloc_env_var_as_target_str ( & name, & value, & mut this) ?;
117
+ let var_ptr = alloc_env_var_as_c_str ( & name, & value, & mut this) ?;
89
118
if let Some ( var) = this. machine . env_vars . map . insert ( name, var_ptr) {
90
119
this. memory
91
120
. deallocate ( var, None , MiriMemoryKind :: Machine . into ( ) ) ?;
92
121
}
93
122
this. update_environ ( ) ?;
94
- Ok ( 0 )
123
+ Ok ( 0 ) // return zero on success
95
124
} else {
125
+ // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
126
+ let einval = this. eval_libc ( "EINVAL" ) ?;
127
+ this. set_last_error ( einval) ?;
96
128
Ok ( -1 )
97
129
}
98
130
}
99
131
100
132
fn unsetenv ( & mut self , name_op : OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
101
133
let this = self . eval_context_mut ( ) ;
134
+ let target_os = & this. tcx . sess . target . target . target_os ;
135
+ assert ! ( target_os == "linux" || target_os == "macos" , "`unsetenv` is only available for the UNIX target family" ) ;
102
136
103
137
let name_ptr = this. read_scalar ( name_op) ?. not_undef ( ) ?;
104
138
let mut success = None ;
@@ -116,6 +150,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
116
150
this. update_environ ( ) ?;
117
151
Ok ( 0 )
118
152
} else {
153
+ // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
154
+ let einval = this. eval_libc ( "EINVAL" ) ?;
155
+ this. set_last_error ( einval) ?;
119
156
Ok ( -1 )
120
157
}
121
158
}
0 commit comments