Skip to content
/ rust Public
forked from rust-lang/rust

Commit

Permalink
Rollup merge of rust-lang#124410 - RalfJung:path-buf-transmute, r=Nil…
Browse files Browse the repository at this point in the history
…strieb

PathBuf: replace transmuting by accessor functions

The existing `repr(transparent)` was anyway insufficient as `OsString` was not `repr(transparent)`. And furthermore, on Windows it was blatantly wrong as `OsString` wraps `Wtf8Buf` which is a `repr(Rust)` type with 2 fields:

https://github.com/rust-lang/rust/blob/51a7396ad3d78d9326ee1537b9ff29ab3919556f/library/std/src/sys_common/wtf8.rs#L131-L146

So let's just be honest about what happens and add accessor methods that make this abstraction-breaking act of PathBuf visible on the APIs that it pierces through.

Fixes rust-lang#124409
  • Loading branch information
jhpratt authored Apr 26, 2024
2 parents 7cb7337 + c47978a commit 7cbba53
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 7 deletions.
6 changes: 6 additions & 0 deletions library/std/src/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,12 @@ impl OsString {
let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr;
unsafe { Box::from_raw(rw) }
}

/// Part of a hack to make PathBuf::push/pop more efficient.
#[inline]
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
self.inner.as_mut_vec_for_path_buf()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
8 changes: 1 addition & 7 deletions library/std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1158,20 +1158,14 @@ impl FusedIterator for Ancestors<'_> {}
/// Which method works best depends on what kind of situation you're in.
#[cfg_attr(not(test), rustc_diagnostic_item = "PathBuf")]
#[stable(feature = "rust1", since = "1.0.0")]
// `PathBuf::as_mut_vec` current implementation relies
// on `PathBuf` being layout-compatible with `Vec<u8>`.
// However, `PathBuf` layout is considered an implementation detail and must not be relied upon. We
// want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
// `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
#[cfg_attr(not(doc), repr(transparent))]
pub struct PathBuf {
inner: OsString,
}

impl PathBuf {
#[inline]
fn as_mut_vec(&mut self) -> &mut Vec<u8> {
unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
self.inner.as_mut_vec_for_path_buf()
}

/// Allocates an empty `PathBuf`.
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/os_str/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ impl Buf {
pub fn into_rc(&self) -> Rc<Slice> {
self.as_slice().into_rc()
}

/// Part of a hack to make PathBuf::push/pop more efficient.
#[inline]
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
&mut self.inner
}
}

impl Slice {
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/os_str/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ impl Buf {
pub fn into_rc(&self) -> Rc<Slice> {
self.as_slice().into_rc()
}

/// Part of a hack to make PathBuf::push/pop more efficient.
#[inline]
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
self.inner.as_mut_vec_for_path_buf()
}
}

impl Slice {
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys_common/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ impl Wtf8Buf {
let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false }
}

/// Part of a hack to make PathBuf::push/pop more efficient.
#[inline]
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
&mut self.bytes
}
}

/// Creates a new WTF-8 string from an iterator of code points.
Expand Down

0 comments on commit 7cbba53

Please sign in to comment.