Skip to content

Commit 911d35f

Browse files
ecstatic-morseRalfJung
authored andcommitted
Rewrite docs for std::ptr
- Add links to the GNU libc docs for `memmove`, `memcpy`, and `memset`, as well as internally linking to other functions in `std::ptr` - List invariants which, when violated, cause UB for all functions - Add example to `ptr::drop_in_place` and compares it to `ptr::read`. - Add examples which more closely mirror real world uses for the functions in `std::ptr`. Also, move the reimplementation of `mem::swap` to the examples of `ptr::read` and use a more interesting example for `copy_nonoverlapping`. - Change module level description - Define what constitutes a "valid" pointer. - Centralize discussion of ownership of bitwise copies in `ptr::read` and provide an example.
1 parent 29e6aab commit 911d35f

File tree

2 files changed

+497
-102
lines changed

2 files changed

+497
-102
lines changed

Diff for: src/libcore/intrinsics.rs

+146-34
Original file line numberDiff line numberDiff line change
@@ -962,59 +962,129 @@ 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`].
971+
///
972+
/// [`copy`]: ./fn.copy.html
973+
/// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy
969974
///
970975
/// # Safety
971976
///
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.
977+
/// Behavior is undefined if any of the following conditions are violated:
978+
///
979+
/// * Both `src` and `dst` must be [valid].
980+
///
981+
/// * Both `src` and `dst` must be properly aligned.
982+
///
983+
/// * `src.offset(count)` must be [valid]. In other words, the region of
984+
/// memory which begins at `src` and has a length of `count *
985+
/// size_of::<T>()` bytes must belong to a single, live allocation.
986+
///
987+
/// * `dst.offset(count)` must be [valid]. In other words, the region of
988+
/// memory which begins at `dst` and has a length of `count *
989+
/// size_of::<T>()` bytes must belong to a single, live allocation.
990+
///
991+
/// * The two regions of memory must *not* overlap.
992+
///
993+
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
994+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
995+
/// in the region beginning at `*src` and the region beginning at `*dst` can
996+
/// [violate memory safety][read-ownership].
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) {
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();
1014+
///
1015+
/// // Ensure that `dst` has enough capacity to hold all of `src`.
1016+
/// dst.reserve(src_len);
1017+
///
9891018
/// unsafe {
990-
/// // Give ourselves some scratch space to work with
991-
/// let mut t: T = mem::uninitialized();
1019+
/// // The call to offset is always safe because `Vec` will never
1020+
/// // allocate more than `isize::MAX` bytes.
1021+
/// let dst = dst.as_mut_ptr().offset(dst_len as isize);
1022+
/// let src = src.as_ptr();
1023+
///
1024+
/// // The two regions cannot overlap becuase mutable references do
1025+
/// // not alias, and two different vectors cannot own the same
1026+
/// // memory.
1027+
/// ptr::copy_nonoverlapping(src, dst, src_len);
1028+
/// }
9921029
///
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);
1030+
/// unsafe {
1031+
/// // Truncate `src` without dropping its contents.
1032+
/// src.set_len(0);
9971033
///
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);
1034+
/// // Notify `dst` that it now holds the contents of `src`.
1035+
/// dst.set_len(dst_len + src_len);
10011036
/// }
10021037
/// }
1038+
///
1039+
/// let mut a = vec!['r'];
1040+
/// let mut b = vec!['u', 's', 't'];
1041+
///
1042+
/// append(&mut a, &mut b);
1043+
///
1044+
/// assert_eq!(a, &['r', 'u', 's', 't']);
1045+
/// assert!(b.is_empty());
10031046
/// ```
1047+
///
1048+
/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
10041049
#[stable(feature = "rust1", since = "1.0.0")]
10051050
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
10061051

1007-
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
1052+
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
10081053
/// and destination may overlap.
10091054
///
1010-
/// `copy` is semantically equivalent to C's `memmove`.
1055+
/// If the source and destination will *never* overlap,
1056+
/// [`copy_nonoverlapping`] can be used instead.
1057+
///
1058+
/// `copy` is semantically equivalent to C's [`memmove`].
1059+
///
1060+
/// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
1061+
/// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove
10111062
///
10121063
/// # Safety
10131064
///
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.
1065+
/// Behavior is undefined if any of the following conditions are violated:
1066+
///
1067+
/// * Both `src` and `dst` must be [valid].
1068+
///
1069+
/// * Both `src` and `dst` must be properly aligned.
1070+
///
1071+
/// * `src.offset(count)` must be [valid]. In other words, the region of
1072+
/// memory which begins at `src` and has a length of `count *
1073+
/// size_of::<T>()` bytes must belong to a single, live allocation.
1074+
///
1075+
/// * `dst.offset(count)` must be [valid]. In other words, the region of
1076+
/// memory which begins at `dst` and has a length of `count *
1077+
/// size_of::<T>()` bytes must belong to a single, live allocation.
1078+
///
1079+
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
1080+
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
1081+
/// in the region beginning at `*src` and the region beginning at `*dst` can
1082+
/// [violate memory safety][read-ownership].
1083+
///
1084+
/// [`Copy`]: ../marker/trait.Copy.html
1085+
/// [`read`]: ../ptr/fn.read.html
1086+
/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value
1087+
/// [valid]: ../ptr/index.html#safety
10181088
///
10191089
/// # Examples
10201090
///
@@ -1031,24 +1101,66 @@ extern "rust-intrinsic" {
10311101
/// dst
10321102
/// }
10331103
/// ```
1034-
///
10351104
#[stable(feature = "rust1", since = "1.0.0")]
10361105
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
10371106

1038-
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
1039-
/// bytes of memory starting at `dst` to `val`.
1107+
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
1108+
/// `val`.
1109+
///
1110+
/// `write_bytes` is similar to C's [`memset`], but sets `count *
1111+
/// size_of::<T>()` bytes to `val`.
1112+
///
1113+
/// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset
1114+
///
1115+
/// # Safety
1116+
///
1117+
/// Behavior is undefined if any of the following conditions are violated:
1118+
///
1119+
/// * `dst` must be [valid].
1120+
///
1121+
/// * `dst.offset(count)` must be [valid]. In other words, the region of
1122+
/// memory which begins at `dst` and has a length of `count *
1123+
/// size_of::<T>()` bytes must belong to a single, live allocation.
1124+
///
1125+
/// * `dst` must be properly aligned.
1126+
///
1127+
/// Additionally, the caller must ensure that writing `count *
1128+
/// size_of::<T>()` bytes to the given region of memory results in a valid
1129+
/// value of `T`. Creating an invalid value of `T` can result in undefined
1130+
/// behavior.
1131+
///
1132+
/// [valid]: ../ptr/index.html#safety
10401133
///
10411134
/// # Examples
10421135
///
1136+
/// Basic usage:
1137+
///
10431138
/// ```
10441139
/// use std::ptr;
10451140
///
1046-
/// let mut vec = vec![0; 4];
1141+
/// let mut vec = vec![0u32; 4];
10471142
/// unsafe {
10481143
/// let vec_ptr = vec.as_mut_ptr();
1049-
/// ptr::write_bytes(vec_ptr, b'a', 2);
1144+
/// ptr::write_bytes(vec_ptr, 0xfe, 2);
10501145
/// }
1051-
/// assert_eq!(vec, [b'a', b'a', 0, 0]);
1146+
/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]);
1147+
/// ```
1148+
///
1149+
/// Creating an invalid value:
1150+
///
1151+
/// ```no_run
1152+
/// use std::{mem, ptr};
1153+
///
1154+
/// let mut v = Box::new(0i32);
1155+
///
1156+
/// unsafe {
1157+
/// // Leaks the previously held value by overwriting the `Box<T>` with
1158+
/// // a null pointer.
1159+
/// ptr::write_bytes(&mut v, 0, 1);
1160+
/// }
1161+
///
1162+
/// // At this point, using or dropping `v` results in undefined behavior.
1163+
/// // v = Box::new(0i32); // ERROR
10521164
/// ```
10531165
#[stable(feature = "rust1", since = "1.0.0")]
10541166
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);

0 commit comments

Comments
 (0)