Skip to content

Commit aac93b0

Browse files
committed
Don't assume representation of SocketAddr
1 parent ae13bda commit aac93b0

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

quinn/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ libc = "0.2.69"
3333
mio = { version = "0.7.7", features = ["net"] }
3434
proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.6.1" }
3535
rustls = { version = "0.19", features = ["quic"], optional = true }
36+
socket2 = "0.3"
3637
thiserror = "1.0.21"
3738
tracing = "0.1.10"
3839
tokio = { version = "1.0.1", features = ["net", "rt", "rt-multi-thread", "time"] }

quinn/src/platform/unix.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,25 @@ fn send(io: &mio::net::UdpSocket, transmits: &[Transmit]) -> io::Result<usize> {
198198
let mut msgs: [libc::mmsghdr; BATCH_SIZE] = unsafe { mem::zeroed() };
199199
let mut iovecs: [libc::iovec; BATCH_SIZE] = unsafe { mem::zeroed() };
200200
let mut cmsgs = [cmsg::Aligned([0u8; CMSG_LEN]); BATCH_SIZE];
201+
// This assume_init looks a bit weird because one might think it
202+
// assumes the SockAddr data to be initialized, but that call
203+
// refers to the whole array, which itself is made up of MaybeUninit
204+
// containers. Their presence protects the SockAddr inside from
205+
// being assumed as initialized by the assume_init call.
206+
// TODO: Replace this with uninit_array once it becomes MSRV-stable
207+
let mut addrs: [MaybeUninit<socket2::SockAddr>; BATCH_SIZE] =
208+
unsafe { MaybeUninit::uninit().assume_init() };
201209
for (i, transmit) in transmits.iter().enumerate().take(BATCH_SIZE) {
210+
let dest_addr = unsafe {
211+
std::ptr::write(
212+
addrs[i].as_mut_ptr(),
213+
socket2::SockAddr::from(transmit.destination),
214+
);
215+
&mut *(&mut addrs[i] as *mut _ as *mut _)
216+
};
202217
prepare_msg(
203218
transmit,
219+
dest_addr,
204220
&mut msgs[i].msg_hdr,
205221
&mut iovecs[i],
206222
&mut cmsgs[i],
@@ -233,7 +249,8 @@ fn send(io: &mio::net::UdpSocket, transmits: &[Transmit]) -> io::Result<usize> {
233249
let mut ctrl = cmsg::Aligned([0u8; CMSG_LEN]);
234250
let mut sent = 0;
235251
while sent < transmits.len() {
236-
prepare_msg(&transmits[sent], &mut hdr, &mut iov, &mut ctrl);
252+
let addr = socket2::SockAddr::from(transmits[sent].destination);
253+
prepare_msg(&transmits[sent], &addr, &mut hdr, &mut iov, &mut ctrl);
237254
let n = unsafe { libc::sendmsg(io.as_raw_fd(), &hdr, 0) };
238255
if n == -1 {
239256
let e = io::Error::last_os_error();
@@ -334,19 +351,23 @@ const CMSG_LEN: usize = 80;
334351

335352
fn prepare_msg(
336353
transmit: &Transmit,
354+
dest_addr: &socket2::SockAddr,
337355
hdr: &mut libc::msghdr,
338356
iov: &mut libc::iovec,
339357
ctrl: &mut cmsg::Aligned<[u8; CMSG_LEN]>,
340358
) {
341359
iov.iov_base = transmit.contents.as_ptr() as *const _ as *mut _;
342360
iov.iov_len = transmit.contents.len();
343361

344-
let (name, namelen) = match transmit.destination {
345-
SocketAddr::V4(ref addr) => (addr as *const _ as _, mem::size_of::<libc::sockaddr_in>()),
346-
SocketAddr::V6(ref addr) => (addr as *const _ as _, mem::size_of::<libc::sockaddr_in6>()),
347-
};
348-
hdr.msg_name = name;
349-
hdr.msg_namelen = namelen as _;
362+
// SAFETY: Casting the pointer to a mutable one is legal,
363+
// as sendmsg is guaranteed to not alter the mutable pointer
364+
// as per the POSIX spec. See the section on the sys/socket.h
365+
// header for details. The type is only mutable in the first
366+
// place because it is reused by recvmsg as well.
367+
let name = dest_addr.as_ptr() as *mut libc::c_void;
368+
let namelen = dest_addr.len();
369+
hdr.msg_name = name as *mut _;
370+
hdr.msg_namelen = namelen;
350371
hdr.msg_iov = iov;
351372
hdr.msg_iovlen = 1;
352373

0 commit comments

Comments
 (0)