@@ -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`). 
110115fn  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