Skip to content

Commit a81e9a7

Browse files
Improve documentation of slice::from_raw_parts
This is to provide a more explicit statement against a code pattern that many people end up coming with, since the reason of it being unsound comes from the badly known single-allocation validity rule. Providing that very pattern as a counter-example could help mitigate that. Co-authored-by: Ralf Jung <post@ralfj.de>
1 parent 06c9fef commit a81e9a7

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

src/libcore/slice/mod.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -5740,7 +5740,8 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
57405740
/// and it must be properly aligned. This means in particular:
57415741
///
57425742
/// * The entire memory range of this slice must be contained within a single allocated object!
5743-
/// Slices can never span across multiple allocated objects.
5743+
/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
5744+
/// for an example incorrectly not taking this into account.
57445745
/// * `data` must be non-null and aligned even for zero-length slices. One
57455746
/// reason for this is that enum layout optimizations may rely on references
57465747
/// (including slices of any length) being aligned and non-null to distinguish
@@ -5773,6 +5774,34 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
57735774
/// assert_eq!(slice[0], 42);
57745775
/// ```
57755776
///
5777+
/// ### Incorrect usage
5778+
///
5779+
/// The following `join_slices` function is **unsound** ⚠️
5780+
///
5781+
/// ```rust,no_run
5782+
/// use std::slice;
5783+
///
5784+
/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
5785+
/// let fst_end = fst.as_ptr().wrapping_add(fst.len());
5786+
/// let snd_start = snd.as_ptr();
5787+
/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
5788+
/// unsafe {
5789+
/// // The assertion above ensures `fst` and `snd` are contiguous, but they might
5790+
/// // still be contained within _different allocated objects_, in which case
5791+
/// // creating this slice is undefined behavior.
5792+
/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
5793+
/// }
5794+
/// }
5795+
///
5796+
/// fn main() {
5797+
/// // `a` and `b` are different allocated objects...
5798+
/// let a = 42;
5799+
/// let b = 27;
5800+
/// // ... which may nevertheless be laid out contiguous in memory: | a | b |
5801+
/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
5802+
/// }
5803+
/// ```
5804+
///
57765805
/// [valid]: ../../std/ptr/index.html#safety
57775806
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
57785807
/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset

0 commit comments

Comments
 (0)