From dab02ccfbf890ef8d6be069a6fd280913b0661a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Dec 2022 22:34:45 +0100 Subject: [PATCH] Windows targets: make sure current_dir is absolute --- src/shims/os_str.rs | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index e42ebc187b..af6e9034f0 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -232,6 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.alloc_os_str_as_c_str(&os_str, memkind) } + #[allow(clippy::get_first)] fn convert_path<'a>( &self, os_str: Cow<'a, OsStr>, @@ -252,7 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { }; let mut converted = os_str .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .map(|wchar| if wchar == from.into() { to.into() } else { wchar }) .collect::>(); // We also have to ensure that absolute paths remain absolute. match direction { @@ -260,20 +261,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // If this is an absolute Windows path that starts with a drive letter (`C:/...` // after separator conversion), it would not be considered absolute by Unix // target code. - if converted.get(1).copied() == Some(':' as u16) - && converted.get(2).copied() == Some('/' as u16) + if converted.get(1).copied() == Some(b':'.into()) + && converted.get(2).copied() == Some(b'/'.into()) { // We add a `/` at the beginning, to store the absolute Windows // path in something that looks like an absolute Unix path. - converted.insert(0, '/' as u16); + converted.insert(0, b'/'.into()); } } PathConversion::TargetToHost => { // If the path is `\C:\`, the leading backslash was probably added by the above code // and we should get rid of it again. - if converted.get(0).copied() == Some('\\' as u16) - && converted.get(2).copied() == Some(':' as u16) - && converted.get(3).copied() == Some('\\' as u16) + if converted.get(0).copied() == Some(b'\\'.into()) + && converted.get(2).copied() == Some(b':'.into()) + && converted.get(3).copied() == Some(b'\\'.into()) { converted.remove(0); } @@ -288,13 +289,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { PathConversion::HostToTarget => ('/', '\\'), PathConversion::TargetToHost => ('\\', '/'), }; - let converted = os_str + let mut converted = os_str .as_bytes() .iter() .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) .collect::>(); - // TODO: Once we actually support file system things on Windows targets, we'll probably - // have to also do something clever for absolute path preservation here, like above. + // We also have to ensure that absolute paths remain absolute. + match direction { + PathConversion::HostToTarget => { + // If this start withs a `\`, we add `\\.` so it starts with `\\.\` which is + // some magic path on Windos that *is* considered absolute. + if converted.get(0).copied() == Some(b'\\') { + converted.splice(0..0, b"\\\\.".iter().copied()); + } + } + PathConversion::TargetToHost => { + // If this starts with `//./`, it was probably added by the above code and we + // remove the `//.` that got added to get the Unix path back out. + if converted.get(0).copied() == Some(b'/') + && converted.get(1).copied() == Some(b'/') + && converted.get(2).copied() == Some(b'.') + && converted.get(3).copied() == Some(b'/') + { + // Remove first 3 characters + converted.splice(0..3, std::iter::empty()); + } + } + } Cow::Owned(OsString::from_vec(converted)) } else { // Unix-on-Unix, all is fine.