From ef2957de137fb8d6959310e5d8f2fa1d600d7d36 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 13:13:07 -0400 Subject: [PATCH 1/6] allowing getting &mut OsStr from OsString --- src/libstd/ffi/os_str.rs | 21 +++++++++++++++++++++ src/libstd/sys/windows/os_str.rs | 5 +++++ src/libstd/sys_common/os_str_bytes.rs | 5 +++++ 3 files changed, 31 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 77da97219b147..2f921ce7a5fe4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -379,6 +379,14 @@ impl ops::Index for OsString { } } +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::IndexMut for OsString { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr { + OsStr::from_inner_mut(self.inner.as_mut_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Deref for OsString { type Target = OsStr; @@ -389,6 +397,14 @@ impl ops::Deref for OsString { } } +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::DerefMut for OsString { + #[inline] + fn deref_mut(&mut self) -> &mut OsStr { + &mut self[..] + } +} + #[stable(feature = "osstring_default", since = "1.9.0")] impl Default for OsString { /// Constructs an empty `OsString`. @@ -512,6 +528,11 @@ impl OsStr { unsafe { &*(inner as *const Slice as *const OsStr) } } + #[inline] + fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + unsafe { &mut *(inner as *mut Slice as *mut OsStr) } + } + /// Yields a [`&str`] slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index ef260f9c5d21f..4cff23b2f4a09 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -80,6 +80,11 @@ impl Buf { unsafe { mem::transmute(self.inner.as_slice()) } } + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + unsafe { mem::transmute(self.inner.as_mut_slice()) } + } + pub fn into_string(self) -> Result { self.inner.into_string().map_err(|buf| Buf { inner: buf }) } diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index e965ea79aa039..5767350336dad 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -109,6 +109,11 @@ impl Buf { unsafe { mem::transmute(&*self.inner) } } + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + unsafe { mem::transmute(&mut *self.inner) } + } + pub fn into_string(self) -> Result { String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) } From 21975a1aaa682a88266970459f6f67829774d6c4 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:12:54 -0400 Subject: [PATCH 2/6] add comments about safety --- src/libstd/ffi/os_str.rs | 4 ++++ src/libstd/sys/windows/os_str.rs | 6 ++++++ src/libstd/sys_common/os_str_bytes.rs | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 2f921ce7a5fe4..45417403c1084 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -525,11 +525,15 @@ impl OsStr { #[inline] fn from_inner(inner: &Slice) -> &OsStr { + // Safety: OsStr is just a wrapper of Slice, + // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + // Safety: OsStr is just a wrapper of Slice, + // therefore converting &mut Slice to &mut OsStr is safe. unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 4cff23b2f4a09..e768d9c326b0a 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -77,11 +77,17 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and as_slice returns &Wtf8. Therefore, + // transmute &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and as_slice returns &Wtf8. Therefore, + // transmute &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index 5767350336dad..c5d02fb17722f 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -106,11 +106,17 @@ impl Buf { #[inline] pub fn as_slice(&self) -> &Slice { + // Safety: Slice just wraps [u8], + // and &*self.inner is &[u8], therefore + // transmuting &[u8] to &Slice is safe. unsafe { mem::transmute(&*self.inner) } } #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { + // Safety: Slice just wraps [u8], + // and &mut *self.inner is &mut [u8], therefore + // transmuting &mut [u8] to &mut Slice is safe. unsafe { mem::transmute(&mut *self.inner) } } From cce8ee8bf7dbf461872d72c8b29302242bb11701 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:15:13 -0400 Subject: [PATCH 3/6] remove #[inline] for consistency in windows/os_str --- src/libstd/sys/windows/os_str.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index e768d9c326b0a..cd0eaaef5b669 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -83,7 +83,6 @@ impl Buf { unsafe { mem::transmute(self.inner.as_slice()) } } - #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, // and as_slice returns &Wtf8. Therefore, From 16712ede6202067d0c1b2e23ad95b87e0afd7191 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:18:35 -0400 Subject: [PATCH 4/6] corrections on safety comments --- src/libstd/sys/windows/os_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index cd0eaaef5b669..9142b42f55858 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -79,14 +79,14 @@ impl Buf { pub fn as_slice(&self) -> &Slice { // Safety: Slice is just a wrapper for Wtf8, // and as_slice returns &Wtf8. Therefore, - // transmute &Wtf8 to &Slice is safe. + // transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_slice returns &Wtf8. Therefore, - // transmute &mut Wtf8 to &mut Slice is safe. + // and as_mut_slice returns &mut Wtf8. Therefore, + // transmuting &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } From e4a65e83e7ce89ce7a015753a4b8d989416ae2a8 Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Mon, 16 Mar 2020 16:22:49 -0400 Subject: [PATCH 5/6] make safety comments more explicit --- src/libstd/sys/windows/os_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 9142b42f55858..2820d2b5fe967 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -78,15 +78,15 @@ impl Buf { pub fn as_slice(&self) -> &Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_slice returns &Wtf8. Therefore, - // transmuting &Wtf8 to &Slice is safe. + // and self.inner.as_slice() returns &Wtf8. + // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { // Safety: Slice is just a wrapper for Wtf8, - // and as_mut_slice returns &mut Wtf8. Therefore, - // transmuting &mut Wtf8 to &mut Slice is safe. + // and self.inner.as_mut_slice() returns &mut Wtf8. + // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. unsafe { mem::transmute(self.inner.as_mut_slice()) } } From 45416cd91a6bdc493ea62fb3f412713a0fd8e52e Mon Sep 17 00:00:00 2001 From: TyPR124 Date: Fri, 20 Mar 2020 09:00:53 -0400 Subject: [PATCH 6/6] add comment about maintaining OsStr encoding --- src/libstd/ffi/os_str.rs | 2 ++ src/libstd/sys/windows/os_str.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 45417403c1084..0fbe8e5dd83e8 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -534,6 +534,8 @@ impl OsStr { fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { // Safety: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. + // Any method that mutates OsStr must be careful not to + // break platform-specific encoding, in particular Wtf8 on Windows. unsafe { &mut *(inner as *mut Slice as *mut OsStr) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 2820d2b5fe967..ff6885cb27477 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -87,6 +87,8 @@ impl Buf { // Safety: Slice is just a wrapper for Wtf8, // and self.inner.as_mut_slice() returns &mut Wtf8. // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. + // Additionally, care should be taken to ensure the slice + // is always valid Wtf8. unsafe { mem::transmute(self.inner.as_mut_slice()) } }