Skip to content

Commit 2643afc

Browse files
committed
Remove the deprecated CmsgSpace
This eliminates one of the last remaining uninitialized memory accesses in Nix. Fixes #1142
1 parent f3bf1df commit 2643afc

File tree

2 files changed

+38
-89
lines changed

2 files changed

+38
-89
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
3434
([#1148](https://github.com/nix-rust/nix/pull/1148))
3535

3636
### Changed
37+
- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer`
38+
implementor. If you were already using `cmsg_space!`, then you needn't worry.
39+
([#1156](https://github.com/nix-rust/nix/pull/1156))
40+
3741
- `sys::socket::recvfrom` now returns
3842
`Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`.
3943
([#1145](https://github.com/nix-rust/nix/pull/1145))
@@ -77,6 +81,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
7781
([#1136](https://github.com/nix-rust/nix/pull/1136))
7882

7983
### Removed
84+
- Remove the deprecated `CmsgSpace`.
85+
([#1156](https://github.com/nix-rust/nix/pull/1156))
8086

8187
## [0.15.0] - 10 August 2019
8288
### Added

src/sys/socket/mod.rs

Lines changed: 32 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,6 @@ impl Ipv6MembershipRequest {
261261
}
262262
}
263263

264-
cfg_if! {
265-
// Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
266-
if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
267-
type align_of_cmsg_data = u32;
268-
} else {
269-
type align_of_cmsg_data = size_t;
270-
}
271-
}
272-
273-
/// A type that can be used to store ancillary data received by
274-
/// [`recvmsg`](fn.recvmsg.html)
275-
pub trait CmsgBuffer {
276-
fn as_bytes_mut(&mut self) -> &mut [u8];
277-
}
278-
279264
/// Create a buffer large enough for storing some control messages as returned
280265
/// by [`recvmsg`](fn.recvmsg.html).
281266
///
@@ -311,63 +296,11 @@ macro_rules! cmsg_space {
311296
CMSG_SPACE(mem::size_of::<$x>() as c_uint)
312297
} as usize;
313298
)*
314-
let mut v = Vec::<u8>::with_capacity(space);
315-
// safe because any bit pattern is a valid u8
316-
unsafe {v.set_len(space)};
317-
v
299+
Vec::<u8>::with_capacity(space)
318300
}
319301
}
320302
}
321303

322-
/// A structure used to make room in a cmsghdr passed to recvmsg. The
323-
/// size and alignment match that of a cmsghdr followed by a T, but the
324-
/// fields are not accessible, as the actual types will change on a call
325-
/// to recvmsg.
326-
///
327-
/// To make room for multiple messages, nest the type parameter with
328-
/// tuples:
329-
///
330-
/// ```
331-
/// use std::os::unix::io::RawFd;
332-
/// use nix::sys::socket::CmsgSpace;
333-
/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
334-
/// ```
335-
#[repr(C)]
336-
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
337-
pub struct CmsgSpace<T> {
338-
_hdr: cmsghdr,
339-
_pad: [align_of_cmsg_data; 0],
340-
_data: T,
341-
}
342-
343-
impl<T> CmsgSpace<T> {
344-
/// Create a CmsgSpace<T>. The structure is used only for space, so
345-
/// the fields are uninitialized.
346-
#[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
347-
// It's deprecated anyway; no sense adding Default
348-
#[allow(clippy::new_without_default)]
349-
pub fn new() -> Self {
350-
// Safe because the fields themselves aren't accessible.
351-
unsafe { mem::uninitialized() }
352-
}
353-
}
354-
355-
impl<T> CmsgBuffer for CmsgSpace<T> {
356-
fn as_bytes_mut(&mut self) -> &mut [u8] {
357-
// Safe because nothing ever attempts to access CmsgSpace's fields
358-
unsafe {
359-
slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
360-
mem::size_of::<Self>())
361-
}
362-
}
363-
}
364-
365-
impl CmsgBuffer for Vec<u8> {
366-
fn as_bytes_mut(&mut self) -> &mut [u8] {
367-
&mut self[..]
368-
}
369-
}
370-
371304
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
372305
pub struct RecvMsg<'a> {
373306
pub bytes: usize,
@@ -893,33 +826,39 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
893826
/// optionally receive ancillary data into the provided buffer.
894827
/// If no ancillary data is desired, use () as the type parameter.
895828
///
829+
/// # Arguments
830+
///
831+
/// * `fd`: Socket file descriptor
832+
/// * `iov`: Scatter-gather list of buffers to receive the message
833+
/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
834+
/// [`cmsg_space!`](macro.cmsg_space.html)
835+
/// * `flags`: Optional flags passed directly to the operating system.
836+
///
896837
/// # References
897838
/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
898839
pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
899-
cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
840+
mut cmsg_buffer: Option<&'a mut Vec<u8>>,
900841
flags: MsgFlags) -> Result<RecvMsg<'a>>
901842
{
902843
let mut address = mem::MaybeUninit::uninit();
903-
let (msg_control, msg_controllen) = match cmsg_buffer {
904-
Some(cmsgspace) => {
905-
let msg_buf = cmsgspace.as_bytes_mut();
906-
(msg_buf.as_mut_ptr(), msg_buf.len())
907-
},
908-
None => (ptr::null_mut(), 0),
909-
};
910-
let mut mhdr = unsafe {
911-
// Musl's msghdr has private fields, so this is the only way to
912-
// initialize it.
913-
let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
914-
let p = mhdr.as_mut_ptr();
915-
(*p).msg_name = address.as_mut_ptr() as *mut c_void;
916-
(*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
917-
(*p).msg_iov = iov.as_ptr() as *mut iovec;
918-
(*p).msg_iovlen = iov.len() as _;
919-
(*p).msg_control = msg_control as *mut c_void;
920-
(*p).msg_controllen = msg_controllen as _;
921-
(*p).msg_flags = 0;
922-
mhdr.assume_init()
844+
let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
845+
.map(|v| (v.as_mut_ptr(), v.capacity()))
846+
.unwrap_or((ptr::null_mut(), 0));
847+
let mut mhdr = {
848+
unsafe {
849+
// Musl's msghdr has private fields, so this is the only way to
850+
// initialize it.
851+
let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
852+
let p = mhdr.as_mut_ptr();
853+
(*p).msg_name = address.as_mut_ptr() as *mut c_void;
854+
(*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
855+
(*p).msg_iov = iov.as_ptr() as *mut iovec;
856+
(*p).msg_iovlen = iov.len() as _;
857+
(*p).msg_control = msg_control as *mut c_void;
858+
(*p).msg_controllen = msg_controllen as _;
859+
(*p).msg_flags = 0;
860+
mhdr.assume_init()
861+
}
923862
};
924863

925864
let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
@@ -928,6 +867,10 @@ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
928867
let cmsghdr = unsafe {
929868
if mhdr.msg_controllen > 0 {
930869
// got control message(s)
870+
cmsg_buffer
871+
.as_mut()
872+
.unwrap()
873+
.set_len(mhdr.msg_controllen as usize);
931874
debug_assert!(!mhdr.msg_control.is_null());
932875
debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
933876
CMSG_FIRSTHDR(&mhdr as *const msghdr)

0 commit comments

Comments
 (0)