Skip to content

Commit ecb6503

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 856e411 + 66c894e commit ecb6503

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
@@ -1741,9 +1741,9 @@ mod traits {
17411741
}
17421742
#[inline]
17431743
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1744-
let ptr = slice.as_ptr().add(self.start);
1744+
let ptr = slice.as_mut_ptr().add(self.start);
17451745
let len = self.end - self.start;
1746-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
1746+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
17471747
}
17481748
#[inline]
17491749
fn index(self, slice: &str) -> &Self::Output {
@@ -1805,8 +1805,8 @@ mod traits {
18051805
}
18061806
#[inline]
18071807
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1808-
let ptr = slice.as_ptr();
1809-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
1808+
let ptr = slice.as_mut_ptr();
1809+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end))
18101810
}
18111811
#[inline]
18121812
fn index(self, slice: &str) -> &Self::Output {
@@ -1867,9 +1867,9 @@ mod traits {
18671867
}
18681868
#[inline]
18691869
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1870-
let ptr = slice.as_ptr().add(self.start);
1870+
let ptr = slice.as_mut_ptr().add(self.start);
18711871
let len = slice.len() - self.start;
1872-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
1872+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
18731873
}
18741874
#[inline]
18751875
fn index(self, slice: &str) -> &Self::Output {
@@ -2197,6 +2197,22 @@ impl str {
21972197
self as *const str as *const u8
21982198
}
21992199

2200+
/// Converts a mutable string slice to a raw pointer.
2201+
///
2202+
/// As string slices are a slice of bytes, the raw pointer points to a
2203+
/// [`u8`]. This pointer will be pointing to the first byte of the string
2204+
/// slice.
2205+
///
2206+
/// It is your responsibility to make sure that the string slice only gets
2207+
/// modified in a way that it remains valid UTF-8.
2208+
///
2209+
/// [`u8`]: primitive.u8.html
2210+
#[unstable(feature = "str_as_mut_ptr", issue = "58215")]
2211+
#[inline]
2212+
pub fn as_mut_ptr(&mut self) -> *mut u8 {
2213+
self as *mut str as *mut u8
2214+
}
2215+
22002216
/// Returns a subslice of `str`.
22012217
///
22022218
/// This is the non-panicking alternative to indexing the `str`. Returns
@@ -2484,7 +2500,7 @@ impl str {
24842500
// is_char_boundary checks that the index is in [0, .len()]
24852501
if self.is_char_boundary(mid) {
24862502
let len = self.len();
2487-
let ptr = self.as_ptr() as *mut u8;
2503+
let ptr = self.as_mut_ptr();
24882504
unsafe {
24892505
(from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
24902506
from_utf8_unchecked_mut(slice::from_raw_parts_mut(

0 commit comments

Comments
 (0)