@@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101
101
self . eval_context_mut ( ) . write_c_str ( bytes, ptr, size)
102
102
}
103
103
104
- /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
105
- /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
106
- /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
107
- /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
108
- /// string length returned does include the null terminator. Length is measured in units of
109
- /// `u16.`
104
+ /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
105
+ /// Windows APIs usually handle.
106
+ ///
107
+ /// If `truncate == false` (the usual mode of operation), this function returns `Ok((false,
108
+ /// length))` without trying to write if `size` is not large enough to fit the contents of
109
+ /// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process
110
+ /// was successful. The string length returned does include the null terminator. Length is
111
+ /// measured in units of `u16.`
112
+ ///
113
+ /// If `truncate == true`, then in case `size` is not large enough it *will* write the first
114
+ /// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
110
115
fn write_os_str_to_wide_str (
111
116
& mut self ,
112
117
os_str : & OsStr ,
113
118
ptr : Pointer < Option < Provenance > > ,
114
119
size : u64 ,
120
+ truncate : bool ,
115
121
) -> InterpResult < ' tcx , ( bool , u64 ) > {
116
122
#[ cfg( windows) ]
117
123
fn os_str_to_u16vec < ' tcx > ( os_str : & OsStr ) -> InterpResult < ' tcx , Vec < u16 > > {
@@ -129,7 +135,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
129
135
}
130
136
131
137
let u16_vec = os_str_to_u16vec ( os_str) ?;
132
- self . eval_context_mut ( ) . write_wide_str ( & u16_vec, ptr, size)
138
+ let ( written, size_needed) = self . eval_context_mut ( ) . write_wide_str ( & u16_vec, ptr, size) ?;
139
+ if truncate && !written && size > 0 {
140
+ // Write the truncated part that fits.
141
+ let truncated_data = & u16_vec[ ..size. saturating_sub ( 1 ) . try_into ( ) . unwrap ( ) ] ;
142
+ let ( written, written_len) =
143
+ self . eval_context_mut ( ) . write_wide_str ( truncated_data, ptr, size) ?;
144
+ assert ! ( written && written_len == size) ;
145
+ }
146
+ Ok ( ( written, size_needed) )
133
147
}
134
148
135
149
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
@@ -143,7 +157,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
143
157
144
158
let arg_type = this. tcx . mk_array ( this. tcx . types . u8 , size) ;
145
159
let arg_place = this. allocate ( this. layout_of ( arg_type) . unwrap ( ) , memkind) ?;
146
- assert ! ( self . write_os_str_to_c_str( os_str, arg_place. ptr, size) . unwrap( ) . 0 ) ;
160
+ let ( written, _) = self . write_os_str_to_c_str ( os_str, arg_place. ptr , size) . unwrap ( ) ;
161
+ assert ! ( written) ;
147
162
Ok ( arg_place. ptr )
148
163
}
149
164
@@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158
173
159
174
let arg_type = this. tcx . mk_array ( this. tcx . types . u16 , size) ;
160
175
let arg_place = this. allocate ( this. layout_of ( arg_type) . unwrap ( ) , memkind) ?;
161
- assert ! ( self . write_os_str_to_wide_str( os_str, arg_place. ptr, size) . unwrap( ) . 0 ) ;
176
+ let ( written, _) =
177
+ self . write_os_str_to_wide_str ( os_str, arg_place. ptr , size, /*truncate*/ false ) . unwrap ( ) ;
178
+ assert ! ( written) ;
162
179
Ok ( arg_place. ptr )
163
180
}
164
181
@@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
212
229
path : & Path ,
213
230
ptr : Pointer < Option < Provenance > > ,
214
231
size : u64 ,
232
+ truncate : bool ,
215
233
) -> InterpResult < ' tcx , ( bool , u64 ) > {
216
234
let this = self . eval_context_mut ( ) ;
217
235
let os_str =
218
236
this. convert_path ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
219
- this. write_os_str_to_wide_str ( & os_str, ptr, size)
237
+ this. write_os_str_to_wide_str ( & os_str, ptr, size, truncate )
220
238
}
221
239
222
240
/// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
@@ -232,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
232
250
this. alloc_os_str_as_c_str ( & os_str, memkind)
233
251
}
234
252
253
+ /// Allocate enough memory to store a Path as a null-terminated sequence of `u16`s,
254
+ /// adjusting path separators if needed.
255
+ fn alloc_path_as_wide_str (
256
+ & mut self ,
257
+ path : & Path ,
258
+ memkind : MemoryKind < MiriMemoryKind > ,
259
+ ) -> InterpResult < ' tcx , Pointer < Option < Provenance > > > {
260
+ let this = self . eval_context_mut ( ) ;
261
+ let os_str =
262
+ this. convert_path ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
263
+ this. alloc_os_str_as_wide_str ( & os_str, memkind)
264
+ }
265
+
235
266
#[ allow( clippy:: get_first) ]
236
267
fn convert_path < ' a > (
237
268
& self ,
0 commit comments