Skip to content

Commit

Permalink
Auto merge of #1235 - asomers:cmsg_osx, r=gnzlbg
Browse files Browse the repository at this point in the history
Fix cmsg(3) bugs for musl and OSX

This PR fixes bugs in the cmsg(3) family of functions for Linux/musl and OSX, introduced by PR #1098 and PR #1212 .  It also adds an integration test which hopefully will validate these functions on every platform.
  • Loading branch information
bors committed Feb 5, 2019
2 parents be1a8de + 38cf5b1 commit fcf28c6
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 33 deletions.
3 changes: 2 additions & 1 deletion ci/docker/x86_64-rumprun-netbsd/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ fn find_ok(input: &mut Read, tx: mpsc::Sender<()>) {
for line in BufReader::new(input).lines() {
let line = line.unwrap();
println!("{}", line);
if line.starts_with("PASSED ") && line.contains(" tests") {
if (line.starts_with("PASSED ") && line.contains(" tests")) ||
line.starts_with("test result: ok"){
tx.send(()).unwrap();
}
}
Expand Down
7 changes: 5 additions & 2 deletions ci/ios/deploy_and_run_on_ios_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ fn run_app_on_simulator() {

let stdout = String::from_utf8_lossy(&output.stdout);
let passed = stdout.lines()
.find(|l| l.contains("PASSED"))
.map(|l| l.contains("tests"))
.find(|l|
(l.contains("PASSED") &&
l.contains("tests")) ||
l.contains("test result: ok")
)
.unwrap_or(false);

println!("Shutting down simulator");
Expand Down
2 changes: 1 addition & 1 deletion ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ if [ "$QEMU" != "" ]; then
-net user \
-nographic \
-vga none 2>&1 | tee "${CARGO_TARGET_DIR}/out.log"
exec grep "^PASSED .* tests" "${CARGO_TARGET_DIR}/out.log"
exec egrep "^(PASSED)|(test result: ok)" "${CARGO_TARGET_DIR}/out.log"
fi

# FIXME: x86_64-unknown-linux-gnux32 fail to compile without --release
Expand Down
8 changes: 5 additions & 3 deletions ci/runtest-android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ fn main() {
String::from_utf8_lossy(&output.stderr));

let stdout = String::from_utf8_lossy(&output.stdout);
let mut lines = stdout.lines().filter(|l| l.starts_with("PASSED "));
if !lines.any(|l| l.contains(" tests")) {
let passed = stdout.lines().find(|l|
(l.starts_with("PASSED ") && l.contains(" tests")) ||
l.starts_with("test result: ok")
).unwrap_or_else(|| {
panic!("failed to find successful test run");
}
});
}
15 changes: 13 additions & 2 deletions ci/test-runner-linux
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,18 @@ set -e
arch=$1
prog=$2

# Skip cmsg test on linux-s390x
# https://github.com/rust-lang/libc/issues/1240
if [ "$arch" = "s390x" ]; then
progbasename=`basename $prog`
if [ "${progbasename%%-*}" = "cmsg" ]; then
exit 0
fi
fi

cd /qemu/init
echo "#!/bin/sh\n/prog --color=never" > run_prog.sh
chmod +x run_prog.sh
cp -f $2 prog
find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz
cd ..
Expand All @@ -15,9 +26,9 @@ timeout 30s qemu-system-$arch \
-nographic \
-kernel kernel \
-initrd initrd.gz \
-append init=/prog > output || true
-append init=/run_prog.sh > output || true

# remove kernel messages
tr -d '\r' < output | egrep -v '^\['

grep PASSED output > /dev/null
egrep "(PASSED)|(test result: ok)" output > /dev/null
5 changes: 5 additions & 0 deletions libc-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ path = ".."
default-features = false

[build-dependencies]
cc = "1.0"
ctest = "0.2.8"

[features]
Expand All @@ -27,3 +28,7 @@ name = "linux-fcntl"
path = "test/linux_fcntl.rs"
harness = false

[[test]]
name = "cmsg"
path = "test/cmsg.rs"
harness = true
18 changes: 17 additions & 1 deletion libc-test/build.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
#![deny(warnings)]

extern crate cc;
extern crate ctest;

use std::env;

fn main() {
#[cfg(unix)]
fn do_cc() {
cc::Build::new()
.file("src/cmsg.c")
.compile("cmsg");
}
#[cfg(not(unix))]
fn do_cc() {
}

fn do_ctest() {
let target = env::var("TARGET").unwrap();
let aarch64 = target.contains("aarch64");
let i686 = target.contains("i686");
Expand Down Expand Up @@ -975,3 +986,8 @@ fn main() {
}
cfg.generate("../src/lib.rs", "linux_fcntl.rs");
}

fn main() {
do_cc();
do_ctest();
}
28 changes: 28 additions & 0 deletions libc-test/src/cmsg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <sys/param.h>
#include <sys/socket.h>

// Since the cmsg(3) macros are macros instead of functions, they aren't
// available to FFI. libc must reimplement them, which is error-prone. This
// file provides FFI access to the actual macros so they can be tested against
// the Rust reimplementations.

struct cmsghdr *cmsg_firsthdr(struct msghdr *msgh) {
return CMSG_FIRSTHDR(msgh);
}

struct cmsghdr *cmsg_nxthdr(struct msghdr *msgh, struct cmsghdr *cmsg) {
return CMSG_NXTHDR(msgh, cmsg);
}

size_t cmsg_space(size_t length) {
return CMSG_SPACE(length);
}

size_t cmsg_len(size_t length) {
return CMSG_LEN(length);
}

unsigned char *cmsg_data(struct cmsghdr *cmsg) {
return CMSG_DATA(cmsg);
}

99 changes: 99 additions & 0 deletions libc-test/test/cmsg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! Compare libc's CMSG(3) family of functions against the actual C macros, for
//! various inputs.

extern crate libc;

#[cfg(unix)]
mod t {

use libc::{self, c_uchar, c_uint, c_void, cmsghdr, msghdr};
use std::mem;

extern {
pub fn cmsg_firsthdr(msgh: *const msghdr) -> *mut cmsghdr;
pub fn cmsg_nxthdr(mhdr: *const msghdr,
cmsg: *const cmsghdr) -> *mut cmsghdr;
pub fn cmsg_space(length: c_uint) -> usize;
pub fn cmsg_len(length: c_uint) -> usize;
pub fn cmsg_data(cmsg: *const cmsghdr) -> *mut c_uchar;
}

#[test]
fn test_cmsg_data() {
for l in 0..128 {
let pcmsghdr = l as *const cmsghdr;
unsafe {
assert_eq!(libc::CMSG_DATA(pcmsghdr), cmsg_data(pcmsghdr));
}
}
}

#[test]
fn test_cmsg_firsthdr() {
let mut mhdr: msghdr = unsafe{mem::zeroed()};
mhdr.msg_control = 0xdeadbeef as *mut c_void;
let pmhdr = &mhdr as *const msghdr;
for l in 0..128 {
mhdr.msg_controllen = l;
unsafe {
assert_eq!(libc::CMSG_FIRSTHDR(pmhdr), cmsg_firsthdr(pmhdr));
}
}
}

#[test]
fn test_cmsg_len() {
for l in 0..128 {
unsafe {
assert_eq!(libc::CMSG_LEN(l) as usize, cmsg_len(l));
}
}
}

// Skip on sparc64
// https://github.com/rust-lang/libc/issues/1239
#[cfg(not(target_arch = "sparc64"))]
#[test]
fn test_cmsg_nxthdr() {
use std::ptr;

let mut buffer = [0u8; 256];
let mut mhdr: msghdr = unsafe{mem::zeroed()};
let pmhdr = &mhdr as *const msghdr;
for start_ofs in 0..64 {
let pcmsghdr = &mut buffer[start_ofs] as *mut u8 as *mut cmsghdr;
mhdr.msg_control = pcmsghdr as *mut c_void;
mhdr.msg_controllen = (160 - start_ofs) as _;
for cmsg_len in 0..64 {
for next_cmsg_len in 0..32 {
for i in buffer[start_ofs..].iter_mut() {
*i = 0;
}
unsafe {
(*pcmsghdr).cmsg_len = cmsg_len;
let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
let next = cmsg_nxthdr(pmhdr, pcmsghdr);
assert_eq!(libc_next, next);

if libc_next != ptr::null_mut() {
(*libc_next).cmsg_len = next_cmsg_len;
let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
let next = cmsg_nxthdr(pmhdr, pcmsghdr);
assert_eq!(libc_next, next);
}
}
}
}
}
}

#[test]
fn test_cmsg_space() {
unsafe {
for l in 0..128 {
assert_eq!(libc::CMSG_SPACE(l) as usize, cmsg_space(l));
}
}
}

}
7 changes: 3 additions & 4 deletions src/unix/bsd/apple/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2777,11 +2777,10 @@ f! {
return ::CMSG_FIRSTHDR(mhdr);
};
let cmsg_len = (*cmsg).cmsg_len as usize;
let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len as usize)
+ __DARWIN_ALIGN32(mem::size_of::<::cmsghdr>());
let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len as usize);
let max = (*mhdr).msg_control as usize
+ (*mhdr).msg_controllen as usize;
if next > max {
if next + __DARWIN_ALIGN32(mem::size_of::<::cmsghdr>()) > max {
0 as *mut ::cmsghdr
} else {
next as *mut ::cmsghdr
Expand All @@ -2800,7 +2799,7 @@ f! {
}

pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint {
__DARWIN_ALIGN32(mem::size_of::<::cmsghdr>() + length as usize)
(__DARWIN_ALIGN32(mem::size_of::<::cmsghdr>()) + length as usize)
as ::c_uint
}

Expand Down
14 changes: 14 additions & 0 deletions src/unix/notbsd/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,20 @@ pub const MODULE_INIT_IGNORE_VERMAGIC: ::c_uint = 0x0002;
pub const ENOATTR: ::c_int = ::ENODATA;

f! {
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
cmsg: *const cmsghdr) -> *mut cmsghdr {
let next = (cmsg as usize
+ super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
as *mut cmsghdr;
let max = (*mhdr).msg_control as usize
+ (*mhdr).msg_controllen as usize;
if (next.offset(1)) as usize > max {
0 as *mut cmsghdr
} else {
next as *mut cmsghdr
}
}

pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
for slot in cpuset.__bits.iter_mut() {
*slot = 0;
Expand Down
17 changes: 17 additions & 0 deletions src/unix/notbsd/emscripten.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,23 @@ pub const ARPD_FLUSH: ::c_ushort = 0x03;
pub const ATF_MAGIC: ::c_int = 0x80;

f! {
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
cmsg: *const cmsghdr) -> *mut cmsghdr {
if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
return 0 as *mut cmsghdr;
};
let next = (cmsg as usize +
super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
as *mut cmsghdr;
let max = (*mhdr).msg_control as usize
+ (*mhdr).msg_controllen as usize;
if (next.offset(1)) as usize > max {
0 as *mut cmsghdr
} else {
next as *mut cmsghdr
}
}

pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
for slot in cpuset.bits.iter_mut() {
*slot = 0;
Expand Down
19 changes: 19 additions & 0 deletions src/unix/notbsd/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1897,6 +1897,25 @@ pub const SOF_TIMESTAMPING_SYS_HARDWARE: ::c_uint = 1 << 5;
pub const SOF_TIMESTAMPING_RAW_HARDWARE: ::c_uint = 1 << 6;

f! {
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
cmsg: *const cmsghdr) -> *mut cmsghdr {
if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
return 0 as *mut cmsghdr;
};
let next = (cmsg as usize +
super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
as *mut cmsghdr;
let max = (*mhdr).msg_control as usize
+ (*mhdr).msg_controllen as usize;
if (next.offset(1)) as usize > max ||
next as usize + super::CMSG_ALIGN((*next).cmsg_len as usize) > max
{
0 as *mut cmsghdr
} else {
next as *mut cmsghdr
}
}

pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
for slot in cpuset.bits.iter_mut() {
*slot = 0;
Expand Down
26 changes: 7 additions & 19 deletions src/unix/notbsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,10 @@ pub const ARPHRD_IEEE802154: u16 = 804;
pub const ARPHRD_VOID: u16 = 0xFFFF;
pub const ARPHRD_NONE: u16 = 0xFFFE;

fn CMSG_ALIGN(len: usize) -> usize {
len + mem::size_of::<usize>() - 1 & !(mem::size_of::<usize>() - 1)
}

f! {
pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr {
if (*mhdr).msg_controllen as usize >= mem::size_of::<cmsghdr>() {
Expand All @@ -1123,33 +1127,17 @@ f! {
}
}

pub fn CMSG_NXTHDR(mhdr: *const msghdr,
cmsg: *const cmsghdr) -> *mut cmsghdr {
if cmsg.is_null() {
return CMSG_FIRSTHDR(mhdr);
};
let pad = mem::align_of::<cmsghdr>() - 1;
let next = cmsg as usize + (*cmsg).cmsg_len as usize + pad & !pad;
let max = (*mhdr).msg_control as usize
+ (*mhdr).msg_controllen as usize;
if next < max {
next as *mut cmsghdr
} else {
0 as *mut cmsghdr
}
}

pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut ::c_uchar {
cmsg.offset(1) as *mut ::c_uchar
}

pub fn CMSG_SPACE(length: ::c_uint) -> ::c_uint {
let pad = mem::align_of::<cmsghdr>() as ::c_uint - 1;
mem::size_of::<cmsghdr>() as ::c_uint + ((length + pad) & !pad)
(CMSG_ALIGN(length as usize) + CMSG_ALIGN(mem::size_of::<cmsghdr>()))
as ::c_uint
}

pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint {
mem::size_of::<cmsghdr>() as ::c_uint + length
CMSG_ALIGN(mem::size_of::<cmsghdr>()) as ::c_uint + length
}

pub fn FD_CLR(fd: ::c_int, set: *mut fd_set) -> () {
Expand Down

0 comments on commit fcf28c6

Please sign in to comment.