Skip to content

Commit fcf28c6

Browse files
committed
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.
2 parents be1a8de + 38cf5b1 commit fcf28c6

File tree

14 files changed

+235
-33
lines changed

14 files changed

+235
-33
lines changed

ci/docker/x86_64-rumprun-netbsd/runtest.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ fn find_ok(input: &mut Read, tx: mpsc::Sender<()>) {
4747
for line in BufReader::new(input).lines() {
4848
let line = line.unwrap();
4949
println!("{}", line);
50-
if line.starts_with("PASSED ") && line.contains(" tests") {
50+
if (line.starts_with("PASSED ") && line.contains(" tests")) ||
51+
line.starts_with("test result: ok"){
5152
tx.send(()).unwrap();
5253
}
5354
}

ci/ios/deploy_and_run_on_ios_simulator.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,11 @@ fn run_app_on_simulator() {
129129

130130
let stdout = String::from_utf8_lossy(&output.stdout);
131131
let passed = stdout.lines()
132-
.find(|l| l.contains("PASSED"))
133-
.map(|l| l.contains("tests"))
132+
.find(|l|
133+
(l.contains("PASSED") &&
134+
l.contains("tests")) ||
135+
l.contains("test result: ok")
136+
)
134137
.unwrap_or(false);
135138

136139
println!("Shutting down simulator");

ci/run.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ if [ "$QEMU" != "" ]; then
7777
-net user \
7878
-nographic \
7979
-vga none 2>&1 | tee "${CARGO_TARGET_DIR}/out.log"
80-
exec grep "^PASSED .* tests" "${CARGO_TARGET_DIR}/out.log"
80+
exec egrep "^(PASSED)|(test result: ok)" "${CARGO_TARGET_DIR}/out.log"
8181
fi
8282

8383
# FIXME: x86_64-unknown-linux-gnux32 fail to compile without --release

ci/runtest-android.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ fn main() {
3838
String::from_utf8_lossy(&output.stderr));
3939

4040
let stdout = String::from_utf8_lossy(&output.stdout);
41-
let mut lines = stdout.lines().filter(|l| l.starts_with("PASSED "));
42-
if !lines.any(|l| l.contains(" tests")) {
41+
let passed = stdout.lines().find(|l|
42+
(l.starts_with("PASSED ") && l.contains(" tests")) ||
43+
l.starts_with("test result: ok")
44+
).unwrap_or_else(|| {
4345
panic!("failed to find successful test run");
44-
}
46+
});
4547
}

ci/test-runner-linux

+13-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,18 @@ set -e
55
arch=$1
66
prog=$2
77

8+
# Skip cmsg test on linux-s390x
9+
# https://github.com/rust-lang/libc/issues/1240
10+
if [ "$arch" = "s390x" ]; then
11+
progbasename=`basename $prog`
12+
if [ "${progbasename%%-*}" = "cmsg" ]; then
13+
exit 0
14+
fi
15+
fi
16+
817
cd /qemu/init
18+
echo "#!/bin/sh\n/prog --color=never" > run_prog.sh
19+
chmod +x run_prog.sh
920
cp -f $2 prog
1021
find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz
1122
cd ..
@@ -15,9 +26,9 @@ timeout 30s qemu-system-$arch \
1526
-nographic \
1627
-kernel kernel \
1728
-initrd initrd.gz \
18-
-append init=/prog > output || true
29+
-append init=/run_prog.sh > output || true
1930

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

23-
grep PASSED output > /dev/null
34+
egrep "(PASSED)|(test result: ok)" output > /dev/null

libc-test/Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ path = ".."
99
default-features = false
1010

1111
[build-dependencies]
12+
cc = "1.0"
1213
ctest = "0.2.8"
1314

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

31+
[[test]]
32+
name = "cmsg"
33+
path = "test/cmsg.rs"
34+
harness = true

libc-test/build.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
#![deny(warnings)]
22

3+
extern crate cc;
34
extern crate ctest;
45

56
use std::env;
67

7-
fn main() {
8+
#[cfg(unix)]
9+
fn do_cc() {
10+
cc::Build::new()
11+
.file("src/cmsg.c")
12+
.compile("cmsg");
13+
}
14+
#[cfg(not(unix))]
15+
fn do_cc() {
16+
}
17+
18+
fn do_ctest() {
819
let target = env::var("TARGET").unwrap();
920
let aarch64 = target.contains("aarch64");
1021
let i686 = target.contains("i686");
@@ -975,3 +986,8 @@ fn main() {
975986
}
976987
cfg.generate("../src/lib.rs", "linux_fcntl.rs");
977988
}
989+
990+
fn main() {
991+
do_cc();
992+
do_ctest();
993+
}

libc-test/src/cmsg.c

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <sys/param.h>
2+
#include <sys/socket.h>
3+
4+
// Since the cmsg(3) macros are macros instead of functions, they aren't
5+
// available to FFI. libc must reimplement them, which is error-prone. This
6+
// file provides FFI access to the actual macros so they can be tested against
7+
// the Rust reimplementations.
8+
9+
struct cmsghdr *cmsg_firsthdr(struct msghdr *msgh) {
10+
return CMSG_FIRSTHDR(msgh);
11+
}
12+
13+
struct cmsghdr *cmsg_nxthdr(struct msghdr *msgh, struct cmsghdr *cmsg) {
14+
return CMSG_NXTHDR(msgh, cmsg);
15+
}
16+
17+
size_t cmsg_space(size_t length) {
18+
return CMSG_SPACE(length);
19+
}
20+
21+
size_t cmsg_len(size_t length) {
22+
return CMSG_LEN(length);
23+
}
24+
25+
unsigned char *cmsg_data(struct cmsghdr *cmsg) {
26+
return CMSG_DATA(cmsg);
27+
}
28+

libc-test/test/cmsg.rs

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! Compare libc's CMSG(3) family of functions against the actual C macros, for
2+
//! various inputs.
3+
4+
extern crate libc;
5+
6+
#[cfg(unix)]
7+
mod t {
8+
9+
use libc::{self, c_uchar, c_uint, c_void, cmsghdr, msghdr};
10+
use std::mem;
11+
12+
extern {
13+
pub fn cmsg_firsthdr(msgh: *const msghdr) -> *mut cmsghdr;
14+
pub fn cmsg_nxthdr(mhdr: *const msghdr,
15+
cmsg: *const cmsghdr) -> *mut cmsghdr;
16+
pub fn cmsg_space(length: c_uint) -> usize;
17+
pub fn cmsg_len(length: c_uint) -> usize;
18+
pub fn cmsg_data(cmsg: *const cmsghdr) -> *mut c_uchar;
19+
}
20+
21+
#[test]
22+
fn test_cmsg_data() {
23+
for l in 0..128 {
24+
let pcmsghdr = l as *const cmsghdr;
25+
unsafe {
26+
assert_eq!(libc::CMSG_DATA(pcmsghdr), cmsg_data(pcmsghdr));
27+
}
28+
}
29+
}
30+
31+
#[test]
32+
fn test_cmsg_firsthdr() {
33+
let mut mhdr: msghdr = unsafe{mem::zeroed()};
34+
mhdr.msg_control = 0xdeadbeef as *mut c_void;
35+
let pmhdr = &mhdr as *const msghdr;
36+
for l in 0..128 {
37+
mhdr.msg_controllen = l;
38+
unsafe {
39+
assert_eq!(libc::CMSG_FIRSTHDR(pmhdr), cmsg_firsthdr(pmhdr));
40+
}
41+
}
42+
}
43+
44+
#[test]
45+
fn test_cmsg_len() {
46+
for l in 0..128 {
47+
unsafe {
48+
assert_eq!(libc::CMSG_LEN(l) as usize, cmsg_len(l));
49+
}
50+
}
51+
}
52+
53+
// Skip on sparc64
54+
// https://github.com/rust-lang/libc/issues/1239
55+
#[cfg(not(target_arch = "sparc64"))]
56+
#[test]
57+
fn test_cmsg_nxthdr() {
58+
use std::ptr;
59+
60+
let mut buffer = [0u8; 256];
61+
let mut mhdr: msghdr = unsafe{mem::zeroed()};
62+
let pmhdr = &mhdr as *const msghdr;
63+
for start_ofs in 0..64 {
64+
let pcmsghdr = &mut buffer[start_ofs] as *mut u8 as *mut cmsghdr;
65+
mhdr.msg_control = pcmsghdr as *mut c_void;
66+
mhdr.msg_controllen = (160 - start_ofs) as _;
67+
for cmsg_len in 0..64 {
68+
for next_cmsg_len in 0..32 {
69+
for i in buffer[start_ofs..].iter_mut() {
70+
*i = 0;
71+
}
72+
unsafe {
73+
(*pcmsghdr).cmsg_len = cmsg_len;
74+
let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
75+
let next = cmsg_nxthdr(pmhdr, pcmsghdr);
76+
assert_eq!(libc_next, next);
77+
78+
if libc_next != ptr::null_mut() {
79+
(*libc_next).cmsg_len = next_cmsg_len;
80+
let libc_next = libc::CMSG_NXTHDR(pmhdr, pcmsghdr);
81+
let next = cmsg_nxthdr(pmhdr, pcmsghdr);
82+
assert_eq!(libc_next, next);
83+
}
84+
}
85+
}
86+
}
87+
}
88+
}
89+
90+
#[test]
91+
fn test_cmsg_space() {
92+
unsafe {
93+
for l in 0..128 {
94+
assert_eq!(libc::CMSG_SPACE(l) as usize, cmsg_space(l));
95+
}
96+
}
97+
}
98+
99+
}

src/unix/bsd/apple/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -2777,11 +2777,10 @@ f! {
27772777
return ::CMSG_FIRSTHDR(mhdr);
27782778
};
27792779
let cmsg_len = (*cmsg).cmsg_len as usize;
2780-
let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len as usize)
2781-
+ __DARWIN_ALIGN32(mem::size_of::<::cmsghdr>());
2780+
let next = cmsg as usize + __DARWIN_ALIGN32(cmsg_len as usize);
27822781
let max = (*mhdr).msg_control as usize
27832782
+ (*mhdr).msg_controllen as usize;
2784-
if next > max {
2783+
if next + __DARWIN_ALIGN32(mem::size_of::<::cmsghdr>()) > max {
27852784
0 as *mut ::cmsghdr
27862785
} else {
27872786
next as *mut ::cmsghdr
@@ -2800,7 +2799,7 @@ f! {
28002799
}
28012800

28022801
pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint {
2803-
__DARWIN_ALIGN32(mem::size_of::<::cmsghdr>() + length as usize)
2802+
(__DARWIN_ALIGN32(mem::size_of::<::cmsghdr>()) + length as usize)
28042803
as ::c_uint
28052804
}
28062805

src/unix/notbsd/android/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,20 @@ pub const MODULE_INIT_IGNORE_VERMAGIC: ::c_uint = 0x0002;
16881688
pub const ENOATTR: ::c_int = ::ENODATA;
16891689

16901690
f! {
1691+
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
1692+
cmsg: *const cmsghdr) -> *mut cmsghdr {
1693+
let next = (cmsg as usize
1694+
+ super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
1695+
as *mut cmsghdr;
1696+
let max = (*mhdr).msg_control as usize
1697+
+ (*mhdr).msg_controllen as usize;
1698+
if (next.offset(1)) as usize > max {
1699+
0 as *mut cmsghdr
1700+
} else {
1701+
next as *mut cmsghdr
1702+
}
1703+
}
1704+
16911705
pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
16921706
for slot in cpuset.__bits.iter_mut() {
16931707
*slot = 0;

src/unix/notbsd/emscripten.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1515,6 +1515,23 @@ pub const ARPD_FLUSH: ::c_ushort = 0x03;
15151515
pub const ATF_MAGIC: ::c_int = 0x80;
15161516

15171517
f! {
1518+
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
1519+
cmsg: *const cmsghdr) -> *mut cmsghdr {
1520+
if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
1521+
return 0 as *mut cmsghdr;
1522+
};
1523+
let next = (cmsg as usize +
1524+
super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
1525+
as *mut cmsghdr;
1526+
let max = (*mhdr).msg_control as usize
1527+
+ (*mhdr).msg_controllen as usize;
1528+
if (next.offset(1)) as usize > max {
1529+
0 as *mut cmsghdr
1530+
} else {
1531+
next as *mut cmsghdr
1532+
}
1533+
}
1534+
15181535
pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
15191536
for slot in cpuset.bits.iter_mut() {
15201537
*slot = 0;

src/unix/notbsd/linux/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,25 @@ pub const SOF_TIMESTAMPING_SYS_HARDWARE: ::c_uint = 1 << 5;
18971897
pub const SOF_TIMESTAMPING_RAW_HARDWARE: ::c_uint = 1 << 6;
18981898

18991899
f! {
1900+
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
1901+
cmsg: *const cmsghdr) -> *mut cmsghdr {
1902+
if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
1903+
return 0 as *mut cmsghdr;
1904+
};
1905+
let next = (cmsg as usize +
1906+
super::CMSG_ALIGN((*cmsg).cmsg_len as usize))
1907+
as *mut cmsghdr;
1908+
let max = (*mhdr).msg_control as usize
1909+
+ (*mhdr).msg_controllen as usize;
1910+
if (next.offset(1)) as usize > max ||
1911+
next as usize + super::CMSG_ALIGN((*next).cmsg_len as usize) > max
1912+
{
1913+
0 as *mut cmsghdr
1914+
} else {
1915+
next as *mut cmsghdr
1916+
}
1917+
}
1918+
19001919
pub fn CPU_ZERO(cpuset: &mut cpu_set_t) -> () {
19011920
for slot in cpuset.bits.iter_mut() {
19021921
*slot = 0;

src/unix/notbsd/mod.rs

+7-19
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,10 @@ pub const ARPHRD_IEEE802154: u16 = 804;
11141114
pub const ARPHRD_VOID: u16 = 0xFFFF;
11151115
pub const ARPHRD_NONE: u16 = 0xFFFE;
11161116

1117+
fn CMSG_ALIGN(len: usize) -> usize {
1118+
len + mem::size_of::<usize>() - 1 & !(mem::size_of::<usize>() - 1)
1119+
}
1120+
11171121
f! {
11181122
pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr {
11191123
if (*mhdr).msg_controllen as usize >= mem::size_of::<cmsghdr>() {
@@ -1123,33 +1127,17 @@ f! {
11231127
}
11241128
}
11251129

1126-
pub fn CMSG_NXTHDR(mhdr: *const msghdr,
1127-
cmsg: *const cmsghdr) -> *mut cmsghdr {
1128-
if cmsg.is_null() {
1129-
return CMSG_FIRSTHDR(mhdr);
1130-
};
1131-
let pad = mem::align_of::<cmsghdr>() - 1;
1132-
let next = cmsg as usize + (*cmsg).cmsg_len as usize + pad & !pad;
1133-
let max = (*mhdr).msg_control as usize
1134-
+ (*mhdr).msg_controllen as usize;
1135-
if next < max {
1136-
next as *mut cmsghdr
1137-
} else {
1138-
0 as *mut cmsghdr
1139-
}
1140-
}
1141-
11421130
pub fn CMSG_DATA(cmsg: *const cmsghdr) -> *mut ::c_uchar {
11431131
cmsg.offset(1) as *mut ::c_uchar
11441132
}
11451133

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

11511139
pub fn CMSG_LEN(length: ::c_uint) -> ::c_uint {
1152-
mem::size_of::<cmsghdr>() as ::c_uint + length
1140+
CMSG_ALIGN(mem::size_of::<cmsghdr>()) as ::c_uint + length
11531141
}
11541142

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

0 commit comments

Comments
 (0)