Repository: rust-lang/socket2
Pull request #163 (2020-12-22 11:32:10)

Change Socket::recv_vectored to accept uninitialised buffers
Follow up to #161.


Patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 0b51b9a..c7cb4a3 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -55,8 +55,8 @@ jobs:
     - name: Install Rust
       run: rustup update nightly && rustup default nightly
     - run: rustup target add ${{ matrix.target }}
-    - run: cargo check --target ${{ matrix.target }}
-    - run: cargo check --target ${{ matrix.target }} --features all
+    - run: cargo check --target ${{ matrix.target }} --all-targets --examples --bins --tests --no-default-features
+    - run: cargo check --target ${{ matrix.target }} --all-targets --examples --bins --tests --all-features
       continue-on-error: true
 
   publish_docs:
diff --git a/src/lib.rs b/src/lib.rs
index 1783bfe..3b25b2f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -66,7 +66,10 @@
 // Disallow warnings in examples.
 #![doc(test(attr(deny(warnings))))]
 
+use std::fmt;
+use std::mem::MaybeUninit;
 use std::net::SocketAddr;
+use std::ops::{Deref, DerefMut};
 use std::time::Duration;
 
 /// Macro to implement `fmt::Debug` for a type, printing the constant names
@@ -277,6 +280,47 @@ impl RecvFlags {
     }
 }
 
+/// A version of [`IoSliceMut`] that allows the buffer to be uninitialised.
+///
+/// [`IoSliceMut`]: std::io::IoSliceMut
+#[repr(transparent)]
+pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>);
+
+unsafe impl<'a> Send for MaybeUninitSlice<'a> {}
+
+unsafe impl<'a> Sync for MaybeUninitSlice<'a> {}
+
+impl<'a> fmt::Debug for MaybeUninitSlice<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(self.0.as_slice(), fmt)
+    }
+}
+
+impl<'a> MaybeUninitSlice<'a> {
+    /// Creates a new `MaybeUninitSlice` wrapping a byte slice.
+    ///
+    /// # Panics
+    ///
+    /// Panics on Windows if the slice is larger than 4GB.
+    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
+        MaybeUninitSlice(sys::MaybeUninitSlice::new(buf))
+    }
+}
+
+impl<'a> Deref for MaybeUninitSlice<'a> {
+    type Target = [MaybeUninit<u8>];
+
+    fn deref(&self) -> &[MaybeUninit<u8>] {
+        self.0.as_slice()
+    }
+}
+
+impl<'a> DerefMut for MaybeUninitSlice<'a> {
+    fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        self.0.as_mut_slice()
+    }
+}
+
 /// Configures a socket's TCP keepalive parameters.
 ///
 /// See [`Socket::set_tcp_keepalive`].
diff --git a/src/sockaddr.rs b/src/sockaddr.rs
index f2cc00b..239a81c 100644
--- a/src/sockaddr.rs
+++ b/src/sockaddr.rs
@@ -78,7 +78,7 @@ impl SockAddr {
     }
 
     /// Returns a raw pointer to the address storage.
-    #[cfg(unix)]
+    #[cfg(all(unix, not(target_os = "redox")))]
     pub(crate) const fn as_storage_ptr(&self) -> *const sockaddr_storage {
         &self.storage
     }
diff --git a/src/socket.rs b/src/socket.rs
index fdb5c37..4e6c4ee 100644
--- a/src/socket.rs
+++ b/src/socket.rs
@@ -19,9 +19,9 @@ use std::os::windows::io::{FromRawSocket, IntoRawSocket};
 use std::time::Duration;
 
 use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
-#[cfg(not(target_os = "redox"))]
-use crate::RecvFlags;
 use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
+#[cfg(not(target_os = "redox"))]
+use crate::{MaybeUninitSlice, RecvFlags};
 
 /// Owned wrapper around a system socket.
 ///
@@ -339,8 +339,24 @@ impl Socket {
     ///
     /// [`recv`]: Socket::recv
     /// [`connect`]: Socket::connect
+    ///
+    /// # Safety
+    ///
+    /// Normally casting a `IoSliceMut` to `MaybeUninitSlice` would be unsound,
+    /// as that allows us to write uninitialised bytes to the buffer. However
+    /// this implementation promises to not write uninitialised bytes to the
+    /// `bufs` and passes it directly to `recvmsg(2)` system call. This promise
+    /// ensures that this function can be called using `bufs` of type `&mut
+    /// [IoSliceMut]`.
+    ///
+    /// Note that the [`io::Read::read_vectored`] implementation calls this
+    /// function with `buf`s of type `&mut [IoSliceMut]`, allowing initialised
+    /// buffers to be used without using `unsafe`.
     #[cfg(not(target_os = "redox"))]
-    pub fn recv_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<(usize, RecvFlags)> {
+    pub fn recv_vectored(
+        &self,
+        bufs: &mut [MaybeUninitSlice<'_>],
+    ) -> io::Result<(usize, RecvFlags)> {
         self.recv_vectored_with_flags(bufs, 0)
     }
 
@@ -348,10 +364,17 @@ impl Socket {
     /// flags to the underlying `recvmsg`/`WSARecv` call.
     ///
     /// [`recv_vectored`]: Socket::recv_vectored
+    ///
+    /// # Safety
+    ///
+    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
+    /// as [`recv_vectored`].
+    ///
+    /// [`recv_vectored`]: Socket::recv_vectored
     #[cfg(not(target_os = "redox"))]
     pub fn recv_vectored_with_flags(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &mut [MaybeUninitSlice<'_>],
         flags: i32,
     ) -> io::Result<(usize, RecvFlags)> {
         sys::recv_vectored(self.inner, bufs, flags)
@@ -404,10 +427,17 @@ impl Socket {
     /// [`recv_from`] this allows passing multiple buffers.
     ///
     /// [`recv_from`]: Socket::recv_from
+    ///
+    /// # Safety
+    ///
+    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
+    /// as [`recv_vectored`].
+    ///
+    /// [`recv_vectored`]: Socket::recv_vectored
     #[cfg(not(target_os = "redox"))]
     pub fn recv_from_vectored(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &mut [MaybeUninitSlice<'_>],
     ) -> io::Result<(usize, RecvFlags, SockAddr)> {
         self.recv_from_vectored_with_flags(bufs, 0)
     }
@@ -416,10 +446,17 @@ impl Socket {
     /// arbitrary flags to the underlying `recvmsg`/`WSARecvFrom` call.
     ///
     /// [`recv_from_vectored`]: Socket::recv_from_vectored
+    ///
+    /// # Safety
+    ///
+    /// `recv_from_vectored` makes the same safety guarantees regarding `bufs`
+    /// as [`recv_vectored`].
+    ///
+    /// [`recv_vectored`]: Socket::recv_vectored
     #[cfg(not(target_os = "redox"))]
     pub fn recv_from_vectored_with_flags(
         &self,
-        bufs: &mut [IoSliceMut<'_>],
+        bufs: &mut [MaybeUninitSlice<'_>],
         flags: i32,
     ) -> io::Result<(usize, RecvFlags, SockAddr)> {
         sys::recv_from_vectored(self.inner, bufs, flags)
@@ -1292,6 +1329,11 @@ impl Read for Socket {
 
     #[cfg(not(target_os = "redox"))]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        // Safety: both `IoSliceMut` and `MaybeUninitSlice` promise to have the
+        // same layout, that of `iovec`/`WSABUF`. Furthermore `recv_vectored`
+        // promises to not write unitialised bytes to the `bufs` and pass it
+        // directly to the `recvmsg` system call, so this is safe.
+        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
         self.recv_vectored(bufs).map(|(n, _)| n)
     }
 }
@@ -1305,6 +1347,8 @@ impl<'a> Read for &'a Socket {
 
     #[cfg(not(target_os = "redox"))]
     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        // Safety: see other `Read::read` impl.
+        let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
         self.recv_vectored(bufs).map(|(n, _)| n)
     }
 }
diff --git a/src/sys/unix.rs b/src/sys/unix.rs
index 32780ca..e788812 100644
--- a/src/sys/unix.rs
+++ b/src/sys/unix.rs
@@ -10,7 +10,8 @@ use std::cmp::min;
 #[cfg(all(feature = "all", target_os = "linux"))]
 use std::ffi::{CStr, CString};
 #[cfg(not(target_os = "redox"))]
-use std::io::{IoSlice, IoSliceMut};
+use std::io::IoSlice;
+use std::marker::PhantomData;
 use std::mem::{self, size_of, MaybeUninit};
 use std::net::Shutdown;
 use std::net::{Ipv4Addr, Ipv6Addr};
@@ -21,10 +22,10 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
 use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
 #[cfg(feature = "all")]
 use std::path::Path;
-#[cfg(all(feature = "all", target_os = "linux"))]
-use std::slice;
+#[cfg(not(all(target_os = "redox", not(feature = "all"))))]
+use std::ptr;
 use std::time::Duration;
-use std::{io, ptr};
+use std::{io, slice};
 
 #[cfg(not(target_vendor = "apple"))]
 use libc::ssize_t;
@@ -52,14 +53,14 @@ pub(crate) use libc::{
 };
 // Used in `RecvFlags`.
 #[cfg(not(target_os = "redox"))]
-pub(crate) use libc::MSG_TRUNC;
+pub(crate) use libc::{MSG_TRUNC, SO_OOBINLINE};
 // Used in `Socket`.
 pub(crate) use libc::{
     ip_mreq as IpMreq, ipv6_mreq as Ipv6Mreq, linger, IPPROTO_IP, IPPROTO_IPV6,
     IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
     IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL,
     IP_TTL, MSG_OOB, MSG_PEEK, SOL_SOCKET, SO_BROADCAST, SO_ERROR, SO_KEEPALIVE, SO_LINGER,
-    SO_OOBINLINE, SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, TCP_NODELAY,
+    SO_RCVBUF, SO_RCVTIMEO, SO_REUSEADDR, SO_SNDBUF, SO_SNDTIMEO, TCP_NODELAY,
 };
 #[cfg(not(any(
     target_os = "dragonfly",
@@ -308,6 +309,32 @@ impl std::fmt::Debug for RecvFlags {
     }
 }
 
+#[repr(transparent)]
+pub struct MaybeUninitSlice<'a> {
+    vec: libc::iovec,
+    _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
+}
+
+impl<'a> MaybeUninitSlice<'a> {
+    pub(crate) fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
+        MaybeUninitSlice {
+            vec: libc::iovec {
+                iov_base: buf.as_mut_ptr().cast(),
+                iov_len: buf.len(),
+            },
+            _lifetime: PhantomData,
+        }
+    }
+
+    pub(crate) fn as_slice(&self) -> &[MaybeUninit<u8>] {
+        unsafe { slice::from_raw_parts(self.vec.iov_base.cast(), self.vec.iov_len) }
+    }
+
+    pub(crate) fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
+        unsafe { slice::from_raw_parts_mut(self.vec.iov_base.cast(), self.vec.iov_len) }
+    }
+}
+
 /// Unix only API.
 impl SockAddr {
     /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
@@ -453,7 +480,7 @@ pub(crate) fn recv_from(
 #[cfg(not(target_os = "redox"))]
 pub(crate) fn recv_vectored(
     fd: Socket,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &mut [crate::MaybeUninitSlice<'_>],
     flags: c_int,
 ) -> io::Result<(usize, RecvFlags)> {
     recvmsg(fd, ptr::null_mut(), bufs, flags).map(|(n, _, recv_flags)| (n, recv_flags))
@@ -462,7 +489,7 @@ pub(crate) fn recv_vectored(
 #[cfg(not(target_os = "redox"))]
 pub(crate) fn recv_from_vectored(
     fd: Socket,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &mut [crate::MaybeUninitSlice<'_>],
     flags: c_int,
 ) -> io::Result<(usize, RecvFlags, SockAddr)> {
     // Safety: `recvmsg` initialises the address storage and we set the length
@@ -484,7 +511,7 @@ pub(crate) fn recv_from_vectored(
 fn recvmsg(
     fd: Socket,
     msg_name: *mut sockaddr_storage,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &mut [crate::MaybeUninitSlice<'_>],
     flags: c_int,
 ) -> io::Result<(usize, libc::socklen_t, RecvFlags)> {
     let msg_namelen = if msg_name.is_null() {
diff --git a/src/sys/windows.rs b/src/sys/windows.rs
index e595b58..6578d40 100644
--- a/src/sys/windows.rs
+++ b/src/sys/windows.rs
@@ -7,21 +7,24 @@
 // except according to those terms.
 
 use std::cmp::min;
-use std::io::{self, IoSlice, IoSliceMut};
+use std::io::{self, IoSlice};
+use std::marker::PhantomData;
 use std::mem::{self, size_of, MaybeUninit};
 use std::net::{self, Ipv4Addr, Ipv6Addr, Shutdown};
 use std::os::windows::prelude::*;
-use std::ptr;
 use std::sync::Once;
 use std::time::Duration;
+use std::{ptr, slice};
 
 use winapi::ctypes::c_long;
 use winapi::shared::in6addr::*;
 use winapi::shared::inaddr::*;
 use winapi::shared::minwindef::DWORD;
+use winapi::shared::minwindef::ULONG;
 use winapi::shared::mstcpip::{tcp_keepalive, SIO_KEEPALIVE_VALS};
 use winapi::shared::ntdef::HANDLE;
 use winapi::shared::ws2def;
+use winapi::shared::ws2def::WSABUF;
 use winapi::um::handleapi::SetHandleInformation;
 use winapi::um::processthreadsapi::GetCurrentProcessId;
 use winapi::um::winbase::{self, INFINITE};
@@ -144,6 +147,33 @@ impl std::fmt::Debug for RecvFlags {
     }
 }
 
+#[repr(transparent)]
+pub struct MaybeUninitSlice<'a> {
+    vec: WSABUF,
+    _lifetime: PhantomData<&'a mut [MaybeUninit<u8>]>,
+}
+
+impl<'a> MaybeUninitSlice<'a> {
+    pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> {
+        assert!(buf.len() <= ULONG::MAX as usize);
+        MaybeUninitSlice {
+            vec: WSABUF {
+                len: buf.len() as ULONG,
+                buf: buf.as_mut_ptr().cast(),
+            },
+            _lifetime: PhantomData,
+        }
+    }
+
+    pub fn as_slice(&self) -> &[MaybeUninit<u8>] {
+        unsafe { slice::from_raw_parts(self.vec.buf.cast(), self.vec.len as usize) }
+    }
+
+    pub fn as_mut_slice(&mut self) -> &mut [MaybeUninit<u8>] {
+        unsafe { slice::from_raw_parts_mut(self.vec.buf.cast(), self.vec.len as usize) }
+    }
+}
+
 fn init() {
     static INIT: Once = Once::new();
 
@@ -293,7 +323,7 @@ pub(crate) fn recv(socket: Socket, buf: &mut [MaybeUninit<u8>], flags: c_int) ->
 
 pub(crate) fn recv_vectored(
     socket: Socket,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &mut [crate::MaybeUninitSlice<'_>],
     flags: c_int,
 ) -> io::Result<(usize, RecvFlags)> {
     let mut nread = 0;
@@ -354,7 +384,7 @@ pub(crate) fn recv_from(
 
 pub(crate) fn recv_from_vectored(
     socket: Socket,
-    bufs: &mut [IoSliceMut<'_>],
+    bufs: &mut [crate::MaybeUninitSlice<'_>],
     flags: c_int,
 ) -> io::Result<(usize, RecvFlags, SockAddr)> {
     // Safety: `recvfrom` initialises the `SockAddr` for us.


Test patch:
diff --git a/tests/socket.rs b/tests/socket.rs
index 2b44b60..e0987d1 100644
--- a/tests/socket.rs
+++ b/tests/socket.rs
@@ -2,13 +2,15 @@
 use std::ffi::CStr;
 #[cfg(any(windows, target_vendor = "apple"))]
 use std::io;
+#[cfg(not(target_os = "redox"))]
+use std::io::IoSlice;
 #[cfg(all(unix, feature = "all"))]
 use std::io::Read;
 use std::io::Write;
-#[cfg(not(target_os = "redox"))]
-use std::io::{IoSlice, IoSliceMut};
 use std::mem::MaybeUninit;
-use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
+use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+#[cfg(not(target_os = "redox"))]
+use std::net::{Ipv6Addr, SocketAddrV6};
 #[cfg(unix)]
 use std::os::unix::io::AsRawFd;
 #[cfg(windows)]
@@ -26,6 +28,8 @@ use winapi::um::handleapi::GetHandleInformation;
 #[cfg(windows)]
 use winapi::um::winbase::HANDLE_FLAG_INHERIT;
 
+#[cfg(not(target_os = "redox"))]
+use socket2::MaybeUninitSlice;
 use socket2::{Domain, Protocol, SockAddr, Socket, TcpKeepalive, Type};
 
 #[test]
@@ -385,21 +389,21 @@ fn send_recv_vectored() {
         .unwrap();
     assert_eq!(sent, 23);
 
-    let mut the = [0u8; 3];
-    let mut wee = [0u8; 3];
-    let mut knight = [0u8; 6];
-    let mut would = [0u8; 5];
-    let mut yell = [0u8; 4];
-    let mut ow = [0u8; 2];
+    let mut the = [MaybeUninit::new(1); 3];
+    let mut wee = [MaybeUninit::new(2); 3];
+    let mut knight = [MaybeUninit::new(3); 6];
+    let mut would = [MaybeUninit::new(4); 5];
+    let mut yell = [MaybeUninit::new(5); 4];
+    let mut ow = [MaybeUninit::new(6); 2];
 
     let (received, flags) = socket_b
         .recv_vectored(&mut [
-            IoSliceMut::new(&mut the),
-            IoSliceMut::new(&mut wee),
-            IoSliceMut::new(&mut knight),
-            IoSliceMut::new(&mut would),
-            IoSliceMut::new(&mut yell),
-            IoSliceMut::new(&mut ow),
+            MaybeUninitSlice::new(&mut the),
+            MaybeUninitSlice::new(&mut wee),
+            MaybeUninitSlice::new(&mut knight),
+            MaybeUninitSlice::new(&mut would),
+            MaybeUninitSlice::new(&mut yell),
+            MaybeUninitSlice::new(&mut ow),
         ])
         .unwrap();
     assert_eq!(received, 23);
@@ -409,12 +413,12 @@ fn send_recv_vectored() {
     assert_eq!(flags.is_out_of_band(), false);
     assert_eq!(flags.is_truncated(), false);
 
-    assert_eq!(&the, b"the");
-    assert_eq!(&wee, b"wee");
-    assert_eq!(&knight, b"knight");
-    assert_eq!(&would, b"would");
-    assert_eq!(&yell, b"yell");
-    assert_eq!(&ow, b"ow");
+    assert_eq!(unsafe { assume_init(&the) }, b"the");
+    assert_eq!(unsafe { assume_init(&wee) }, b"wee");
+    assert_eq!(unsafe { assume_init(&knight) }, b"knight");
+    assert_eq!(unsafe { assume_init(&would) }, b"would");
+    assert_eq!(unsafe { assume_init(&yell) }, b"yell");
+    assert_eq!(unsafe { assume_init(&ow) }, b"ow");
 }
 
 #[test]
@@ -436,16 +440,16 @@ fn send_from_recv_to_vectored() {
         .unwrap();
     assert_eq!(sent, 18);
 
-    let mut surgeon = [0u8; 7];
-    let mut has = [0u8; 3];
-    let mut men = [0u8; 3];
-    let mut swear = [0u8; 5];
+    let mut surgeon = [MaybeUninit::new(10); 7];
+    let mut has = [MaybeUninit::new(11); 3];
+    let mut men = [MaybeUninit::new(12); 3];
+    let mut swear = [MaybeUninit::new(13); 5];
     let (received, flags, addr) = socket_b
         .recv_from_vectored(&mut [
-            IoSliceMut::new(&mut surgeon),
-            IoSliceMut::new(&mut has),
-            IoSliceMut::new(&mut men),
-            IoSliceMut::new(&mut swear),
+            MaybeUninitSlice::new(&mut surgeon),
+            MaybeUninitSlice::new(&mut has),
+            MaybeUninitSlice::new(&mut men),
+            MaybeUninitSlice::new(&mut swear),
         ])
         .unwrap();
 
@@ -456,10 +460,11 @@ fn send_from_recv_to_vectored() {
     assert_eq!(flags.is_out_of_band(), false);
     assert_eq!(flags.is_truncated(), false);
     assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
-    assert_eq!(&surgeon, b"surgeon");
-    assert_eq!(&has, b"has");
-    assert_eq!(&men, b"men");
-    assert_eq!(&swear, b"swear");
+
+    assert_eq!(unsafe { assume_init(&surgeon) }, b"surgeon");
+    assert_eq!(unsafe { assume_init(&has) }, b"has");
+    assert_eq!(unsafe { assume_init(&men) }, b"men");
+    assert_eq!(unsafe { assume_init(&swear) }, b"swear");
 }
 
 #[test]
@@ -472,14 +477,14 @@ fn recv_vectored_truncated() {
         .unwrap();
     assert_eq!(sent, 39);
 
-    let mut buffer = [0u8; 24];
+    let mut buffer = [MaybeUninit::new(20); 24];
 
     let (received, flags) = socket_b
-        .recv_vectored(&mut [IoSliceMut::new(&mut buffer)])
+        .recv_vectored(&mut [MaybeUninitSlice::new(&mut buffer)])
         .unwrap();
     assert_eq!(received, 24);
     assert_eq!(flags.is_truncated(), true);
-    assert_eq!(&buffer, b"do not feed the gremlins");
+    assert_eq!(unsafe { assume_init(&buffer) }, b"do not feed the gremlins");
 }
 
 #[test]
@@ -494,15 +499,15 @@ fn recv_from_vectored_truncated() {
         .unwrap();
     assert_eq!(sent, 39);
 
-    let mut buffer = [0u8; 24];
+    let mut buffer = [MaybeUninit::new(30); 24];
 
     let (received, flags, addr) = socket_b
-        .recv_from_vectored(&mut [IoSliceMut::new(&mut buffer)])
+        .recv_from_vectored(&mut [MaybeUninitSlice::new(&mut buffer)])
         .unwrap();
     assert_eq!(received, 24);
     assert_eq!(flags.is_truncated(), true);
     assert_eq!(addr.as_inet6().unwrap(), addr_a.as_inet6().unwrap());
-    assert_eq!(&buffer, b"do not feed the gremlins");
+    assert_eq!(unsafe { assume_init(&buffer) }, b"do not feed the gremlins");
 }
 
 /// Create a pair of non-connected UDP sockets suitable for unit tests.
@@ -721,7 +726,7 @@ test!(reuse_address, set_reuse_address(true));
     not(any(windows, target_os = "solaris", target_os = "illumos"))
 ))]
 test!(reuse_port, set_reuse_port(true));
-#[cfg(all(feature = "all", unix))]
+#[cfg(all(feature = "all", unix, not(target_os = "redox")))]
 test!(
     #[cfg_attr(target_os = "linux", ignore = "Different value returned")]
     mss,