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:
commit
f9b96ee6a1
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) -> () {
|
||||
|
|
Loading…
Reference in New Issue