Skip to content

Commit 70073ec

Browse files
committed
Auto merge of #53783 - RalfJung:ptr-docs, r=alexcrichton
Rewrite docs for pointer methods This takes over #51016 by @ecstatic-morse. They did most of the work, I just did some editing. However, I realized one problem: This updates the docs for the "free functions" in `core::ptr`, but it does not update the copies of these docs for the inherent methods of the `*const T` and `*mut T` types. These getting out-of-sync is certainly bad, but I also don't feel like copying all this stuff around. Instead, we should remove this redundancy. Any good ideas?
2 parents a072d1b + c197dc4 commit 70073ec

File tree

2 files changed

+701
-549
lines changed

2 files changed

+701
-549
lines changed

src/libcore/intrinsics.rs

+160-36
Original file line numberDiff line numberDiff line change
@@ -962,59 +962,127 @@ extern "rust-intrinsic" {
962962
/// value is not necessarily valid to be used to actually access memory.
963963
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
964964

965-
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
966-
/// and destination may *not* overlap.
965+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
966+
/// and destination must *not* overlap.
967967
///
968-
/// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
968+
/// For regions of memory which might overlap, use [`copy`] instead.
969+
///
970+
/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
971+
/// with the argument order swapped.
972+
///
973+
/// [`copy`]: ./fn.copy.html
974+
/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
969975
///
970976
/// # Safety
971977
///
972-
/// Beyond requiring that the program must be allowed to access both regions
973-
/// of memory, it is Undefined Behavior for source and destination to
974-
/// overlap. Care must also be taken with the ownership of `src` and
975-
/// `dst`. This method semantically moves the values of `src` into `dst`.
976-
/// However it does not drop the contents of `dst`, or prevent the contents
977-
/// of `src` from being dropped or used.
978+
/// Behavior is undefined if any of the following conditions are violated:
979+
///
980+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
981+
///
982+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
983+
///
984+
/// * Both `src` and `dst` must be properly aligned.
985+
///
986+
/// * The region of memory beginning at `src` with a size of `count *
987+
/// size_of::<T>()` bytes must *not* overlap with the region of memory
988+
/// beginning at `dst` with the same size.
989+
///
990+
/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of
991+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values
992+
/// in the region beginning at `*src` and the region beginning at `*dst` can
993+
/// [violate memory safety][read-ownership].
994+
///
995+
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
996+
/// `0`, the pointers must be non-NULL and properly aligned.
997+
///
998+
/// [`Copy`]: ../marker/trait.Copy.html
999+
/// [`read`]: ../ptr/fn.read.html
1000+
/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value
1001+
/// [valid]: ../ptr/index.html#safety
9781002
///
9791003
/// # Examples
9801004
///
981-
/// A safe swap function:
1005+
/// Manually implement [`Vec::append`]:
9821006
///
9831007
/// ```
984-
/// use std::mem;
9851008
/// use std::ptr;
9861009
///
987-
/// # #[allow(dead_code)]
988-
/// fn swap<T>(x: &mut T, y: &mut T) {
989-
/// unsafe {
990-
/// // Give ourselves some scratch space to work with
991-
/// let mut t: T = mem::uninitialized();
1010+
/// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
1011+
/// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
1012+
/// let src_len = src.len();
1013+
/// let dst_len = dst.len();
9921014
///
993-
/// // Perform the swap, `&mut` pointers never alias
994-
/// ptr::copy_nonoverlapping(x, &mut t, 1);
995-
/// ptr::copy_nonoverlapping(y, x, 1);
996-
/// ptr::copy_nonoverlapping(&t, y, 1);
1015+
/// // Ensure that `dst` has enough capacity to hold all of `src`.
1016+
/// dst.reserve(src_len);
9971017
///
998-
/// // y and t now point to the same thing, but we need to completely forget `t`
999-
/// // because it's no longer relevant.
1000-
/// mem::forget(t);
1018+
/// unsafe {
1019+
/// // The call to offset is always safe because `Vec` will never
1020+
/// // allocate more than `isize::MAX` bytes.
1021+
/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize);
1022+
/// let src_ptr = src.as_ptr();
1023+
///
1024+
/// // Truncate `src` without dropping its contents. We do this first,
1025+
/// // to avoid problems in case something further down panics.
1026+
/// src.set_len(0);
1027+
///
1028+
/// // The two regions cannot overlap becuase mutable references do
1029+
/// // not alias, and two different vectors cannot own the same
1030+
/// // memory.
1031+
/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len);
1032+
///
1033+
/// // Notify `dst` that it now holds the contents of `src`.
1034+
/// dst.set_len(dst_len + src_len);
10011035
/// }
10021036
/// }
1037+
///
1038+
/// let mut a = vec!['r'];
1039+
/// let mut b = vec!['u', 's', 't'];
1040+
///
1041+
/// append(&mut a, &mut b);
1042+
///
1043+
/// assert_eq!(a, &['r', 'u', 's', 't']);
1044+
/// assert!(b.is_empty());
10031045
/// ```
1046+
///
1047+
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
10041048
#[stable(feature = "rust1", since = "1.0.0")]
10051049
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
10061050

1007-
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
1051+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
10081052
/// and destination may overlap.
10091053
///
1010-
/// `copy` is semantically equivalent to C's `memmove`.
1054+
/// If the source and destination will *never* overlap,
1055+
/// [`copy_nonoverlapping`] can be used instead.
1056+
///
1057+
/// `copy` is semantically equivalent to C's [`memmove`], but with the argument
1058+
/// order swapped. Copying takes place as if the bytes were copied from `src`
1059+
/// to a temporary array and then copied from the array to `dst`.
1060+
///
1061+
/// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
1062+
/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
10111063
///
10121064
/// # Safety
10131065
///
1014-
/// Care must be taken with the ownership of `src` and `dst`.
1015-
/// This method semantically moves the values of `src` into `dst`.
1016-
/// However it does not drop the contents of `dst`, or prevent the contents of `src`
1017-
/// from being dropped or used.
1066+
/// Behavior is undefined if any of the following conditions are violated:
1067+
///
1068+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
1069+
///
1070+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1071+
///
1072+
/// * Both `src` and `dst` must be properly aligned.
1073+
///
1074+
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
1075+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
1076+
/// in the region beginning at `*src` and the region beginning at `*dst` can
1077+
/// [violate memory safety][read-ownership].
1078+
///
1079+
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1080+
/// `0`, the pointers must be non-NULL and properly aligned.
1081+
///
1082+
/// [`Copy`]: ../marker/trait.Copy.html
1083+
/// [`read`]: ../ptr/fn.read.html
1084+
/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value
1085+
/// [valid]: ../ptr/index.html#safety
10181086
///
10191087
/// # Examples
10201088
///
@@ -1031,24 +1099,80 @@ extern "rust-intrinsic" {
10311099
/// dst
10321100
/// }
10331101
/// ```
1034-
///
10351102
#[stable(feature = "rust1", since = "1.0.0")]
10361103
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
10371104

1038-
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
1039-
/// bytes of memory starting at `dst` to `val`.
1105+
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
1106+
/// `val`.
1107+
///
1108+
/// `write_bytes` is similar to C's [`memset`], but sets `count *
1109+
/// size_of::<T>()` bytes to `val`.
1110+
///
1111+
/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset
1112+
///
1113+
/// # Safety
1114+
///
1115+
/// Behavior is undefined if any of the following conditions are violated:
1116+
///
1117+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
1118+
///
1119+
/// * `dst` must be properly aligned.
1120+
///
1121+
/// Additionally, the caller must ensure that writing `count *
1122+
/// size_of::<T>()` bytes to the given region of memory results in a valid
1123+
/// value of `T`. Using a region of memory typed as a `T` that contains an
1124+
/// invalid value of `T` is undefined behavior.
1125+
///
1126+
/// Note that even if the effectively copied size (`count * size_of::<T>()`) is
1127+
/// `0`, the pointer must be non-NULL and properly aligned.
1128+
///
1129+
/// [valid]: ../ptr/index.html#safety
10401130
///
10411131
/// # Examples
10421132
///
1133+
/// Basic usage:
1134+
///
10431135
/// ```
10441136
/// use std::ptr;
10451137
///
1046-
/// let mut vec = vec![0; 4];
1138+
/// let mut vec = vec![0u32; 4];
10471139
/// unsafe {
10481140
/// let vec_ptr = vec.as_mut_ptr();
1049-
/// ptr::write_bytes(vec_ptr, b'a', 2);
1141+
/// ptr::write_bytes(vec_ptr, 0xfe, 2);
1142+
/// }
1143+
/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
1144+
/// ```
1145+
///
1146+
/// Creating an invalid value:
1147+
///
1148+
/// ```
1149+
/// use std::ptr;
1150+
///
1151+
/// let mut v = Box::new(0i32);
1152+
///
1153+
/// unsafe {
1154+
/// // Leaks the previously held value by overwriting the `Box<T>` with
1155+
/// // a null pointer.
1156+
/// ptr::write_bytes(&mut v as *mut Box<i32>, 0, 1);
10501157
/// }
1051-
/// assert_eq!(vec, [b'a', b'a', 0, 0]);
1158+
///
1159+
/// // At this point, using or dropping `v` results in undefined behavior.
1160+
/// // drop(v); // ERROR
1161+
///
1162+
/// // Even leaking `v` "uses" it, and hence is undefined behavior.
1163+
/// // mem::forget(v); // ERROR
1164+
///
1165+
/// // In fact, `v` is invalid according to basic type layout invariants, so *any*
1166+
/// // operation touching it is undefined behavior.
1167+
/// // let v2 = v; // ERROR
1168+
///
1169+
/// unsafe {
1170+
/// // Let us instead put in a valid value
1171+
/// ptr::write(&mut v as *mut Box<i32>, Box::new(42i32));
1172+
/// }
1173+
///
1174+
/// // Now the box is fine
1175+
/// assert_eq!(*v, 42);
10521176
/// ```
10531177
#[stable(feature = "rust1", since = "1.0.0")]
10541178
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
@@ -1066,7 +1190,7 @@ extern "rust-intrinsic" {
10661190
/// `min_align_of::<T>()`
10671191
///
10681192
/// The volatile parameter is set to `true`, so it will not be optimized out
1069-
/// unless size is equal to zero..
1193+
/// unless size is equal to zero.
10701194
pub fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
10711195
/// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
10721196
/// size of `count` * `size_of::<T>()` and an alignment of

0 commit comments

Comments
 (0)