Skip to content

Commit

Permalink
Fix sendmsg on macOS when passing a zero entry cmsgs array.
Browse files Browse the repository at this point in the history
  • Loading branch information
kinetiknz committed Jul 10, 2017
1 parent 2e00adf commit 64815c6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added `nix::ptrace` on all Linux-kernel-based platforms
[#624](https://github.com/nix-rust/nix/pull/624). Previously it was
only available on x86, x86-64, and ARM, and also not on Android.
- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter.
([#623](https://github.com/nix-rust/nix/pull/623))

## [0.8.1] 2017-04-16

Expand Down
8 changes: 7 additions & 1 deletion src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,18 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
None => (0 as *const _, 0),
};

let cmsg_ptr = if capacity > 0 {
cmsg_buffer.as_ptr() as *const c_void
} else {
ptr::null()
};

let mhdr = msghdr {
msg_name: name as *const c_void,
msg_namelen: namelen,
msg_iov: iov.as_ptr(),
msg_iovlen: iov.len() as size_t,
msg_control: cmsg_buffer.as_ptr() as *const c_void,
msg_control: cmsg_ptr,
msg_controllen: capacity as size_t,
msg_flags: 0,
};
Expand Down
39 changes: 38 additions & 1 deletion test/sys/test_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub fn test_scm_rights() {
panic!("unexpected cmsg");
}
}
assert_eq!(msg.flags & (MSG_TRUNC | MSG_CTRUNC), MsgFlags::empty());
assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
close(fd2).unwrap();
}

Expand All @@ -145,6 +145,43 @@ pub fn test_scm_rights() {
close(w).unwrap();
}

// Verify `sendmsg` builds a valid `msghdr` when passing an empty
// `cmsgs` argument. This should result in a msghdr with a nullptr
// msg_control field and a msg_controllen of 0 when calling into the
// raw `sendmsg`.
#[test]
pub fn test_sendmsg_empty_cmsgs() {
use nix::sys::uio::IoVec;
use nix::unistd::close;
use nix::sys::socket::{socketpair, sendmsg, recvmsg,
AddressFamily, SockType, SockFlag,
CmsgSpace, MsgFlags,
MSG_TRUNC, MSG_CTRUNC};

let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, 0,
SockFlag::empty())
.unwrap();

{
let iov = [IoVec::from_slice(b"hello")];
assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
close(fd1).unwrap();
}

{
let mut buf = [0u8; 5];
let iov = [IoVec::from_mut_slice(&mut buf[..])];
let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();

for _ in msg.cmsgs() {
panic!("unexpected cmsg");
}
assert!(!msg.flags.intersects(MSG_TRUNC | MSG_CTRUNC));
close(fd2).unwrap();
}
}

// Test creating and using named unix domain sockets
#[test]
pub fn test_unixdomain() {
Expand Down

0 comments on commit 64815c6

Please sign in to comment.