From 0f3d1b805a27710d6ef23e2e2d873e9420951266 Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sat, 28 May 2022 12:40:26 +0200
Subject: [PATCH] Add `as_ptr` and `as_mut_ptr` inherent method to `String`

Before, they went through `&str` and `&mut str`, which created
intermediary references, shrinking provenance to only the initialized
parts. `Vec<T>` already has such inherent methods added in #61114.
---
 library/alloc/src/string.rs   | 75 +++++++++++++++++++++++++++++++++++
 library/alloc/tests/string.rs | 19 +++++++++
 2 files changed, 94 insertions(+)

diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 668af60611b86..9cc6f5d755776 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1612,6 +1612,81 @@ impl String {
         &mut self.vec
     }
 
+    /// Returns a raw pointer to the string's buffer.
+    ///
+    /// The caller must ensure that the string outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the string may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// The caller must also ensure that the memory the pointer (non-transitively) points to
+    /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+    /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x = "012".to_string();
+    /// let x_ptr = x.as_ptr();
+    ///
+    /// unsafe {
+    ///     for i in 0..x.len() {
+    ///         assert_eq!(*x_ptr.add(i), b'0' + u8::try_from(i).unwrap());
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// [`as_mut_ptr`]: String::as_mut_ptr
+    #[stable(feature = "string_as_ptr", since = "1.63.0")]
+    #[inline]
+    pub fn as_ptr(&self) -> *const u8 {
+        // We shadow the str method of the same name to avoid going through
+        // `deref`, which creates an intermediate reference.
+        self.vec.as_ptr()
+    }
+
+    /// Returns an unsafe mutable pointer to the string's buffer.
+    ///
+    /// The caller must ensure that the string outlives the pointer this
+    /// function returns, or else it will end up pointing to garbage.
+    /// Modifying the string may cause its buffer to be reallocated,
+    /// which would also make any pointers to it invalid.
+    ///
+    /// The caller must also guarantee to not write invalid UTF-8 to the
+    /// initialized part of the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # use core::mem::ManuallyDrop;
+    ///
+    /// // Allocate String big enough for 4 elements.
+    /// let size = 4;
+    /// // use a ManuallyDrop to avoid a double free
+    /// let mut x = ManuallyDrop::new(String::with_capacity(size));
+    /// let x_ptr = x.as_mut_ptr();
+    ///
+    /// // Initialize elements via raw pointer writes.
+    /// unsafe {
+    ///     for i in 0..size {
+    ///         *x_ptr.add(i) = b'A';
+    ///     }
+    /// }
+    ///
+    /// // Create a new String from the ptr
+    /// unsafe {
+    ///     let y = String::from_utf8_unchecked(Vec::from_raw_parts(x_ptr, size, size));
+    ///     assert_eq!(y.as_str(), "AAAA");
+    /// }
+    /// ```
+    #[stable(feature = "string_as_ptr", since = "1.63.0")]
+    #[inline]
+    pub fn as_mut_ptr(&mut self) -> *mut u8 {
+        // We shadow the str method of the same name to avoid going through
+        // `deref_mut`, which creates an intermediate reference.
+        self.vec.as_mut_ptr()
+    }
+
     /// Returns the length of this `String`, in bytes, not [`char`]s or
     /// graphemes. In other words, it might not be what a human considers the
     /// length of the string.
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index b6836fdc88ee8..aae31a30f9dfd 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -874,3 +874,22 @@ fn test_str_concat() {
     let s: String = format!("{a}{b}");
     assert_eq!(s.as_bytes()[9], 'd' as u8);
 }
+
+#[test]
+fn test_string_as_mut_ptr_roundtrip() {
+    // Allocate String big enough for 4 elements.
+    let cap = 4;
+    // use a ManuallyDrop to avoid a double free
+    let mut x = std::mem::ManuallyDrop::new(String::with_capacity(cap));
+    let x_ptr = x.as_mut_ptr();
+
+    // Create a new String from the ptr
+    // Because as_mut_ptr goes through Vec::as_mut_ptr, it has provenance for the entire allocation
+    let mut y = unsafe { String::from_utf8_unchecked(Vec::from_raw_parts(x_ptr, 0, cap)) };
+    // We have provenance to write to the empty capacity
+    y.push_str("uwu");
+    assert_eq!(y.as_str(), "uwu");
+
+    y.push('!');
+    assert_eq!(y.as_str(), "uwu!");
+}