Skip to content

Commit 38cf5b1

Browse files
committed
Add an integration test for the cmsg(3) functions.
Since these are defined in C as macros, they must be reimplemented in libc as Rust functions. They're hard to get exactly right, and they vary from platform to platform. The test builds custom C code that uses the real macros, and compares its output to the Rust versions' output for various inputs. Skip the CMSG_NXTHDR test on sparc64 linux because it hits a Bus Error. Issue #1239 Skip the entire cmsg test program on s390x because it dumps core seemingly before the kernel finishes booting. Issue #1240
1 parent eddc8d3 commit 38cf5b1

File tree

9 files changed

+175
-10
lines changed

9 files changed

+175
-10
lines changed

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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 5 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 5 additions & 3 deletions
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

Lines changed: 13 additions & 2 deletions
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

Lines changed: 5 additions & 0 deletions
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

Lines changed: 17 additions & 1 deletion
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

Lines changed: 28 additions & 0 deletions
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

Lines changed: 99 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)