Skip to content

Commit cedbe5c

Browse files
committed
Auto merge of #113859 - Manishearth:vec-as-mut-ptr-stacked-borrow, r=dtolnay
Add note that Vec::as_mut_ptr() does not materialize a reference to the internal buffer See discussion on thomcc/rust-typed-arena#62 and [t-opsem](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/is.20this.20typed_arena.20code.20sound.20under.20stacked.2Ftree.20borrows.3F) This method already does the correct thing here, but it is worth guaranteeing that it does so it can be used more freely in unsafe code without having to worry about potential Stacked/Tree Borrows violations. This moves one more unsafe usage pattern from the "very likely sound but technically not fully defined" box into "definitely sound", and currently our surface area of the latter is woefully small. I'm not sure how best to word this, opening this PR as a way to start discussion.
2 parents a517049 + 7cea69c commit cedbe5c

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

library/alloc/src/vec/mod.rs

+51
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,15 @@ impl<T, A: Allocator> Vec<T, A> {
12181218
/// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
12191219
/// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
12201220
///
1221+
/// This method guarantees that for the purpose of the aliasing model, this method
1222+
/// does not materialize a reference to the underlying slice, and thus the returned pointer
1223+
/// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
1224+
/// Note that calling other methods that materialize mutable references to the slice,
1225+
/// or mutable references to specific elements you are planning on accessing through this pointer,
1226+
/// as well as writing to those elements, may still invalidate this pointer.
1227+
/// See the second example below for how this guarantee can be used.
1228+
///
1229+
///
12211230
/// # Examples
12221231
///
12231232
/// ```
@@ -1231,7 +1240,23 @@ impl<T, A: Allocator> Vec<T, A> {
12311240
/// }
12321241
/// ```
12331242
///
1243+
/// Due to the aliasing guarantee, the following code is legal:
1244+
///
1245+
/// ```rust
1246+
/// unsafe {
1247+
/// let mut v = vec![0, 1, 2];
1248+
/// let ptr1 = v.as_ptr();
1249+
/// let _ = ptr1.read();
1250+
/// let ptr2 = v.as_mut_ptr().offset(2);
1251+
/// ptr2.write(2);
1252+
/// // Notably, the write to `ptr2` did *not* invalidate `ptr1`
1253+
/// // because it mutated a different element:
1254+
/// let _ = ptr1.read();
1255+
/// }
1256+
/// ```
1257+
///
12341258
/// [`as_mut_ptr`]: Vec::as_mut_ptr
1259+
/// [`as_ptr`]: Vec::as_ptr
12351260
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
12361261
#[inline]
12371262
pub fn as_ptr(&self) -> *const T {
@@ -1248,6 +1273,15 @@ impl<T, A: Allocator> Vec<T, A> {
12481273
/// Modifying the vector may cause its buffer to be reallocated,
12491274
/// which would also make any pointers to it invalid.
12501275
///
1276+
/// This method guarantees that for the purpose of the aliasing model, this method
1277+
/// does not materialize a reference to the underlying slice, and thus the returned pointer
1278+
/// will remain valid when mixed with other calls to [`as_ptr`] and [`as_mut_ptr`].
1279+
/// Note that calling other methods that materialize references to the slice,
1280+
/// or references to specific elements you are planning on accessing through this pointer,
1281+
/// may still invalidate this pointer.
1282+
/// See the second example below for how this guarantee can be used.
1283+
///
1284+
///
12511285
/// # Examples
12521286
///
12531287
/// ```
@@ -1265,6 +1299,23 @@ impl<T, A: Allocator> Vec<T, A> {
12651299
/// }
12661300
/// assert_eq!(&*x, &[0, 1, 2, 3]);
12671301
/// ```
1302+
///
1303+
/// Due to the aliasing guarantee, the following code is legal:
1304+
///
1305+
/// ```rust
1306+
/// unsafe {
1307+
/// let mut v = vec![0];
1308+
/// let ptr1 = v.as_mut_ptr();
1309+
/// ptr1.write(1);
1310+
/// let ptr2 = v.as_mut_ptr();
1311+
/// ptr2.write(2);
1312+
/// // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
1313+
/// ptr1.write(3);
1314+
/// }
1315+
/// ```
1316+
///
1317+
/// [`as_mut_ptr`]: Vec::as_mut_ptr
1318+
/// [`as_ptr`]: Vec::as_ptr
12681319
#[stable(feature = "vec_as_ptr", since = "1.37.0")]
12691320
#[inline]
12701321
pub fn as_mut_ptr(&mut self) -> *mut T {

0 commit comments

Comments
 (0)