From 2643afc22f0d76c01b28f12da6195047b2db35de Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 30 Nov 2019 20:25:55 -0700 Subject: Remove the deprecated CmsgSpace This eliminates one of the last remaining uninitialized memory accesses in Nix. Fixes #1142 --- CHANGELOG.md | 6 +++ src/sys/socket/mod.rs | 121 +++++++++++++------------------------------------- 2 files changed, 38 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4fe67da..80e9a20d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#1148](https://github.com/nix-rust/nix/pull/1148)) ### Changed +- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer` + implementor. If you were already using `cmsg_space!`, then you needn't worry. + ([#1156](https://github.com/nix-rust/nix/pull/1156)) + - `sys::socket::recvfrom` now returns `Result<(usize, Option)>` instead of `Result<(usize, SockAddr)>`. ([#1145](https://github.com/nix-rust/nix/pull/1145)) @@ -77,6 +81,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#1136](https://github.com/nix-rust/nix/pull/1136)) ### Removed +- Remove the deprecated `CmsgSpace`. + ([#1156](https://github.com/nix-rust/nix/pull/1156)) ## [0.15.0] - 10 August 2019 ### Added diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 3ee02c3a..5ecf088a 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -261,21 +261,6 @@ impl Ipv6MembershipRequest { } } -cfg_if! { - // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only. - if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] { - type align_of_cmsg_data = u32; - } else { - type align_of_cmsg_data = size_t; - } -} - -/// A type that can be used to store ancillary data received by -/// [`recvmsg`](fn.recvmsg.html) -pub trait CmsgBuffer { - fn as_bytes_mut(&mut self) -> &mut [u8]; -} - /// Create a buffer large enough for storing some control messages as returned /// by [`recvmsg`](fn.recvmsg.html). /// @@ -311,63 +296,11 @@ macro_rules! cmsg_space { CMSG_SPACE(mem::size_of::<$x>() as c_uint) } as usize; )* - let mut v = Vec::::with_capacity(space); - // safe because any bit pattern is a valid u8 - unsafe {v.set_len(space)}; - v + Vec::::with_capacity(space) } } } -/// A structure used to make room in a cmsghdr passed to recvmsg. The -/// size and alignment match that of a cmsghdr followed by a T, but the -/// fields are not accessible, as the actual types will change on a call -/// to recvmsg. -/// -/// To make room for multiple messages, nest the type parameter with -/// tuples: -/// -/// ``` -/// use std::os::unix::io::RawFd; -/// use nix::sys::socket::CmsgSpace; -/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new(); -/// ``` -#[repr(C)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct CmsgSpace { - _hdr: cmsghdr, - _pad: [align_of_cmsg_data; 0], - _data: T, -} - -impl CmsgSpace { - /// Create a CmsgSpace. The structure is used only for space, so - /// the fields are uninitialized. - #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")] - // It's deprecated anyway; no sense adding Default - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - // Safe because the fields themselves aren't accessible. - unsafe { mem::uninitialized() } - } -} - -impl CmsgBuffer for CmsgSpace { - fn as_bytes_mut(&mut self) -> &mut [u8] { - // Safe because nothing ever attempts to access CmsgSpace's fields - unsafe { - slice::from_raw_parts_mut(self as *mut CmsgSpace as *mut u8, - mem::size_of::()) - } - } -} - -impl CmsgBuffer for Vec { - fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut self[..] - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct RecvMsg<'a> { pub bytes: usize, @@ -893,33 +826,39 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], /// optionally receive ancillary data into the provided buffer. /// If no ancillary data is desired, use () as the type parameter. /// +/// # Arguments +/// +/// * `fd`: Socket file descriptor +/// * `iov`: Scatter-gather list of buffers to receive the message +/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by +/// [`cmsg_space!`](macro.cmsg_space.html) +/// * `flags`: Optional flags passed directly to the operating system. +/// /// # References /// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], - cmsg_buffer: Option<&'a mut dyn CmsgBuffer>, + mut cmsg_buffer: Option<&'a mut Vec>, flags: MsgFlags) -> Result> { let mut address = mem::MaybeUninit::uninit(); - let (msg_control, msg_controllen) = match cmsg_buffer { - Some(cmsgspace) => { - let msg_buf = cmsgspace.as_bytes_mut(); - (msg_buf.as_mut_ptr(), msg_buf.len()) - }, - None => (ptr::null_mut(), 0), - }; - let mut mhdr = unsafe { - // Musl's msghdr has private fields, so this is the only way to - // initialize it. - let mut mhdr = mem::MaybeUninit::::zeroed(); - let p = mhdr.as_mut_ptr(); - (*p).msg_name = address.as_mut_ptr() as *mut c_void; - (*p).msg_namelen = mem::size_of::() as socklen_t; - (*p).msg_iov = iov.as_ptr() as *mut iovec; - (*p).msg_iovlen = iov.len() as _; - (*p).msg_control = msg_control as *mut c_void; - (*p).msg_controllen = msg_controllen as _; - (*p).msg_flags = 0; - mhdr.assume_init() + let (msg_control, msg_controllen) = cmsg_buffer.as_mut() + .map(|v| (v.as_mut_ptr(), v.capacity())) + .unwrap_or((ptr::null_mut(), 0)); + let mut mhdr = { + unsafe { + // Musl's msghdr has private fields, so this is the only way to + // initialize it. + let mut mhdr = mem::MaybeUninit::::zeroed(); + let p = mhdr.as_mut_ptr(); + (*p).msg_name = address.as_mut_ptr() as *mut c_void; + (*p).msg_namelen = mem::size_of::() as socklen_t; + (*p).msg_iov = iov.as_ptr() as *mut iovec; + (*p).msg_iovlen = iov.len() as _; + (*p).msg_control = msg_control as *mut c_void; + (*p).msg_controllen = msg_controllen as _; + (*p).msg_flags = 0; + mhdr.assume_init() + } }; let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; @@ -928,6 +867,10 @@ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], let cmsghdr = unsafe { if mhdr.msg_controllen > 0 { // got control message(s) + cmsg_buffer + .as_mut() + .unwrap() + .set_len(mhdr.msg_controllen as usize); debug_assert!(!mhdr.msg_control.is_null()); debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); CMSG_FIRSTHDR(&mhdr as *const msghdr) -- cgit v1.2.3