Skip to content

Commit e6c378f

Browse files
committed
Auto merge of rust-lang#125966 - schvv31n:impl_os_string_pathbuf_leak, r=workingjubilee
Implement `os_string_pathbuf_leak` implementation of rust-lang#125965 ACP: rust-lang/libs-team#389 [ Accepted ]
2 parents 67454f5 + 20f15f4 commit e6c378f

File tree

7 files changed

+72
-0
lines changed

7 files changed

+72
-0
lines changed

std/src/ffi/os_str.rs

+19
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,25 @@ impl OsString {
533533
unsafe { Box::from_raw(rw) }
534534
}
535535

536+
/// Consumes and leaks the `OsString`, returning a mutable reference to the contents,
537+
/// `&'a mut OsStr`.
538+
///
539+
/// The caller has free choice over the returned lifetime, including 'static.
540+
/// Indeed, this function is ideally used for data that lives for the remainder of
541+
/// the program’s life, as dropping the returned reference will cause a memory leak.
542+
///
543+
/// It does not reallocate or shrink the `OsString`, so the leaked allocation may include
544+
/// unused capacity that is not part of the returned slice. If you want to discard excess
545+
/// capacity, call [`into_boxed_os_str`], and then [`Box::leak`] instead.
546+
/// However, keep in mind that trimming the capacity may result in a reallocation and copy.
547+
///
548+
/// [`into_boxed_os_str`]: Self::into_boxed_os_str
549+
#[unstable(feature = "os_string_pathbuf_leak", issue = "125965")]
550+
#[inline]
551+
pub fn leak<'a>(self) -> &'a mut OsStr {
552+
OsStr::from_inner_mut(self.inner.leak())
553+
}
554+
536555
/// Part of a hack to make PathBuf::push/pop more efficient.
537556
#[inline]
538557
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {

std/src/ffi/os_str/tests.rs

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ fn test_os_string_clear() {
2323
assert_eq!(0, os_string.inner.as_inner().len());
2424
}
2525

26+
#[test]
27+
fn test_os_string_leak() {
28+
let os_string = OsString::from("have a cake");
29+
let (len, cap) = (os_string.len(), os_string.capacity());
30+
let leaked = os_string.leak();
31+
assert_eq!(leaked.as_encoded_bytes(), b"have a cake");
32+
unsafe { drop(String::from_raw_parts(leaked as *mut OsStr as _, len, cap)) }
33+
}
34+
2635
#[test]
2736
fn test_os_string_capacity() {
2837
let os_string = OsString::with_capacity(0);

std/src/path.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,25 @@ impl PathBuf {
12261226
self
12271227
}
12281228

1229+
/// Consumes and leaks the `PathBuf`, returning a mutable reference to the contents,
1230+
/// `&'a mut Path`.
1231+
///
1232+
/// The caller has free choice over the returned lifetime, including 'static.
1233+
/// Indeed, this function is ideally used for data that lives for the remainder of
1234+
/// the program’s life, as dropping the returned reference will cause a memory leak.
1235+
///
1236+
/// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include
1237+
/// unused capacity that is not part of the returned slice. If you want to discard excess
1238+
/// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead.
1239+
/// However, keep in mind that trimming the capacity may result in a reallocation and copy.
1240+
///
1241+
/// [`into_boxed_path`]: Self::into_boxed_path
1242+
#[unstable(feature = "os_string_pathbuf_leak", issue = "125965")]
1243+
#[inline]
1244+
pub fn leak<'a>(self) -> &'a mut Path {
1245+
Path::from_inner_mut(self.inner.leak())
1246+
}
1247+
12291248
/// Extends `self` with `path`.
12301249
///
12311250
/// If `path` is absolute, it replaces the current path.

std/src/path/tests.rs

+10
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ fn into() {
126126
assert_eq!(static_cow_path, owned_cow_path);
127127
}
128128

129+
#[test]
130+
fn test_pathbuf_leak() {
131+
let string = "/have/a/cake".to_owned();
132+
let (len, cap) = (string.len(), string.capacity());
133+
let buf = PathBuf::from(string);
134+
let leaked = buf.leak();
135+
assert_eq!(leaked.as_os_str().as_encoded_bytes(), b"/have/a/cake");
136+
unsafe { drop(String::from_raw_parts(leaked.as_mut_os_str() as *mut OsStr as _, len, cap)) }
137+
}
138+
129139
#[test]
130140
#[cfg(unix)]
131141
pub fn test_decompositions_unix() {

std/src/sys/os_str/bytes.rs

+5
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ impl Buf {
176176
self.inner.extend_from_slice(&s.inner)
177177
}
178178

179+
#[inline]
180+
pub fn leak<'a>(self) -> &'a mut Slice {
181+
unsafe { mem::transmute(self.inner.leak()) }
182+
}
183+
179184
#[inline]
180185
pub fn into_box(self) -> Box<Slice> {
181186
unsafe { mem::transmute(self.inner.into_boxed_slice()) }

std/src/sys/os_str/wtf8.rs

+5
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ impl Buf {
138138
self.inner.shrink_to(min_capacity)
139139
}
140140

141+
#[inline]
142+
pub fn leak<'a>(self) -> &'a mut Slice {
143+
unsafe { mem::transmute(self.inner.leak()) }
144+
}
145+
141146
#[inline]
142147
pub fn into_box(self) -> Box<Slice> {
143148
unsafe { mem::transmute(self.inner.into_box()) }

std/src/sys_common/wtf8.rs

+5
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ impl Wtf8Buf {
325325
self.bytes.shrink_to(min_capacity)
326326
}
327327

328+
#[inline]
329+
pub fn leak<'a>(self) -> &'a mut Wtf8 {
330+
unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) }
331+
}
332+
328333
/// Returns the number of bytes that this string buffer can hold without reallocating.
329334
#[inline]
330335
pub fn capacity(&self) -> usize {

0 commit comments

Comments
 (0)