Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC: Add FFI example for slice::from_raw_parts() #123374

Merged
merged 4 commits into from
Jun 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions library/core/src/slice/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,39 @@ use crate::ub_checks;
/// }
/// ```
///
/// ### FFI: Handling null pointers
///
/// In languages such as C++, pointers to empty collections are not guaranteed to be non-null.
/// When accepting such pointers, they have to be checked for null-ness to avoid undefined
/// behavior.
///
/// ```
/// use std::slice;
///
/// /// Sum the elements of an FFI slice.
/// ///
/// /// # Safety
/// ///
/// /// If ptr is not NULL, it must be correctly aligned and
/// /// point to `len` initialized items of type `f32`.
/// unsafe extern "C" fn sum_slice(ptr: *const f32, len: usize) -> f32 {
/// let data = if ptr.is_null() {
/// // `len` is assumed to be 0.
/// &[]
/// } else {
/// // SAFETY: see function docstring.
/// unsafe { slice::from_raw_parts(ptr, len) }
/// };
/// data.into_iter().sum()
/// }
///
/// // This could be the result of C++'s std::vector::data():
/// let ptr = std::ptr::null();
/// // And this could be std::vector::size():
/// let len = 0;
/// assert_eq!(unsafe { sum_slice(ptr, len) }, 0.0);
/// ```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of requests for the example:

  • When there's unsafe functions or blocks in the documentation, please put # Safety header and // SAFETY comments so the docs are a good example of what we'd like people to do.
  • dbg! inside rustdoc examples isn't particularly useful, especially for a function that's never called. Could you maybe do some simple computation on it and return it, so that it could be called and assert!ed instead? That way Miri can check that it's not accidentally UB, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review!

I have added the "safety" comments, please let me know if I should make any changes to the text.

I also changed the function to return a value and added an assert.

I'm not sure if that makes sense, though, since this function would normally be called from C++ or some other FFI language.

Alternatively, I could also provide a more general (and more useful) function:

unsafe fn ffi_slice<'a, T>(ptr: *const T, len: usize) -> &'a [T] {
    if ptr.is_null() {
        // NB: `len` is assumed to be 0.
        &[]
    } else {
        unsafe { std::slice::from_raw_parts(ptr, len) }
    }
}

I have actually used that function in my code: https://github.com/AudioSceneDescriptionFormat/asdfspline-rust/blob/e2608b07e2749caf71e43f23d4592849d27dd450/ffi/src/lib.rs#L59-L89.

However, this is a bit more complicated due to the lifetime annotation, so it might not be appropriate here?

///
/// [valid]: ptr#safety
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
Expand Down
Loading