@@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
174
174
let this = self . eval_context_ref ( ) ;
175
175
let os_str = this. read_os_str_from_c_str ( ptr) ?;
176
176
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 ) {
178
178
Cow :: Borrowed ( x) => Cow :: Borrowed ( Path :: new ( x) ) ,
179
179
Cow :: Owned ( y) => Cow :: Owned ( PathBuf :: from ( y) ) ,
180
180
} )
@@ -188,10 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
188
188
let this = self . eval_context_ref ( ) ;
189
189
let os_str = this. read_os_str_from_wide_str ( ptr) ?;
190
190
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 ( ) )
195
192
}
196
193
197
194
/// 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> {
203
200
size : u64 ,
204
201
) -> InterpResult < ' tcx , ( bool , u64 ) > {
205
202
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 ) ;
208
205
this. write_os_str_to_c_str ( & os_str, ptr, size)
209
206
}
210
207
@@ -217,8 +214,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
217
214
size : u64 ,
218
215
) -> InterpResult < ' tcx , ( bool , u64 ) > {
219
216
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 ) ;
222
219
this. write_os_str_to_wide_str ( & os_str, ptr, size)
223
220
}
224
221
@@ -230,18 +227,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
230
227
memkind : MemoryKind < MiriMemoryKind > ,
231
228
) -> InterpResult < ' tcx , Pointer < Option < Provenance > > > {
232
229
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 ) ;
235
232
this. alloc_os_str_as_c_str ( & os_str, memkind)
236
233
}
237
234
238
- fn convert_path_separator < ' a > (
235
+ #[ allow( clippy:: get_first) ]
236
+ fn convert_path < ' a > (
239
237
& self ,
240
238
os_str : Cow < ' a , OsStr > ,
241
239
direction : PathConversion ,
242
240
) -> Cow < ' a , OsStr > {
243
241
let this = self . eval_context_ref ( ) ;
244
242
let target_os = & this. tcx . sess . target . os ;
243
+
245
244
#[ cfg( windows) ]
246
245
return if target_os == "windows" {
247
246
// Windows-on-Windows, all fine.
@@ -252,24 +251,71 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
252
251
PathConversion :: HostToTarget => ( '\\' , '/' ) ,
253
252
PathConversion :: TargetToHost => ( '/' , '\\' ) ,
254
253
} ;
255
- let converted = os_str
254
+ let mut converted = os_str
256
255
. encode_wide ( )
257
256
. map ( |wchar| if wchar == from as u16 { to as u16 } else { wchar } )
258
257
. 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
+ }
259
283
Cow :: Owned ( OsString :: from_wide ( & converted) )
260
284
} ;
261
285
#[ cfg( unix) ]
262
286
return if target_os == "windows" {
263
287
// Windows target, Unix host.
264
288
let ( from, to) = match direction {
265
- PathConversion :: HostToTarget => ( '/' , '\\' ) ,
266
- PathConversion :: TargetToHost => ( '\\' , '/' ) ,
289
+ PathConversion :: HostToTarget => ( b '/', b '\\') ,
290
+ PathConversion :: TargetToHost => ( b '\\', b '/') ,
267
291
} ;
268
- let converted = os_str
292
+ let mut converted = os_str
269
293
. as_bytes ( )
270
294
. iter ( )
271
- . map ( |& wchar| if wchar == from as u8 { to as u8 } else { wchar } )
295
+ . map ( |& wchar| if wchar == from { to } else { wchar } )
272
296
. 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
+ }
273
319
Cow :: Owned ( OsString :: from_vec ( converted) )
274
320
} else {
275
321
// Unix-on-Unix, all is fine.
0 commit comments