Skip to content

Commit 17ca18c

Browse files
authored
Rollup merge of rust-lang#58200 - RalfJung:str-as-mut-ptr, r=SimonSapin
fix str mutating through a ptr derived from &self Found by Miri: In `get_unchecked_mut` (also used by the checked variants internally) uses `str::as_ptr` to create a mutable reference, but `as_ptr` takes `&self`. This means the mutable references we return here got created from a shared reference, which violates the shared-references-are-read-only discipline! For this by using a newly introduced `as_mut_ptr` instead.
2 parents a92a40d + 66c894e commit 17ca18c

File tree

1 file changed

+23
-7
lines changed

1 file changed

+23
-7
lines changed

src/libcore/str/mod.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -1757,9 +1757,9 @@ mod traits {
17571757
}
17581758
#[inline]
17591759
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1760-
let ptr = slice.as_ptr().add(self.start);
1760+
let ptr = slice.as_mut_ptr().add(self.start);
17611761
let len = self.end - self.start;
1762-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
1762+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
17631763
}
17641764
#[inline]
17651765
fn index(self, slice: &str) -> &Self::Output {
@@ -1821,8 +1821,8 @@ mod traits {
18211821
}
18221822
#[inline]
18231823
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1824-
let ptr = slice.as_ptr();
1825-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
1824+
let ptr = slice.as_mut_ptr();
1825+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end))
18261826
}
18271827
#[inline]
18281828
fn index(self, slice: &str) -> &Self::Output {
@@ -1883,9 +1883,9 @@ mod traits {
18831883
}
18841884
#[inline]
18851885
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1886-
let ptr = slice.as_ptr().add(self.start);
1886+
let ptr = slice.as_mut_ptr().add(self.start);
18871887
let len = slice.len() - self.start;
1888-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
1888+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
18891889
}
18901890
#[inline]
18911891
fn index(self, slice: &str) -> &Self::Output {
@@ -2213,6 +2213,22 @@ impl str {
22132213
self as *const str as *const u8
22142214
}
22152215

2216+
/// Converts a mutable string slice to a raw pointer.
2217+
///
2218+
/// As string slices are a slice of bytes, the raw pointer points to a
2219+
/// [`u8`]. This pointer will be pointing to the first byte of the string
2220+
/// slice.
2221+
///
2222+
/// It is your responsibility to make sure that the string slice only gets
2223+
/// modified in a way that it remains valid UTF-8.
2224+
///
2225+
/// [`u8`]: primitive.u8.html
2226+
#[unstable(feature = "str_as_mut_ptr", issue = "58215")]
2227+
#[inline]
2228+
pub fn as_mut_ptr(&mut self) -> *mut u8 {
2229+
self as *mut str as *mut u8
2230+
}
2231+
22162232
/// Returns a subslice of `str`.
22172233
///
22182234
/// This is the non-panicking alternative to indexing the `str`. Returns
@@ -2500,7 +2516,7 @@ impl str {
25002516
// is_char_boundary checks that the index is in [0, .len()]
25012517
if self.is_char_boundary(mid) {
25022518
let len = self.len();
2503-
let ptr = self.as_ptr() as *mut u8;
2519+
let ptr = self.as_mut_ptr();
25042520
unsafe {
25052521
(from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
25062522
from_utf8_unchecked_mut(slice::from_raw_parts_mut(

0 commit comments

Comments
 (0)