@@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
174174 let this = self . eval_context_ref ( ) ;
175175 let os_str = this. read_os_str_from_c_str ( ptr) ?;
176176
177- Ok ( match this. convert_path_separator ( Cow :: Borrowed ( os_str) , PathConversion :: TargetToHost ) {
177+ Ok ( match this. convert_path ( Cow :: Borrowed ( os_str) , PathConversion :: TargetToHost ) {
178178 Cow :: Borrowed ( x) => Cow :: Borrowed ( Path :: new ( x) ) ,
179179 Cow :: Owned ( y) => Cow :: Owned ( PathBuf :: from ( y) ) ,
180180 } )
@@ -188,10 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
188188 let this = self . eval_context_ref ( ) ;
189189 let os_str = this. read_os_str_from_wide_str ( ptr) ?;
190190
191- Ok ( this
192- . convert_path_separator ( Cow :: Owned ( os_str) , PathConversion :: TargetToHost )
193- . into_owned ( )
194- . into ( ) )
191+ Ok ( this. convert_path ( Cow :: Owned ( os_str) , PathConversion :: TargetToHost ) . into_owned ( ) . into ( ) )
195192 }
196193
197194 /// Write a Path to the machine memory (as a null-terminated sequence of bytes),
@@ -203,8 +200,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
203200 size : u64 ,
204201 ) -> InterpResult < ' tcx , ( bool , u64 ) > {
205202 let this = self . eval_context_mut ( ) ;
206- let os_str = this
207- . convert_path_separator ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
203+ let os_str =
204+ this . convert_path ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
208205 this. write_os_str_to_c_str ( & os_str, ptr, size)
209206 }
210207
@@ -217,8 +214,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
217214 size : u64 ,
218215 ) -> InterpResult < ' tcx , ( bool , u64 ) > {
219216 let this = self . eval_context_mut ( ) ;
220- let os_str = this
221- . convert_path_separator ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
217+ let os_str =
218+ this . convert_path ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
222219 this. write_os_str_to_wide_str ( & os_str, ptr, size)
223220 }
224221
@@ -230,18 +227,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
230227 memkind : MemoryKind < MiriMemoryKind > ,
231228 ) -> InterpResult < ' tcx , Pointer < Option < Provenance > > > {
232229 let this = self . eval_context_mut ( ) ;
233- let os_str = this
234- . convert_path_separator ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
230+ let os_str =
231+ this . convert_path ( Cow :: Borrowed ( path. as_os_str ( ) ) , PathConversion :: HostToTarget ) ;
235232 this. alloc_os_str_as_c_str ( & os_str, memkind)
236233 }
237234
238- fn convert_path_separator < ' a > (
235+ #[ allow( clippy:: get_first) ]
236+ fn convert_path < ' a > (
239237 & self ,
240238 os_str : Cow < ' a , OsStr > ,
241239 direction : PathConversion ,
242240 ) -> Cow < ' a , OsStr > {
243241 let this = self . eval_context_ref ( ) ;
244242 let target_os = & this. tcx . sess . target . os ;
243+
245244 #[ cfg( windows) ]
246245 return if target_os == "windows" {
247246 // Windows-on-Windows, all fine.
@@ -252,24 +251,71 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
252251 PathConversion :: HostToTarget => ( '\\' , '/' ) ,
253252 PathConversion :: TargetToHost => ( '/' , '\\' ) ,
254253 } ;
255- let converted = os_str
254+ let mut converted = os_str
256255 . encode_wide ( )
257256 . map ( |wchar| if wchar == from as u16 { to as u16 } else { wchar } )
258257 . collect :: < Vec < _ > > ( ) ;
258+ // We also have to ensure that absolute paths remain absolute.
259+ match direction {
260+ PathConversion :: HostToTarget => {
261+ // If this is an absolute Windows path that starts with a drive letter (`C:/...`
262+ // after separator conversion), it would not be considered absolute by Unix
263+ // target code.
264+ if converted. get ( 1 ) . copied ( ) == Some ( b':' as u16 )
265+ && converted. get ( 2 ) . copied ( ) == Some ( b'/' as u16 )
266+ {
267+ // We add a `/` at the beginning, to store the absolute Windows
268+ // path in something that looks like an absolute Unix path.
269+ converted. insert ( 0 , b'/' as u16 ) ;
270+ }
271+ }
272+ PathConversion :: TargetToHost => {
273+ // If the path is `\C:\`, the leading backslash was probably added by the above code
274+ // and we should get rid of it again.
275+ if converted. get ( 0 ) . copied ( ) == Some ( b'\\' as u16 )
276+ && converted. get ( 2 ) . copied ( ) == Some ( b':' as u16 )
277+ && converted. get ( 3 ) . copied ( ) == Some ( b'\\' as u16 )
278+ {
279+ converted. remove ( 0 ) ;
280+ }
281+ }
282+ }
259283 Cow :: Owned ( OsString :: from_wide ( & converted) )
260284 } ;
261285 #[ cfg( unix) ]
262286 return if target_os == "windows" {
263287 // Windows target, Unix host.
264288 let ( from, to) = match direction {
265- PathConversion :: HostToTarget => ( '/' , '\\' ) ,
266- PathConversion :: TargetToHost => ( '\\' , '/' ) ,
289+ PathConversion :: HostToTarget => ( b '/', b '\\') ,
290+ PathConversion :: TargetToHost => ( b '\\', b '/') ,
267291 } ;
268- let converted = os_str
292+ let mut converted = os_str
269293 . as_bytes ( )
270294 . iter ( )
271- . map ( |& wchar| if wchar == from as u8 { to as u8 } else { wchar } )
295+ . map ( |& wchar| if wchar == from { to } else { wchar } )
272296 . collect :: < Vec < _ > > ( ) ;
297+ // We also have to ensure that absolute paths remain absolute.
298+ match direction {
299+ PathConversion :: HostToTarget => {
300+ // If this start withs a `\`, we add `\\?` so it starts with `\\?\` which is
301+ // some magic path on Windos that *is* considered absolute.
302+ if converted. get ( 0 ) . copied ( ) == Some ( b'\\' ) {
303+ converted. splice ( 0 ..0 , b"\\ \\ ?" . iter ( ) . copied ( ) ) ;
304+ }
305+ }
306+ PathConversion :: TargetToHost => {
307+ // If this starts with `//?/`, it was probably produced by the above code and we
308+ // remove the `//?` that got added to get the Unix path back out.
309+ if converted. get ( 0 ) . copied ( ) == Some ( b'/' )
310+ && converted. get ( 1 ) . copied ( ) == Some ( b'/' )
311+ && converted. get ( 2 ) . copied ( ) == Some ( b'?' )
312+ && converted. get ( 3 ) . copied ( ) == Some ( b'/' )
313+ {
314+ // Remove first 3 characters
315+ converted. splice ( 0 ..3 , std:: iter:: empty ( ) ) ;
316+ }
317+ }
318+ }
273319 Cow :: Owned ( OsString :: from_vec ( converted) )
274320 } else {
275321 // Unix-on-Unix, all is fine.
0 commit comments