Skip to content

Commit a71e6c8

Browse files
committed
Fix sendmsg on macOS when passing a zero entry cmsgs array.
1 parent 37db5e2 commit a71e6c8

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
5151
`Android` ([#631](https://github.com/nix-rust/nix/pull/631)).
5252
- `bind` and `errno_location` now work correctly on `Android`
5353
([#631](https://github.com/nix-rust/nix/pull/631))
54+
- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter.
55+
([#623](https://github.com/nix-rust/nix/pull/623))
5456

5557
## [0.8.1] 2017-04-16
5658

src/sys/socket/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,18 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
277277
None => (0 as *const _, 0),
278278
};
279279

280+
let cmsg_ptr = if capacity > 0 {
281+
cmsg_buffer.as_ptr() as *const c_void
282+
} else {
283+
ptr::null()
284+
};
285+
280286
let mhdr = msghdr {
281287
msg_name: name as *const c_void,
282288
msg_namelen: namelen,
283289
msg_iov: iov.as_ptr(),
284290
msg_iovlen: iov.len() as size_t,
285-
msg_control: cmsg_buffer.as_ptr() as *const c_void,
291+
msg_control: cmsg_ptr,
286292
msg_controllen: capacity as size_t,
287293
msg_flags: 0,
288294
};

test/sys/test_socket.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,43 @@ pub fn test_scm_rights() {
145145
close(w).unwrap();
146146
}
147147

148+
// Verify `sendmsg` builds a valid `msghdr` when passing an empty
149+
// `cmsgs` argument. This should result in a msghdr with a nullptr
150+
// msg_control field and a msg_controllen of 0 when calling into the
151+
// raw `sendmsg`.
152+
#[test]
153+
pub fn test_sendmsg_empty_cmsgs() {
154+
use nix::sys::uio::IoVec;
155+
use nix::unistd::close;
156+
use nix::sys::socket::{socketpair, sendmsg, recvmsg,
157+
AddressFamily, SockType, SockFlag,
158+
CmsgSpace, MsgFlags,
159+
MSG_TRUNC, MSG_CTRUNC};
160+
161+
let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, 0,
162+
SockFlag::empty())
163+
.unwrap();
164+
165+
{
166+
let iov = [IoVec::from_slice(b"hello")];
167+
assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
168+
close(fd1).unwrap();
169+
}
170+
171+
{
172+
let mut buf = [0u8; 5];
173+
let iov = [IoVec::from_mut_slice(&mut buf[..])];
174+
let mut cmsgspace: CmsgSpace<[RawFd; 1]> = CmsgSpace::new();
175+
let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
176+
177+
for _ in msg.cmsgs() {
178+
panic!("unexpected cmsg");
179+
}
180+
assert_eq!(msg.flags & (MSG_TRUNC | MSG_CTRUNC), MsgFlags::empty());
181+
close(fd2).unwrap();
182+
}
183+
}
184+
148185
// Test creating and using named unix domain sockets
149186
#[test]
150187
pub fn test_unixdomain() {

0 commit comments

Comments
 (0)