Skip to content

Commit 03f1ce4

Browse files
committed
Windows targets: make sure current_dir is absolute
1 parent 9db5511 commit 03f1ce4

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

src/shims/os_str.rs

+33-12
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
232232
this.alloc_os_str_as_c_str(&os_str, memkind)
233233
}
234234

235+
#[allow(clippy::get_first)]
235236
fn convert_path<'a>(
236237
&self,
237238
os_str: Cow<'a, OsStr>,
@@ -260,20 +261,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
260261
// If this is an absolute Windows path that starts with a drive letter (`C:/...`
261262
// after separator conversion), it would not be considered absolute by Unix
262263
// target code.
263-
if converted.get(1).copied() == Some(':' as u16)
264-
&& converted.get(2).copied() == Some('/' as u16)
264+
if converted.get(1).copied() == Some(b':' as u16)
265+
&& converted.get(2).copied() == Some(b'/' as u16)
265266
{
266267
// We add a `/` at the beginning, to store the absolute Windows
267268
// path in something that looks like an absolute Unix path.
268-
converted.insert(0, '/' as u16);
269+
converted.insert(0, b'/' as u16);
269270
}
270271
}
271272
PathConversion::TargetToHost => {
272273
// If the path is `\C:\`, the leading backslash was probably added by the above code
273274
// and we should get rid of it again.
274-
if converted.get(0).copied() == Some('\\' as u16)
275-
&& converted.get(2).copied() == Some(':' as u16)
276-
&& converted.get(3).copied() == Some('\\' as u16)
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)
277278
{
278279
converted.remove(0);
279280
}
@@ -285,16 +286,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
285286
return if target_os == "windows" {
286287
// Windows target, Unix host.
287288
let (from, to) = match direction {
288-
PathConversion::HostToTarget => ('/', '\\'),
289-
PathConversion::TargetToHost => ('\\', '/'),
289+
PathConversion::HostToTarget => (b'/', b'\\'),
290+
PathConversion::TargetToHost => (b'\\', b'/'),
290291
};
291-
let converted = os_str
292+
let mut converted = os_str
292293
.as_bytes()
293294
.iter()
294-
.map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar })
295+
.map(|&wchar| if wchar == from { to } else { wchar })
295296
.collect::<Vec<_>>();
296-
// TODO: Once we actually support file system things on Windows targets, we'll probably
297-
// have to also do something clever for absolute path preservation here, like above.
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+
}
298319
Cow::Owned(OsString::from_vec(converted))
299320
} else {
300321
// Unix-on-Unix, all is fine.

0 commit comments

Comments
 (0)