Auto merge of #1235 - asomers:cmsg_osx, r=gnzlbg

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.
This commit is contained in:
bors 2019-02-05 17:19:39 +00:00
commit f9b96ee6a1
14 changed files with 235 additions and 33 deletions

View File

@ -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();
}
}

View File

@ -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");

View File

@ -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

View File

@ -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");
}
});
}

View File

@ -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 ..
@ -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

View File

@ -9,6 +9,7 @@ path = ".."
default-features = false
[build-dependencies]
cc = "1.0"
ctest = "0.2.8"
[features]
@ -27,3 +28,7 @@ name = "linux-fcntl"
path = "test/linux_fcntl.rs"
harness = false
[[test]]
name = "cmsg"
path = "test/cmsg.rs"
harness = true

View File

@ -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");
@ -975,3 +986,8 @@ fn main() {
}
cfg.generate("../src/lib.rs", "linux_fcntl.rs");
}
fn main() {
do_cc();
do_ctest();
}

28
libc-test/src/cmsg.c Normal file
View File

@ -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
libc-test/test/cmsg.rs Normal file
View File

@ -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));
}
}
}
}

View File

@ -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
@ -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
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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>() {
@ -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) -> () {