@@ -101,17 +101,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101101 self . eval_context_mut ( ) . write_c_str ( bytes, ptr, size)
102102 }
103103
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`).
110115 fn write_os_str_to_wide_str (
111116 & mut self ,
112117 os_str : & OsStr ,
113118 ptr : Pointer < Option < Provenance > > ,
114119 size : u64 ,
120+ truncate : bool ,
115121 ) -> InterpResult < ' tcx , ( bool , u64 ) > {
116122 #[ cfg( windows) ]
117123 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> {
129135 }
130136
131137 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) )
133147 }
134148
135149 /// 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> {
143157
144158 let arg_type = this. tcx . mk_array ( this. tcx . types . u8 , size) ;
145159 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) ;
147162 Ok ( arg_place. ptr )
148163 }
149164
@@ -158,7 +173,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158173
159174 let arg_type = this. tcx . mk_array ( this. tcx . types . u16 , size) ;
160175 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) ;
162179 Ok ( arg_place. ptr )
163180 }
164181
@@ -212,11 +229,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
212229 path : & Path ,
213230 ptr : Pointer < Option < Provenance > > ,
214231 size : u64 ,
232+ truncate : bool ,
215233 ) -> InterpResult < ' tcx , ( bool , u64 ) > {
216234 let this = self . eval_context_mut ( ) ;
217235 let os_str =
218236 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 )
220238 }
221239
222240 /// 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> {
232250 this. alloc_os_str_as_c_str ( & os_str, memkind)
233251 }
234252
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+
235266 #[ allow( clippy:: get_first) ]
236267 fn convert_path < ' a > (
237268 & self ,
0 commit comments