Skip to content

Add uninit buffer ancillary APIs #1108

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

Merged
merged 4 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,5 +267,11 @@ argument optionallly containing a raw file descriptor.

[`rustix::io_uring::io_uring_setup`]: https://docs.rs/rustix/1.0.0/rustix/io_uring/fn.io_uring_setup.html

The buffer for [`SendAncillaryBuffer`] and [`RecvAncillaryBuffer`] is now
a `[MaybeUninit<u8>]` instead of a `[u8]`.

[`SendAncillaryBuffer`]: https://docs.rs/rustix/1.0.0/rustix/net/struct.SendAncillaryBuffer.html
[`RecvAncillaryBuffer`]: https://docs.rs/rustix/1.0.0/rustix/net/struct.RecvAncillaryBuffer.html

All explicitly deprecated functions and types have been removed. Their
deprecation messages will have identified alternatives.
67 changes: 42 additions & 25 deletions src/net/send_recv/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::net::UCred;
use core::fmt;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::{align_of, size_of, size_of_val, take};
use core::mem::{align_of, size_of, size_of_val, take, MaybeUninit};
#[cfg(linux_kernel)]
use core::ptr::addr_of;
use core::{ptr, slice};
Expand All @@ -28,25 +28,31 @@ use super::{RecvFlags, ReturnFlags, SendFlags, SocketAddrAny};
///
/// Allocate a buffer for a single file descriptor:
/// ```
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
/// # let _: &[MaybeUninit<u8>] = space.as_slice();
/// ```
///
/// Allocate a buffer for credentials:
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
/// # let _: &[MaybeUninit<u8>] = space.as_slice();
/// # }
/// ```
///
/// Allocate a buffer for two file descriptors and credentials:
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// # let _: &[MaybeUninit<u8>] = space.as_slice();
/// # }
/// ```
#[macro_export]
Expand Down Expand Up @@ -169,7 +175,7 @@ pub enum RecvAncillaryMessage<'a> {
/// [`push`]: SendAncillaryBuffer::push
pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> {
/// Raw byte buffer for messages.
buffer: &'buf mut [u8],
buffer: &'buf mut [MaybeUninit<u8>],

/// The amount of the buffer that is used.
length: usize,
Expand All @@ -178,8 +184,8 @@ pub struct SendAncillaryBuffer<'buf, 'slice, 'fd> {
_phantom: PhantomData<&'slice [BorrowedFd<'fd>]>,
}

impl<'buf> From<&'buf mut [u8]> for SendAncillaryBuffer<'buf, '_, '_> {
fn from(buffer: &'buf mut [u8]) -> Self {
impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for SendAncillaryBuffer<'buf, '_, '_> {
fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
Self::new(buffer)
}
}
Expand All @@ -205,19 +211,21 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
///
/// Allocate a buffer for a single file descriptor:
/// ```
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::SendAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
/// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
/// ```
///
/// Allocate a buffer for credentials:
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::SendAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
/// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
/// # }
/// ```
Expand All @@ -226,16 +234,17 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::SendAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
/// # }
/// ```
///
/// [`send`]: crate::net::send
#[inline]
pub fn new(buffer: &'buf mut [u8]) -> Self {
pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
Self {
buffer: align_for_cmsghdr(buffer),
length: 0,
Expand All @@ -253,7 +262,7 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
return core::ptr::null_mut();
}

self.buffer.as_mut_ptr()
self.buffer.as_mut_ptr().cast()
}

/// Returns the length of the message data.
Expand Down Expand Up @@ -306,7 +315,7 @@ impl<'buf, 'slice, 'fd> SendAncillaryBuffer<'buf, 'slice, 'fd> {
let buffer = leap!(self.buffer.get_mut(..new_length));

// Fill the new part of the buffer with zeroes.
buffer[self.length..new_length].fill(0);
buffer[self.length..new_length].fill(MaybeUninit::new(0));
self.length = new_length;

// Get the last header in the buffer.
Expand Down Expand Up @@ -344,7 +353,7 @@ impl<'slice, 'fd> Extend<SendAncillaryMessage<'slice, 'fd>>
#[derive(Default)]
pub struct RecvAncillaryBuffer<'buf> {
/// Raw byte buffer for messages.
buffer: &'buf mut [u8],
buffer: &'buf mut [MaybeUninit<u8>],

/// The portion of the buffer we've read from already.
read: usize,
Expand All @@ -353,8 +362,8 @@ pub struct RecvAncillaryBuffer<'buf> {
length: usize,
}

impl<'buf> From<&'buf mut [u8]> for RecvAncillaryBuffer<'buf> {
fn from(buffer: &'buf mut [u8]) -> Self {
impl<'buf> From<&'buf mut [MaybeUninit<u8>]> for RecvAncillaryBuffer<'buf> {
fn from(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
Self::new(buffer)
}
}
Expand All @@ -370,19 +379,21 @@ impl<'buf> RecvAncillaryBuffer<'buf> {
///
/// Allocate a buffer for a single file descriptor:
/// ```
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::RecvAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
/// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
/// ```
///
/// Allocate a buffer for credentials:
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::RecvAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
/// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
/// # }
/// ```
Expand All @@ -391,16 +402,17 @@ impl<'buf> RecvAncillaryBuffer<'buf> {
/// ```
/// # #[cfg(linux_kernel)]
/// # {
/// # use core::mem::MaybeUninit;
/// # use rustix::cmsg_space;
/// # use rustix::net::RecvAncillaryBuffer;
/// let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmCredentials(1))];
/// let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut space);
/// # }
/// ```
///
/// [`recv`]: crate::net::recv
#[inline]
pub fn new(buffer: &'buf mut [u8]) -> Self {
pub fn new(buffer: &'buf mut [MaybeUninit<u8>]) -> Self {
Self {
buffer: align_for_cmsghdr(buffer),
read: 0,
Expand All @@ -418,7 +430,7 @@ impl<'buf> RecvAncillaryBuffer<'buf> {
return core::ptr::null_mut();
}

self.buffer.as_mut_ptr()
self.buffer.as_mut_ptr().cast()
}

/// Returns the length of the message data.
Expand Down Expand Up @@ -459,7 +471,7 @@ impl Drop for RecvAncillaryBuffer<'_> {
/// Return a slice of `buffer` starting at the first `cmsghdr` alignment
/// boundary.
#[inline]
fn align_for_cmsghdr(buffer: &mut [u8]) -> &mut [u8] {
fn align_for_cmsghdr(buffer: &mut [MaybeUninit<u8>]) -> &mut [MaybeUninit<u8>] {
// If the buffer is empty, we won't be writing anything into it, so it
// doesn't need to be aligned.
if buffer.is_empty() {
Expand Down Expand Up @@ -884,6 +896,7 @@ mod messages {
use crate::backend::net::msghdr;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ptr::NonNull;

/// An iterator over the messages in an ancillary buffer.
Expand All @@ -897,15 +910,19 @@ mod messages {
header: Option<NonNull<c::cmsghdr>>,

/// Capture the original lifetime of the buffer.
_buffer: PhantomData<&'buf mut [u8]>,
_buffer: PhantomData<&'buf mut [MaybeUninit<u8>]>,
}

pub(super) trait AllowedMsgBufType {}
impl AllowedMsgBufType for u8 {}
impl AllowedMsgBufType for MaybeUninit<u8> {}

impl<'buf> Messages<'buf> {
/// Create a new iterator over messages from a byte buffer.
pub(super) fn new(buf: &'buf mut [u8]) -> Self {
pub(super) fn new(buf: &'buf mut [impl AllowedMsgBufType]) -> Self {
let mut msghdr = msghdr::zero_msghdr();
msghdr.msg_control = buf.as_mut_ptr().cast();
msghdr.msg_controllen = buf.len().try_into().unwrap();
msghdr.msg_controllen = buf.len().try_into().expect("buffer too large for msghdr");

// Get the first header.
let header = NonNull::new(unsafe { c::CMSG_FIRSTHDR(&msghdr) });
Expand Down
30 changes: 16 additions & 14 deletions tests/net/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustix::net::{
accept, bind, connect, listen, socket, AddressFamily, SocketAddrUnix, SocketType,
};
use rustix::path::DecInt;
use std::mem::MaybeUninit;
use std::path::Path;
use std::str::FromStr as _;
use std::sync::{Arc, Condvar, Mutex};
Expand Down Expand Up @@ -449,13 +450,13 @@ fn test_unix_msg_with_scm_rights() {
let mut pipe_end = None;

let mut buffer = [0; BUFFER_SIZE];
let mut cmsg_space = [0; rustix::cmsg_space!(ScmRights(1))];
let mut cmsg_space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];

'exit: loop {
let data_socket = accept(&connection_socket).unwrap();
let mut sum = 0;
loop {
let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space);
let mut cmsg_buffer = RecvAncillaryBuffer::new(cmsg_space.as_mut_slice());
let result = recvmsg(
&data_socket,
&mut [IoSliceMut::new(&mut buffer)],
Expand Down Expand Up @@ -560,8 +561,8 @@ fn test_unix_msg_with_scm_rights() {
// Format the CMSG.
let we = [write_end.as_fd()];
let msg = SendAncillaryMessage::ScmRights(&we);
let mut space = [0; rustix::cmsg_space!(ScmRights(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(space.as_mut_slice());
assert!(cmsg_buffer.push(msg));

connect(&data_socket, &addr).unwrap();
Expand Down Expand Up @@ -620,8 +621,8 @@ fn test_unix_peercred_explicit() {

let ucred = sockopt::socket_peercred(&send_sock).unwrap();
let msg = SendAncillaryMessage::ScmCredentials(ucred);
let mut space = [0; rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(space.as_mut_slice());
assert!(cmsg_buffer.push(msg));

sendmsg(
Expand All @@ -632,8 +633,8 @@ fn test_unix_peercred_explicit() {
)
.unwrap();

let mut cmsg_space = [0; rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space);
let mut cmsg_space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = RecvAncillaryBuffer::new(cmsg_space.as_mut_slice());

let mut buffer = [0; BUFFER_SIZE];
let result = recvmsg(
Expand Down Expand Up @@ -692,8 +693,8 @@ fn test_unix_peercred_implicit() {
)
.unwrap();

let mut cmsg_space = [0; rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space);
let mut cmsg_space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmCredentials(1))];
let mut cmsg_buffer = RecvAncillaryBuffer::new(cmsg_space.as_mut_slice());

let mut buffer = [0; BUFFER_SIZE];
let result = recvmsg(
Expand Down Expand Up @@ -747,13 +748,14 @@ fn test_unix_msg_with_combo() {
let mut yet_another_pipe_end = None;

let mut buffer = [0; BUFFER_SIZE];
let mut cmsg_space = [0; rustix::cmsg_space!(ScmRights(2), ScmRights(1))];
let mut cmsg_space =
[MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmRights(1))];

'exit: loop {
let data_socket = accept(&connection_socket).unwrap();
let mut sum = 0;
loop {
let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space);
let mut cmsg_buffer = RecvAncillaryBuffer::new(cmsg_space.as_mut_slice());
let result = recvmsg(
&data_socket,
&mut [IoSliceMut::new(&mut buffer)],
Expand Down Expand Up @@ -872,8 +874,8 @@ fn test_unix_msg_with_combo() {

let data_socket = socket(AddressFamily::UNIX, SocketType::SEQPACKET, None).unwrap();

let mut space = [0; rustix::cmsg_space!(ScmRights(2), ScmRights(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(&mut space);
let mut space = [MaybeUninit::uninit(); rustix::cmsg_space!(ScmRights(2), ScmRights(1))];
let mut cmsg_buffer = SendAncillaryBuffer::new(space.as_mut_slice());

// Format a CMSG.
let we = [write_end.as_fd(), another_write_end.as_fd()];
Expand Down
Loading
Loading