diff options
Diffstat (limited to 'libc/libc-test')
-rw-r--r-- | libc/libc-test/Cargo.toml | 24 | ||||
-rw-r--r-- | libc/libc-test/build.rs | 1311 | ||||
-rw-r--r-- | libc/libc-test/test/linux_elf.rs | 12 | ||||
-rw-r--r-- | libc/libc-test/test/linux_fcntl.rs | 4 | ||||
-rw-r--r-- | libc/libc-test/test/linux_ipv6.rs | 12 | ||||
-rw-r--r-- | libc/libc-test/test/linux_strerror_r.rs | 12 | ||||
-rw-r--r-- | libc/libc-test/test/linux_termios.rs | 12 |
7 files changed, 500 insertions, 887 deletions
diff --git a/libc/libc-test/Cargo.toml b/libc/libc-test/Cargo.toml index 9862d3a..8d2d903 100644 --- a/libc/libc-test/Cargo.toml +++ b/libc/libc-test/Cargo.toml @@ -13,8 +13,8 @@ cc = "1.0" ctest = "0.2" [features] -default = [ "use_std" ] -use_std = [ "libc/use_std" ] +default = [ "std" ] +std = [ "libc/std" ] align = [ "libc/align" ] extra_traits = [ "libc/extra_traits" ] @@ -29,6 +29,26 @@ path = "test/linux_fcntl.rs" harness = false [[test]] +name = "linux-ipv6" +path = "test/linux_ipv6.rs" +harness = false + +[[test]] +name = "linux-elf" +path = "test/linux_elf.rs" +harness = false + +[[test]] +name = "linux-strerror_r" +path = "test/linux_strerror_r.rs" +harness = false + +[[test]] +name = "linux-termios" +path = "test/linux_termios.rs" +harness = false + +[[test]] name = "cmsg" path = "test/cmsg.rs" harness = true diff --git a/libc/libc-test/build.rs b/libc/libc-test/build.rs index 6541fd5..5087906 100644 --- a/libc/libc-test/build.rs +++ b/libc/libc-test/build.rs @@ -37,14 +37,22 @@ fn main() { } macro_rules! headers { - ($cfg:ident: $header:expr) => { + ($cfg:ident: [$m:expr]: $header:literal) => { + if $m { + $cfg.header($header); + } + }; + ($cfg:ident: $header:literal) => { $cfg.header($header); }; - ($cfg:ident: $($header:expr),*) => { - $(headers!($cfg: $header);)* + ($($cfg:ident: $([$c:expr]:)* $header:literal,)*) => { + $(headers!($cfg: $([$c]:)* $header);)* + }; + ($cfg:ident: $( $([$c:expr]:)* $header:literal,)*) => { + headers!($($cfg: $([$c]:)* $header,)*); }; - ($cfg:ident: $($header:expr,)*) => { - $(headers!($cfg: $header);)* + ($cfg:ident: $( $([$c:expr]:)* $header:literal),*) => { + headers!($($cfg: $([$c]:)* $header,)*); }; } @@ -135,10 +143,7 @@ fn test_apple(target: &str) { "utmpx.h", "wchar.h", "xlocale.h", - } - - if x86_64 { - headers! { cfg: "crt_externs.h" } + [x86_64]: "crt_externs.h", } cfg.skip_struct(move |ty| { @@ -313,11 +318,9 @@ fn test_openbsd(target: &str) { cfg.skip_fn(move |name| { match name { + // FIXME: https://github.com/rust-lang/libc/issues/1272 "execv" | "execve" | "execvp" | "execvpe" => true, - // typed 2nd arg - "gettimeofday" => true, - // Removed in OpenBSD 6.5 // https://marc.info/?l=openbsd-cvs&m=154723400730318 "mincore" => true, @@ -388,12 +391,8 @@ fn test_windows(target: &str) { "sys/utime.h", "time.h", "wchar.h", - } - - if gnu { - headers! { cfg: "ws2tcpip.h" } - } else { - headers! { cfg: "Winsock2.h" }; + [gnu]: "ws2tcpip.h", + [!gnu]: "Winsock2.h", } cfg.type_name(move |ty, is_struct, is_union| { @@ -461,7 +460,7 @@ fn test_windows(target: &str) { cfg.skip_fn(move |name| { match name { - // FIXME: API error: + // FIXME: https://github.com/rust-lang/libc/issues/1272 "execv" | "execve" | "execvp" | "execvpe" => true, _ => false, @@ -852,7 +851,6 @@ fn test_netbsd(target: &str) { cfg.skip_signededness(move |c| { match c { "LARGE_INTEGER" | "float" | "double" => true, - // uuid_t is a struct, not an integer. n if n.starts_with("pthread") => true, // sem_t is a struct or pointer "sem_t" => true, @@ -876,12 +874,8 @@ fn test_netbsd(target: &str) { cfg.skip_fn(move |name| { match name { - // FIXME: incorrect API - "execv" | - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" => true, "getrlimit" | "getrlimit64" | // non-int in 1st arg "setrlimit" | "setrlimit64" | // non-int in 1st arg @@ -1028,14 +1022,9 @@ fn test_dragonflybsd(target: &str) { s.replace("e_nsec", ".tv_nsec") } "u64" if struct_ == "epoll_event" => "data.u64".to_string(), - "type_" - if struct_ == "input_event" - || struct_ == "input_mask" - || struct_ == "ff_effect" - || struct_ == "rtprio" => - { - "type".to_string() - } + // Field is named `type` in C but that is a Rust keyword, + // so these fields are translated to `type_` in the bindings. + "type_" if struct_ == "rtprio" => "type".to_string(), s => s.to_string(), } }); @@ -1105,17 +1094,13 @@ fn test_dragonflybsd(target: &str) { cfg.skip_fn(move |name| { // skip those that are manually verified match name { - "execv" | // crazy stuff with const/mut - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" => true, "getrlimit" | "getrlimit64" | // non-int in 1st arg "setrlimit" | "setrlimit64" | // non-int in 1st arg - "prlimit" | "prlimit64" | // non-int in 2nd arg - // typed 2nd arg on linux - "gettimeofday" => true, + "prlimit" | "prlimit64" // non-int in 2nd arg + => true, _ => false, } @@ -1226,14 +1211,6 @@ fn test_android(target: &str) { let mut cfg = ctest::TestGenerator::new(); cfg.define("_GNU_SOURCE", None); - // FIXME: still necessary? - cfg.flag("-Wno-deprecated-declarations"); - - // Android doesn't actually have in_port_t but it's much easier if we - // provide one for us to test against - // FIXME: still necessary? - cfg.define("in_port_t", Some("uint16_t")); - headers! { cfg: "arpa/inet.h", "asm/mman.h", @@ -1300,6 +1277,7 @@ fn test_android(target: &str) { "sys/personality.h", "sys/prctl.h", "sys/ptrace.h", + "sys/random.h", "sys/reboot.h", "sys/resource.h", "sys/sendfile.h", @@ -1317,6 +1295,7 @@ fn test_android(target: &str) { "sys/un.h", "sys/utsname.h", "sys/vfs.h", + "sys/xattr.h", "sys/wait.h", "syslog.h", "termios.h", @@ -1326,30 +1305,24 @@ fn test_android(target: &str) { "utmp.h", "wchar.h", "xlocale.h", - } - - if target_pointer_width == 32 { - // time64_t is not defined for 64-bit targets If included it will - // generate the error 'Your time_t is already 64-bit' - cfg.header("time64.h"); - } - if x86 { - cfg.header("sys/reg.h"); + // time64_t is not defined for 64-bit targets If included it will + // generate the error 'Your time_t is already 64-bit' + [target_pointer_width == 32]: "time64.h", + [x86]: "sys/reg.h", } cfg.type_name(move |ty, is_struct, is_union| { match ty { // Just pass all these through, no need for a "struct" prefix - // FIXME: still required ? - "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" - | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" - | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" - | "Elf64_Chdr" => ty.to_string(), + "FILE" | "fd_set" | "Dl_info" => ty.to_string(), t if is_union => format!("union {}", t), t if t.ends_with("_t") => t.to_string(), + // sigval is a struct in Rust, but a union in C: + "sigval" => format!("union sigval"), + // put `struct` in front of all structs:. t if is_struct => format!("struct {}", t), @@ -1364,7 +1337,7 @@ fn test_android(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.to_string() } - // FIXME: still necessary? + // FIXME: appears that `epoll_event.data` is an union "u64" if struct_ == "epoll_event" => "data.u64".to_string(), s => s.to_string(), } @@ -1372,8 +1345,8 @@ fn test_android(target: &str) { cfg.skip_type(move |ty| { match ty { - // sighandler_t is crazy across platforms - // FIXME: still necessary? + // FIXME: `sighandler_t` type is incorrect, see: + // https://github.com/rust-lang/libc/issues/1359 "sighandler_t" => true, _ => false, } @@ -1381,71 +1354,24 @@ fn test_android(target: &str) { cfg.skip_struct(move |ty| { match ty { - // This is actually a union, not a struct - // FIXME: still necessary - "sigval" => true, - - // These structs have changed since unified headers in NDK r14b. - // `st_atime` and `st_atime_nsec` have changed sign. - // FIXME: unskip it for next major release - "stat" | "stat64" => true, - // These are tested as part of the linux_fcntl tests since there are // header conflicts when including them with all the other structs. - // FIXME: still necessary "termios2" => true, _ => false, } }); - cfg.skip_signededness(move |c| { - match c { - // FIXME: still necessary? - "LARGE_INTEGER" | "float" | "double" => true, - // FIXME: still necessary? - n if n.starts_with("pthread") => true, - _ => false, - } - }); - cfg.skip_const(move |name| { match name { - // FIXME: still necessary? - "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness - // FIXME: still necessary? - "SIGUNUSED" => true, // removed in glibc 2.26 - - // weird signed extension or something like that? - // FIXME: still necessary? - "MS_NOUSER" => true, - // FIXME: still necessary? - "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 - - // Android uses old kernel headers - // These are constants used in getrandom syscall - // FIXME: still necessary? - "GRND_NONBLOCK" | "GRND_RANDOM" => true, - - // Defined by libattr not libc on linux (hard to test). - // See constant definition for more details. - // FIXME: still necessary? + // FIXME: deprecated: not available in any header + // See: https://github.com/rust-lang/libc/issues/1356 "ENOATTR" => true, // FIXME: still necessary? - "BOTHER" => true, - - // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the - // x86_64 and i686 builders it seems to be available for all targets, so at least test - // it there. - // FIXME: still necessary? - "MFD_HUGETLB" => true, - - // These change all the time from release to release of linux - // distros, let's just not bother trying to verify them. They - // shouldn't be used in code anyway... - // FIXME: still necessary? - "AF_MAX" | "PF_MAX" => true, + "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness + // FIXME: deprecated - removed in glibc 2.26 + "SIGUNUSED" => true, _ => false, } @@ -1454,128 +1380,72 @@ fn test_android(target: &str) { cfg.skip_fn(move |name| { // skip those that are manually verified match name { - // FIXME: still necessary? - "execv" | // crazy stuff with const/mut - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, - - // typed 2nd arg on android - // FIXME: still necessary? - "gettimeofday" => true, - - // not declared in newer android toolchains - // FIXME: still necessary? - "getdtablesize" => true, - - // FIXME: still necessary? - "dlerror" => true, // const-ness is added - - // Apparently the NDK doesn't have this defined on android, but - // it's in a header file? - // FIXME: still necessary? - "endpwent" => true, - - // Apparently res_init exists on Android, but isn't defined in a header: - // https://mail.gnome.org/archives/commits-list/2013-May/msg01329.html - // FIXME: still necessary? - "res_init" => true, + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, - // Definition of those functions as changed since unified headers from NDK r14b - // These changes imply some API breaking changes but are still ABI compatible. - // We can wait for the next major release to be compliant with the new API. - // FIXME: unskip these for next major release - "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" | - "setpriority" | "personality" => true, - // In Android 64 bits, these functions have been fixed since unified headers. - // Ignore these until next major version. - "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" - if target_pointer_width == 64 => true, + // There are two versions of the sterror_r function, see + // + // https://linux.die.net/man/3/strerror_r + // + // An XSI-compliant version provided if: + // + // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE + // + // and a GNU specific version provided if _GNU_SOURCE is defined. + // + // libc provides bindings for the XSI-compliant version, which is + // preferred for portable applications. + // + // We skip the test here since here _GNU_SOURCE is defined, and + // test the XSI version below. + "strerror_r" => true, _ => false, } }); - cfg.skip_static(move |name| { - match name { - // Internal constant, not declared in any headers. - // FIXME: still necessary - "__progname" => true, - _ => false, - } - }); - - // FIXME: still necessary? cfg.skip_field_type(move |struct_, field| { // This is a weird union, don't check the type. (struct_ == "ifaddrs" && field == "ifa_ifu") || - // sighandler_t type is super weird - (struct_ == "sigaction" && field == "sa_sigaction") || // sigval is actually a union, but we pretend it's a struct - (struct_ == "sigevent" && field == "sigev_value") || - // aio_buf is "volatile void*" and Rust doesn't understand volatile - (struct_ == "aiocb" && field == "aio_buf") + (struct_ == "sigevent" && field == "sigev_value") }); - // FIXME: still necessary? cfg.skip_field(move |struct_, field| { // this is actually a union on linux, so we can't represent it well and // just insert some padding. (struct_ == "siginfo_t" && field == "_pad") || + // FIXME: `sa_sigaction` has type `sighandler_t` but that type is + // incorrect, see: https://github.com/rust-lang/libc/issues/1359 + (struct_ == "sigaction" && field == "sa_sigaction") || // sigev_notify_thread_id is actually part of a sigev_un union (struct_ == "sigevent" && field == "sigev_notify_thread_id") || - // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. - (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || - field == "_pad2" || - field == "ssi_syscall" || + // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. + (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" || field == "ssi_call_addr" || field == "ssi_arch")) }); - // FIXME: remove - cfg.fn_cname(move |name, _cname| name.to_string()); - cfg.generate("../src/lib.rs", "main.rs"); - // On Android also generate another script for testing linux/fcntl - // declarations. These cannot be tested normally because including both - // `linux/fcntl.h` and `fcntl.h` fails. - // - // FIXME: is still necessary? - let mut cfg = ctest::TestGenerator::new(); - cfg.skip_type(|_| true) - .skip_fn(|_| true) - .skip_static(|_| true); - cfg.header("linux/fcntl.h"); - cfg.header("net/if.h"); - cfg.header("linux/if.h"); - cfg.header("linux/quota.h"); - cfg.header("asm/termbits.h"); - cfg.skip_const(move |name| match name { - "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false, - "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" => { - false - } - "BOTHER" => false, - _ => true, - }); - cfg.skip_struct(|s| s != "termios2"); - cfg.type_name(move |ty, is_struct, is_union| match ty { - t if is_struct => format!("struct {}", t), - t if is_union => format!("union {}", t), - t => t.to_string(), - }); - cfg.generate("../src/lib.rs", "linux_fcntl.rs"); + test_linux_like_apis(target); } fn test_freebsd(target: &str) { assert!(target.contains("freebsd")); - let x86 = target.contains("i686") || target.contains("x86_64"); - let mut cfg = ctest::TestGenerator::new(); + + let freebsd_ver = which_freebsd(); + + if let Some(12) = freebsd_ver { + // If the host is FreeBSD 12, run FreeBSD 12 tests + cfg.cfg("freebsd12", None); + } + // Required for `getline`: cfg.define("_WITH_GETLINE", None); + // Required for making freebsd11_stat available in the headers + cfg.define("_WANT_FREEBSD11_STAT", None); headers! { cfg: "aio.h", @@ -1655,19 +1525,18 @@ fn test_freebsd(target: &str) { cfg.type_name(move |ty, is_struct, is_union| { match ty { // Just pass all these through, no need for a "struct" prefix - // FIXME: still required? - "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" - | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" - | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" - | "Elf64_Chdr" => ty.to_string(), + "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), - // FIXME: still required? + // FIXME: https://github.com/rust-lang/libc/issues/1273 "sighandler_t" => "sig_t".to_string(), t if is_union => format!("union {}", t), t if t.ends_with("_t") => t.to_string(), + // sigval is a struct in Rust, but a union in C: + "sigval" => format!("union sigval"), + // put `struct` in front of all structs:. t if is_struct => format!("struct {}", t), @@ -1682,125 +1551,40 @@ fn test_freebsd(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - // FIXME: still required? - "u64" if struct_ == "epoll_event" => "data.u64".to_string(), - // FIXME: still required? - "type_" - if struct_ == "input_event" - || struct_ == "input_mask" - || struct_ == "ff_effect" - || struct_ == "rtprio" => - { - "type".to_string() - } + // Field is named `type` in C but that is a Rust keyword, + // so these fields are translated to `type_` in the bindings. + "type_" if struct_ == "rtprio" => "type".to_string(), s => s.to_string(), } }); - cfg.skip_type(move |ty| { - match ty { - // sighandler_t is crazy across platforms - // FIXME: still required? - "sighandler_t" => true, - - _ => false, - } - }); - - cfg.skip_struct(move |ty| { - match ty { - // This is actually a union, not a struct - // FIXME: still required? - "sigval" => true, - - // These are tested as part of the linux_fcntl tests since there are - // header conflicts when including them with all the other structs. - // FIXME: still required? - "termios2" => true, - - _ => false, - } - }); - - cfg.skip_signededness(move |c| { - match c { - // FIXME: still required? - "LARGE_INTEGER" | "float" | "double" => true, - // FIXME: still required? - n if n.starts_with("pthread") => true, - // sem_t is a struct or pointer - // FIXME: still required? - "sem_t" => true, - // mqd_t is a pointer on FreeBSD - // FIXME: still required? - "mqd_t" => true, - - _ => false, - } - }); - cfg.skip_const(move |name| { match name { - // FIXME: still required? - "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness - // FIXME: still required? - "SIGUNUSED" => true, // removed in glibc 2.26 - - // weird signed extension or something like that? - // FIXME: still required? - "MS_NOUSER" => true, - // FIXME: still required? - "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 + // These constants were introduced in FreeBSD 12: + "SF_USER_READAHEAD" + | "EVFILT_EMPTY" + | "SO_REUSEPORT_LB" + | "IP_ORIGDSTADDR" + | "IP_RECVORIGDSTADDR" + | "IPV6_ORIGDSTADDR" + | "IPV6_RECVORIGDSTADDR" + if Some(12) != freebsd_ver => + { + true + } + // FIXME: There are deprecated - remove in a couple of releases. // These constants were removed in FreeBSD 11 (svn r273250) but will // still be accepted and ignored at runtime. - "MAP_RENAME" | "MAP_NORESERVE" => true, + "MAP_RENAME" | "MAP_NORESERVE" if Some(10) != freebsd_ver => true, + // FIXME: There are deprecated - remove in a couple of releases. // These constants were removed in FreeBSD 11 (svn r262489), // and they've never had any legitimate use outside of the // base system anyway. "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "NET_MAXID" | "USER_MAXID" => true, - // These constants were added in FreeBSD 11 - // FIXME: still required? - "EVFILT_PROCDESC" | "EVFILT_SENDFILE" | "EVFILT_EMPTY" - | "PD_CLOEXEC" | "PD_ALLOWED_AT_FORK" => true, - - // These constants were added in FreeBSD 12 - // FIXME: still required? - "SF_USER_READAHEAD" | "SO_REUSEPORT_LB" => true, - - // These constants are tested in a separate test program generated - // below because there are header conflicts if we try to include the - // headers that define them here. - // FIXME: still required? - "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => true, - // FIXME: still required? - "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" - | "F_SEAL_WRITE" => true, - // FIXME: still required? - "BOTHER" => true, - - // MFD_HUGETLB is not available in some older libc versions on the - // CI builders. On the x86_64 and i686 builders it seems to be - // available for all targets, so at least test it there. - // FIXME: still required? - "MFD_HUGETLB" if !x86 => true, - - // These change all the time from release to release of linux - // distros, let's just not bother trying to verify them. They - // shouldn't be used in code anyway... - // FIXME: still required? - "AF_MAX" | "PF_MAX" => true, - - // FreeBSD 12 required, but CI has FreeBSD 11. - // FIXME: still required? - "IP_ORIGDSTADDR" - | "IP_RECVORIGDSTADDR" - | "IPV6_ORIGDSTADDR" - | "IPV6_RECVORIGDSTADDR" => true, - _ => false, } }); @@ -1808,84 +1592,42 @@ fn test_freebsd(target: &str) { cfg.skip_fn(move |name| { // skip those that are manually verified match name { - // FIXME: still required? - "execv" | // crazy stuff with const/mut - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, - - // FIXME: for some reason, our signature is wrong - "gettimeofday" => true, - - // The `uname` function in freebsd is now an inline wrapper that - // delegates to another, but the symbol still exists, so don't check - // the symbol. - // FIXME: still required? - "uname" => true, - - // FIXME: need to upgrade FreeBSD version; see https://github.com/rust-lang/libc/issues/938 - // FIXME: still required? - "setgrent" => true, + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, - // aio_waitcomplete's return type changed between FreeBSD 10 and 11. - // FIXME: still required? - "aio_waitcomplete" => true, + // The `uname` function in the `utsname.h` FreeBSD header is a C + // inline function (has no symbol) that calls the `__xuname` symbol. + // Therefore the function pointer comparison does not make sense for it. + "uname" => true, - // lio_listio confuses the checker, probably because one of its - // arguments is an array - // FIXME: still required? + // FIXME: Our API is unsound. The Rust API allows aliasing + // pointers, but the C API requires pointers not to alias. + // We should probably be at least using `&`/`&mut` here, see: + // https://github.com/gnzlbg/ctest/issues/68 "lio_listio" => true, - // Definition of those functions as changed since unified headers from NDK r14b - // These changes imply some API breaking changes but are still ABI compatible. - // We can wait for the next major release to be compliant with the new API. - // FIXME: unskip these for next major release - // FIXME: still required ? - "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" | - _ => false, } }); - cfg.skip_field_type(move |struct_, field| { - // This is a weird union, don't check the type. - // FIXME: still required? - (struct_ == "ifaddrs" && field == "ifa_ifu") || - // FIXME: still required? - // sighandler_t type is super weird - (struct_ == "sigaction" && field == "sa_sigaction") || - // FIXME: still required? - // sigval is actually a union, but we pretend it's a struct - (struct_ == "sigevent" && field == "sigev_value") || - // aio_buf is "volatile void*" and Rust doesn't understand volatile - // FIXME: still required? - (struct_ == "aiocb" && field == "aio_buf") || - // stack_t.ss_sp's type changed from FreeBSD 10 to 11 in svn r294930 - // FIXME: still required? - (struct_ == "stack_t" && field == "ss_sp") + cfg.volatile_item(|i| { + use ctest::VolatileItemKind::*; + match i { + // aio_buf is a volatile void** but since we cannot express that in + // Rust types, we have to explicitly tell the checker about it here: + StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { + true + } + _ => false, + } }); cfg.skip_field(move |struct_, field| { - // this is actually a union on linux, so we can't represent it well and - // just insert some padding. - // FIXME: still required? - (struct_ == "siginfo_t" && field == "_pad") || - // sigev_notify_thread_id is actually part of a sigev_un union - // FIXME: still required? - (struct_ == "sigevent" && field == "sigev_notify_thread_id") || - // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. - // FIXME: still required? - (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || - field == "_pad2" || - field == "ssi_syscall" || - field == "ssi_call_addr" || - field == "ssi_arch")) + // FIXME: `sa_sigaction` has type `sighandler_t` but that type is + // incorrect, see: https://github.com/rust-lang/libc/issues/1359 + (struct_ == "sigaction" && field == "sa_sigaction") }); - // FIXME: remove - cfg.fn_cname(move |name, _cname| name.to_string()); - cfg.generate("../src/lib.rs", "main.rs"); } @@ -1893,11 +1635,7 @@ fn test_emscripten(target: &str) { assert!(target.contains("emscripten")); let mut cfg = ctest::TestGenerator::new(); - // FIXME: still necessary? - cfg.define("_GNU_SOURCE", None); - - // FIXME: still necessary? - cfg.flag("-Wno-deprecated-declarations"); + cfg.define("_GNU_SOURCE", None); // FIXME: ?? headers! { cfg: "aio.h", @@ -1990,11 +1728,7 @@ fn test_emscripten(target: &str) { cfg.type_name(move |ty, is_struct, is_union| { match ty { // Just pass all these through, no need for a "struct" prefix - // FIXME: is this necessary? - "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" - | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" - | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" - | "Elf64_Chdr" => ty.to_string(), + "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), t if is_union => format!("union {}", t), @@ -2014,7 +1748,7 @@ fn test_emscripten(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - // FIXME: is this necessary? + // FIXME: appears that `epoll_event.data` is an union "u64" if struct_ == "epoll_event" => "data.u64".to_string(), s => s.to_string(), } @@ -2032,157 +1766,31 @@ fn test_emscripten(target: &str) { cfg.skip_struct(move |ty| { match ty { - // FIXME: is this necessary? - "sockaddr_nl" => true, - // This is actually a union, not a struct // FIXME: is this necessary? "sigval" => true, - // Linux kernel headers used on musl are too old to have this - // definition. Because it's tested on other Linux targets, skip it. - // FIXME: is this necessary? - "input_mask" => true, - - // These are tested as part of the linux_fcntl tests since there are - // header conflicts when including them with all the other structs. - // FIXME: is this necessary? - "termios2" => true, - _ => false, } }); - cfg.skip_signededness(move |c| match c { - // FIXME: is this necessary? - "LARGE_INTEGER" | "float" | "double" => true, - // FIXME: is this necessary? - n if n.starts_with("pthread") => true, - _ => false, - }); - - cfg.skip_const(move |name| { + cfg.skip_fn(move |name| { match name { - // FIXME: is this necessary? - "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness - // FIXME: is this necessary? - "SIGUNUSED" => true, // removed in glibc 2.26 - - // types on musl are defined a little differently - // FIXME: is this necessary? - n if n.contains("__SIZEOF_PTHREAD") => true, - - // Skip constants not defined in MUSL but just passed down to the - // kernel regardless - // FIXME: is this necessary? - "RLIMIT_NLIMITS" - | "TCP_COOKIE_TRANSACTIONS" - | "RLIMIT_RTTIME" - | "MSG_COPY" - => - { - true - } - - // weird signed extension or something like that? - // FIXME: is this necessary? - "MS_NOUSER" => true, - // FIXME: is this necessary? - "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 - - // Musl uses old, patched kernel headers - // FIXME: is this necessary? - "FALLOC_FL_COLLAPSE_RANGE" - | "FALLOC_FL_ZERO_RANGE" - | "FALLOC_FL_INSERT_RANGE" - | "FALLOC_FL_UNSHARE_RANGE" - | "RENAME_NOREPLACE" - | "RENAME_EXCHANGE" - | "RENAME_WHITEOUT" - // ALG_SET_AEAD_* constants are available starting from kernel 3.19 - | "ALG_SET_AEAD_ASSOCLEN" - | "ALG_SET_AEAD_AUTHSIZE" - => - { - true - } - - // musl uses old kernel headers - // These are constants used in getrandom syscall - // FIXME: is this necessary? - "GRND_NONBLOCK" | "GRND_RANDOM" => true, - - - // These constants are tested in a separate test program generated below because there - // are header conflicts if we try to include the headers that define them here. - // FIXME: is this necessary? - "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => true, - // FIXME: is this necessary? - "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" - | "F_SEAL_WRITE" => true, - // FIXME: is this necessary? - "BOTHER" => true, - - // FIXME: is this necessary? - "MFD_CLOEXEC" | "MFD_ALLOW_SEALING" => true, - // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the - // x86_64 and i686 builders it seems to be available for all targets, so at least test - // it there. - // FIXME: is this necessary? - "MFD_HUGETLB" => - { - true - } - - // These are defined for Solaris 11, but the crate is tested on - // illumos, where they are currently not defined - // FIXME: is this necessary? - "EADI" - | "PORT_SOURCE_POSTWAIT" - | "PORT_SOURCE_SIGNAL" - | "PTHREAD_STACK_MIN" => true, - - // These change all the time from release to release of linux - // distros, let's just not bother trying to verify them. They - // shouldn't be used in code anyway... - // FIXME: is this necessary? - "AF_MAX" | "PF_MAX" => true, + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, _ => false, } }); - cfg.skip_fn(move |name| { - // skip those that are manually verified + cfg.skip_const(move |name| { match name { - // FIXME: is this necessary? - "execv" | // crazy stuff with const/mut - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, + // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 + // users should use SIGSYS instead + "SIGUNUSED" => true, - "getrlimit" | "getrlimit64" | // non-int in 1st arg - "setrlimit" | "setrlimit64" | // non-int in 1st arg - "prlimit" | "prlimit64" | // non-int in 2nd arg - - // int vs uint. Sorry musl, your prototype declarations are "correct" in the sense that - // they match the interface defined by Linux verbatim, but they conflict with other - // send*/recv* syscalls - // FIXME: is this necessary? - "sendmmsg" | "recvmmsg" => true, - - // FIXME: is this necessary? - "dladdr" => true, // const-ness only added recently - - // FIXME: is this necessary? - "lio_listio" => true, - - // Definition of those functions as changed since unified headers from NDK r14b - // These changes imply some API breaking changes but are still ABI compatible. - // We can wait for the next major release to be compliant with the new API. - // FIXME: unskip these for next major release - "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" | + // FIXME: emscripten uses different constants to constructs these + n if n.contains("__SIZEOF_PTHREAD") => true, _ => false, } @@ -2224,9 +1832,7 @@ fn test_emscripten(target: &str) { field == "ssi_arch")) }); - // FIXME: remove - cfg.fn_cname(move |name, _cname| name.to_string()); - + // FIXME: test linux like cfg.generate("../src/lib.rs", "main.rs"); } @@ -2248,22 +1854,21 @@ fn test_linux(target: &str) { ), } - let mips = target.contains("mips"); - let i686 = target.contains("i686"); + let arm = target.contains("arm"); let x86_64 = target.contains("x86_64"); - let x32 = target.ends_with("gnux32"); + let x86_32 = target.contains("i686"); + let x32 = target.contains("x32"); + let mips = target.contains("mips"); + let mips32_musl = mips && !target.contains("64") && musl; + let sparc64 = target.contains("sparc64"); let mut cfg = ctest::TestGenerator::new(); - // FIXME: still necessary? cfg.define("_GNU_SOURCE", None); // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are // deprecated since glibc >= 2.29. This allows Rust binaries to link against // glibc versions older than 2.29. cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); - // FIXME: still necessary? - cfg.flag("-Wno-deprecated-declarations"); - headers! { cfg: "ctype.h", "dirent.h", @@ -2319,6 +1924,8 @@ fn test_linux(target: &str) { "sys/prctl.h", "sys/ptrace.h", "sys/quota.h", + // FIXME: the mips-musl CI build jobs use ancient musl 1.0.15: + [!mips32_musl]: "sys/random.h", "sys/reboot.h", "sys/resource.h", "sys/sem.h", @@ -2347,86 +1954,61 @@ fn test_linux(target: &str) { "unistd.h", "utime.h", "utmp.h", + "utmpx.h", "wchar.h", "errno.h", + // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit + // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 + [x86_64 || x86_32 || arm]: "sys/io.h", + // `sys/reg.h` is only available on x86 and x86_64 + [x86_64 || x86_32]: "sys/reg.h", + // sysctl system call is deprecated and not available on musl + // It is also unsupported in x32: + [!(x32 || musl)]: "sys/sysctl.h", + // <execinfo.h> is not supported by musl: + // https://www.openwall.com/lists/musl/2015/04/09/3 + [!musl]: "execinfo.h", } // Include linux headers at the end: headers! { cfg: + "asm/mman.h", + "linux/dccp.h", "linux/falloc.h", - "linux/futex.h", "linux/fs.h", + "linux/futex.h", "linux/genetlink.h", + // FIXME: musl version 1.0.15 used by mips build jobs is ancient + [!mips32_musl]: "linux/if.h", + "linux/if_addr.h", "linux/if_alg.h", "linux/if_ether.h", "linux/if_tun.h", "linux/input.h", + "linux/magic.h", + "linux/memfd.h", "linux/module.h", "linux/net_tstamp.h", + "linux/netfilter/nf_tables.h", "linux/netfilter_ipv4.h", "linux/netfilter_ipv6.h", "linux/netlink.h", + "linux/quota.h", "linux/random.h", + "linux/reboot.h", + "linux/rtnetlink.h", "linux/seccomp.h", "linux/sockios.h", - } - - if x86_64 { - headers! { cfg: "sys/io.h" }; - } - if i686 || x86_64 { - headers! { cfg: "sys/reg.h" }; - } - - if !musl { - assert!(uclibc || gnu); - headers! { cfg: - "asm/mman.h", - "linux/if.h", - "linux/magic.h", - "linux/netfilter/nf_tables.h", - "linux/reboot.h", - "sys/auxv.h", - }; - - if !x32 { - assert!((gnu || uclibc) && !x32); - headers! { cfg: "sys/sysctl.h", } - } - if !uclibc { - assert!(gnu); - headers! { cfg: - "execinfo.h", - "utmpx.h", - } - } - if !mips { - assert!((gnu || uclibc) && !mips); - headers! { cfg: "linux/quota.h" }; - } - } - - // DCCP support - if !uclibc && !musl { - assert!(gnu); - headers! { cfg: "linux/dccp.h" }; - } - - if !musl || mips { - assert!(gnu || uclibc || (mips && musl)); - headers! { cfg: "linux/memfd.h" }; + "sys/auxv.h", } // note: aio.h must be included before sys/mount.h - if !uclibc { - assert!(gnu || musl); - // optionally included in uclibc - headers! { cfg: - "sys/xattr.h", - "sys/sysinfo.h", - "aio.h", - } + headers! { + cfg: + "sys/xattr.h", + "sys/sysinfo.h", + "aio.h", } cfg.type_name(move |ty, is_struct, is_union| { @@ -2455,42 +2037,48 @@ fn test_linux(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - // FIXME: is this necessary? + // FIXME: epoll_event.data is actuall a union in C, but in Rust + // it is only a u64 because we only expose one field + // http://man7.org/linux/man-pages/man2/epoll_wait.2.html "u64" if struct_ == "epoll_event" => "data.u64".to_string(), - // FIXME: is this necessary? + // The following structs have a field called `type` in C, + // but `type` is a Rust keyword, so these fields are translated + // to `type_` in Rust. "type_" if struct_ == "input_event" || struct_ == "input_mask" - || struct_ == "ff_effect" - || struct_ == "rtprio" => + || struct_ == "ff_effect" => { "type".to_string() } + s => s.to_string(), } }); cfg.skip_type(move |ty| { match ty { - // sighandler_t is crazy across platforms - // FIXME: is this necessary? + // FIXME: `sighandler_t` type is incorrect, see: + // https://github.com/rust-lang/libc/issues/1359 "sighandler_t" => true, // These cannot be tested when "resolv.h" is included and are tested - // below. + // in the `linux_elf.rs` file. "Elf64_Phdr" | "Elf32_Phdr" => true, + // This type is private on Linux. It is implemented as a C `enum` + // (`c_uint`) and this clashes with the type of the `rlimit` APIs + // which expect a `c_int` even though both are ABI compatible. + "__rlimit_resource_t" => true, + _ => false, } }); cfg.skip_struct(move |ty| { match ty { - // FIXME: is this necessary? - "sockaddr_nl" if musl => true, - // These cannot be tested when "resolv.h" is included and are tested - // below. + // in the `linux_elf.rs` file. "Elf64_Phdr" | "Elf32_Phdr" => true, // On Linux, the type of `ut_tv` field of `struct utmpx` @@ -2498,184 +2086,79 @@ fn test_linux(target: &str) { // which is absent in glibc, has to be defined. "__timeval" => true, - // This is actually a union, not a struct + // FIXME: This is actually a union, not a struct "sigval" => true, - // Linux kernel headers used on musl are too old to have this - // definition. Because it's tested on other Linux targets, skip it. - // FIXME: is this necessary? - "input_mask" if musl => true, - - // These are tested as part of the linux_fcntl tests since there are - // header conflicts when including them with all the other structs. - // FIXME: is this necessary? + // This type is tested in the `linux_termios.rs` file since there + // are header conflicts when including them with all the other + // structs. "termios2" => true, + // FIXME: musl version using by mips build jobs 1.0.15 is ancient: + "ifmap" | "ifreq" | "ifconf" if mips32_musl => true, + _ => false, } }); - cfg.skip_signededness(move |c| match c { - // FIXME: is this necessary? - "LARGE_INTEGER" | "float" | "double" => true, - // FIXME: is this necessary? - n if n.starts_with("pthread") => true, - _ => false, - }); - cfg.skip_const(move |name| { match name { - // FIXME: is this necessary? - "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness - // FIXME: is this necessary? - "SIGUNUSED" => true, // removed in glibc 2.26 - - // types on musl are defined a little differently - // FIXME: is this necessary? - n if musl && n.contains("__SIZEOF_PTHREAD") => true, - - // Skip constants not defined in MUSL but just passed down to the - // kernel regardless - // FIXME: is this necessary? - "RLIMIT_NLIMITS" - | "TCP_COOKIE_TRANSACTIONS" - | "RLIMIT_RTTIME" - | "MSG_COPY" - if musl => - { - true - } - // work around super old mips toolchain - // FIXME: is this necessary? - "SCHED_IDLE" | "SHM_NORESERVE" => mips, - - // weird signed extension or something like that? - // FIXME: is this necessary? - "MS_NOUSER" => true, - // FIXME: is this necessary? - "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 - - // These are either unimplemented or optionally built into uClibc - // FIXME: is this necessary? - "LC_CTYPE_MASK" - | "LC_NUMERIC_MASK" - | "LC_TIME_MASK" - | "LC_COLLATE_MASK" - | "LC_MONETARY_MASK" - | "LC_MESSAGES_MASK" - | "MADV_MERGEABLE" - | "MADV_UNMERGEABLE" - | "MADV_HWPOISON" - | "IPV6_ADD_MEMBERSHIP" - | "IPV6_DROP_MEMBERSHIP" - | "IPV6_MULTICAST_LOOP" - | "IPV6_V6ONLY" - | "MAP_STACK" - | "RTLD_DEEPBIND" - | "SOL_IPV6" - | "SOL_ICMPV6" - if uclibc => - { - true - } + // These constants are not available if gnu headers have been included + // and can therefore not be tested here + // + // The IPV6 constants are tested in the `linux_ipv6.rs` tests: + | "IPV6_FLOWINFO" + | "IPV6_FLOWLABEL_MGR" + | "IPV6_FLOWINFO_SEND" + | "IPV6_FLOWINFO_FLOWLABEL" + | "IPV6_FLOWINFO_PRIORITY" + // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: + | "F_CANCELLK" + | "F_ADD_SEALS" + | "F_GET_SEALS" + | "F_SEAL_SEAL" + | "F_SEAL_SHRINK" + | "F_SEAL_GROW" + | "F_SEAL_WRITE" => true, - // Musl uses old, patched kernel headers - // FIXME: is this necessary? - "FALLOC_FL_COLLAPSE_RANGE" - | "FALLOC_FL_ZERO_RANGE" - | "FALLOC_FL_INSERT_RANGE" + // The musl-sanitized kernel headers used in CI + // target the Linux kernel 4.4 and do not contain the + // following constants: + // + // Requires Linux kernel 4.9 | "FALLOC_FL_UNSHARE_RANGE" - | "RENAME_NOREPLACE" - | "RENAME_EXCHANGE" - | "RENAME_WHITEOUT" - // ALG_SET_AEAD_* constants are available starting from kernel 3.19 - | "ALG_SET_AEAD_ASSOCLEN" - | "ALG_SET_AEAD_AUTHSIZE" - if musl => - { - true - } - - // musl uses old kernel headers - // These are constants used in getrandom syscall - // FIXME: is this necessary? - "GRND_NONBLOCK" | "GRND_RANDOM" if musl => true, - - // Defined by libattr not libc on linux (hard to test). - // See constant definition for more details. - // FIXME: is this necessary? + // + // Require Linux kernel 5.x: + | "MSG_COPY" + if musl => true, + // Require Linux kernel 5.1: + "F_SEAL_FUTURE_WRITE" => true, + + // The musl version 1.0.22 used in CI does not + // contain these glibc constants yet: + | "RLIMIT_RTTIME" // should be in `resource.h` + | "TCP_COOKIE_TRANSACTIONS" // should be in the `netinet/tcp.h` header + if musl => true, + + // FIXME: deprecated: not available in any header + // See: https://github.com/rust-lang/libc/issues/1356 "ENOATTR" => true, - // On mips*-unknown-linux-gnu* CMSPAR cannot be included with the set of headers we - // want to use here for testing. It's originally defined in asm/termbits.h, which is - // also included by asm/termios.h, but not the standard termios.h. There's no way to - // include both asm/termbits.h and termios.h and there's no way to include both - // asm/termios.h and ioctl.h (+ some other headers) because of redeclared types. - // FIXME: is this necessary? - "CMSPAR" if mips && !musl => true, - - // On mips Linux targets, MADV_SOFT_OFFLINE is currently missing, though it's been added but CI has too old - // of a Linux version. Since it exists on all other Linux targets, just ignore this for now and remove once - // it's been fixed in CI. - // FIXME: is this necessary? - "MADV_SOFT_OFFLINE" if mips => true, + // FIXME: SIGUNUSED was removed in glibc 2.26 + // Users should use SIGSYS instead. + "SIGUNUSED" => true, - // These constants are tested in a separate test program generated below because there - // are header conflicts if we try to include the headers that define them here. - // FIXME: is this necessary? - "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => true, - // FIXME: is this necessary? - "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" - | "F_SEAL_WRITE" => true, - // FIXME: is this necessary? - "QFMT_VFS_OLD" | "QFMT_VFS_V0" | "QFMT_VFS_V1" - if mips => - { - true - } // Only on MIPS - // FIXME: is this necessary? + // FIXME: conflicts with glibc headers and is tested in + // `linux_termios.rs` below: "BOTHER" => true, - // FIXME: is this necessary? - "MFD_CLOEXEC" | "MFD_ALLOW_SEALING" if !mips && musl => true, - // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the - // x86_64 and i686 builders it seems to be available for all targets, so at least test - // it there. - // FIXME: is this necessary? - "MFD_HUGETLB" - if !(x86_64 || i686) || musl => - { - true - } - - // These are defined for Solaris 11, but the crate is tested on - // illumos, where they are currently not defined - // FIXME: is this necessary? - "EADI" - | "PORT_SOURCE_POSTWAIT" - | "PORT_SOURCE_SIGNAL" - | "PTHREAD_STACK_MIN" => true, - - // These change all the time from release to release of linux - // distros, let's just not bother trying to verify them. They - // shouldn't be used in code anyway... - // FIXME: is this necessary? - "AF_MAX" | "PF_MAX" => true, + // FIXME: on musl the pthread types are defined a little differently + // - these constants are used by the glibc implementation. + n if musl && n.contains("__SIZEOF_PTHREAD") => true, - // These are not in a glibc release yet, only in kernel headers. - // FIXME: is this necessary? - "AF_XDP" - | "PF_XDP" - | "SOL_XDP" - | "IPV6_FLOWINFO" - | "IPV6_FLOWLABEL_MGR" - | "IPV6_FLOWINFO_SEND" - | "IPV6_FLOWINFO_FLOWLABEL" - | "IPV6_FLOWINFO_PRIORITY" - => - { - true - } + // FIXME: musl version 1.0.15 used by mips build jobs is ancient + t if mips32_musl && t.starts_with("IFF") => true, + "MFD_HUGETLB" | "AF_XDP" | "PF_XDP" if mips32_musl => true, _ => false, } @@ -2684,70 +2167,41 @@ fn test_linux(target: &str) { cfg.skip_fn(move |name| { // skip those that are manually verified match name { - "execv" | // crazy stuff with const/mut - "execve" | - "execvp" | - "execvpe" | - "fexecve" => true, - - "getrlimit" | "getrlimit64" | // non-int in 1st arg - "setrlimit" | "setrlimit64" | // non-int in 1st arg - "prlimit" | "prlimit64" // non-int in 2nd arg - => true, - - // int vs uint. Sorry musl, your prototype declarations are "correct" in the sense that - // they match the interface defined by Linux verbatim, but they conflict with other - // send*/recv* syscalls - // FIXME: is this necessary? - "sendmmsg" | "recvmmsg" if musl => true, - - // typed 2nd arg on linux - // FIXME: is this necessary? - "gettimeofday" => true, - - // FIXME: is this necessary? - "dladdr" if musl => true, // const-ness only added recently + // FIXME: https://github.com/rust-lang/libc/issues/1272 + "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, - // There seems to be a small error in EGLIBC's eventfd.h header. The - // [underlying system call][1] always takes its first `count` - // argument as an `unsigned int`, but [EGLIBC's <sys/eventfd.h> - // header][2] declares it to take an `int`. [GLIBC's header][3] - // matches the kernel. + // There are two versions of the sterror_r function, see // - // EGLIBC is no longer actively developed, and Debian, the largest - // distribution that had been using it, switched back to GLIBC in - // April 2015. So effectively all Linux <sys/eventfd.h> headers will - // be using `unsigned int` soon. + // https://linux.die.net/man/3/strerror_r // - // [1]: https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/fs/eventfd.c?id=refs/tags/v3.12.51#n397 - // [2]: http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/eglibc/trusty/view/head:/sysdeps/unix/sysv/linux/sys/eventfd.h - // [3]: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sys/eventfd.h;h=6295f32e937e779e74318eb9d3bdbe76aef8a8f3;hb=4e42b5b8f89f0e288e68be7ad70f9525aebc2cff#l34 - // FIXME: is this necessary? - "eventfd" => true, - + // An XSI-compliant version provided if: + // + // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) + // && ! _GNU_SOURCE + // + // and a GNU specific version provided if _GNU_SOURCE is defined. + // + // libc provides bindings for the XSI-compliant version, which is + // preferred for portable applications. + // + // We skip the test here since here _GNU_SOURCE is defined, and + // test the XSI version below. + "strerror_r" => true, + + // FIXME: Our API is unsound. The Rust API allows aliasing + // pointers, but the C API requires pointers not to alias. + // We should probably be at least using `&`/`&mut` here, see: + // https://github.com/gnzlbg/ctest/issues/68 "lio_listio" if musl => true, - // These are either unimplemented or optionally built into uClibc - // or "sysinfo", where it's defined but the structs in linux/sysinfo.h and sys/sysinfo.h - // clash so it can't be tested - "getxattr" | "lgetxattr" | "fgetxattr" | "setxattr" | "lsetxattr" | "fsetxattr" | - "listxattr" | "llistxattr" | "flistxattr" | "removexattr" | "lremovexattr" | - "fremovexattr" | - "backtrace" | - "sysinfo" | "newlocale" | "duplocale" | "freelocale" | "uselocale" | - "nl_langinfo_l" | "wcslen" | "wcstombs" if uclibc => true, - - // Definition of those functions as changed since unified headers from NDK r14b - // These changes imply some API breaking changes but are still ABI compatible. - // We can wait for the next major release to be compliant with the new API. - // FIXME: unskip these for next major release - "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" => true, + // FIXME: the glibc version used by the Sparc64 build jobs + // which use Debian 10.0 is too old. + "statx" if sparc64 => true, _ => false, } }); - // FIXME: is this necessary? cfg.skip_field_type(move |struct_, field| { // This is a weird union, don't check the type. (struct_ == "ifaddrs" && field == "ifa_ifu") || @@ -2757,12 +2211,22 @@ fn test_linux(target: &str) { (struct_ == "utmpx" && field == "ut_tv") || // sigval is actually a union, but we pretend it's a struct (struct_ == "sigevent" && field == "sigev_value") || - // aio_buf is "volatile void*" and Rust doesn't understand volatile - (struct_ == "aiocb" && field == "aio_buf") || // this one is an anonymous union (struct_ == "ff_effect" && field == "u") }); + cfg.volatile_item(|i| { + use ctest::VolatileItemKind::*; + match i { + // aio_buf is a volatile void** but since we cannot express that in + // Rust types, we have to explicitly tell the checker about it here: + StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { + true + } + _ => false, + } + }); + cfg.skip_field(move |struct_, field| { // this is actually a union on linux, so we can't represent it well and // just insert some padding. @@ -2773,7 +2237,8 @@ fn test_linux(target: &str) { (musl && struct_ == "statvfs" && field == "__f_unused") || // sigev_notify_thread_id is actually part of a sigev_un union (struct_ == "sigevent" && field == "sigev_notify_thread_id") || - // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. + // signalfd had SIGSYS fields added in Linux 4.18, but no libc release + // has them yet. (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || field == "_pad2" || field == "ssi_syscall" || @@ -2781,70 +2246,148 @@ fn test_linux(target: &str) { field == "ssi_arch")) }); - // FIXME: remove - cfg.fn_cname(move |name, _cname| name.to_string()); - cfg.generate("../src/lib.rs", "main.rs"); - // On Linux also generate another script for testing linux/fcntl declarations. - // These cannot be tested normally because including both `linux/fcntl.h` and `fcntl.h` - // fails on a lot of platforms. - let mut cfg = ctest::TestGenerator::new(); - cfg.skip_type(|_| true) - .skip_fn(|_| true) - .skip_static(|_| true); - // musl defines these directly in `fcntl.h` - if musl { - cfg.header("fcntl.h"); - } else { - cfg.header("linux/fcntl.h"); + test_linux_like_apis(target); +} + +// This function tests APIs that are incompatible to test when other APIs +// are included (e.g. because including both sets of headers clashes) +fn test_linux_like_apis(target: &str) { + let musl = target.contains("musl"); + let linux = target.contains("linux"); + let emscripten = target.contains("emscripten"); + let android = target.contains("android"); + assert!(linux || android || emscripten); + + if linux || android || emscripten { + // test strerror_r from the `string.h` header + let mut cfg = ctest::TestGenerator::new(); + cfg.skip_type(|_| true).skip_static(|_| true); + + headers! { cfg: "string.h" } + cfg.skip_fn(|f| match f { + "strerror_r" => false, + _ => true, + }) + .skip_const(|_| true) + .skip_struct(|_| true); + cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); } - if !musl { - cfg.header("net/if.h"); - cfg.header("linux/if.h"); + + if linux || android || emscripten { + // test fcntl - see: + // http://man7.org/linux/man-pages/man2/fcntl.2.html + let mut cfg = ctest::TestGenerator::new(); + + if musl { + cfg.header("fcntl.h"); + } else { + cfg.header("linux/fcntl.h"); + } + + cfg.skip_type(|_| true) + .skip_static(|_| true) + .skip_struct(|_| true) + .skip_fn(|_| true) + .skip_const(move |name| match name { + // test fcntl constants: + "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" + | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" + | "F_SEAL_WRITE" => false, + _ => true, + }) + .type_name(move |ty, is_struct, is_union| match ty { + t if is_struct => format!("struct {}", t), + t if is_union => format!("union {}", t), + t => t.to_string(), + }); + + cfg.generate("../src/lib.rs", "linux_fcntl.rs"); } - cfg.header("linux/quota.h"); - cfg.header("asm/termbits.h"); - cfg.skip_const(move |name| match name { - "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false, - "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" => { - false - } - "QFMT_VFS_OLD" | "QFMT_VFS_V0" | "QFMT_VFS_V1" if mips => false, - "BOTHER" => false, - _ => true, - }); - cfg.skip_struct(|s| s != "termios2"); - cfg.type_name(move |ty, is_struct, is_union| match ty { - t if is_struct => format!("struct {}", t), - t if is_union => format!("union {}", t), - t => t.to_string(), - }); - cfg.generate("../src/lib.rs", "linux_fcntl.rs"); - // Test Elf64_Phdr and Elf32_Phdr - // These types have a field called `p_type`, but including - // "resolve.h" defines a `p_type` macro that expands to `__p_type` - // making the tests for these fails when both are included. - let mut cfg = ctest::TestGenerator::new(); - cfg.skip_fn(|_| true) - .skip_const(|_| true) - .skip_static(|_| true) - .type_name(move |ty, _is_struct, _is_union| { - ty.to_string() - }); - cfg.skip_struct(move |ty| { - match ty { - "Elf64_Phdr" | "Elf32_Phdr" => false, - _ => true, - } - }); - cfg.skip_type(move |ty| { - match ty { - "Elf64_Phdr" | "Elf32_Phdr" => false, - _ => true, - } - }); - cfg.header("elf.h"); - cfg.generate("../src/lib.rs", "linux_elf.rs"); + if linux || android { + // test termios + let mut cfg = ctest::TestGenerator::new(); + cfg.header("asm/termbits.h"); + cfg.skip_type(|_| true) + .skip_static(|_| true) + .skip_fn(|_| true) + .skip_const(|c| c != "BOTHER") + .skip_struct(|s| s != "termios2") + .type_name(move |ty, is_struct, is_union| match ty { + t if is_struct => format!("struct {}", t), + t if is_union => format!("union {}", t), + t => t.to_string(), + }); + cfg.generate("../src/lib.rs", "linux_termios.rs"); + } + + if linux || android { + // test IPV6_ constants: + let mut cfg = ctest::TestGenerator::new(); + headers! { + cfg: + "linux/in6.h" + } + cfg.skip_type(|_| true) + .skip_static(|_| true) + .skip_fn(|_| true) + .skip_const(|_| true) + .skip_struct(|_| true) + .skip_const(move |name| match name { + "IPV6_FLOWINFO" + | "IPV6_FLOWLABEL_MGR" + | "IPV6_FLOWINFO_SEND" + | "IPV6_FLOWINFO_FLOWLABEL" + | "IPV6_FLOWINFO_PRIORITY" => false, + _ => true, + }) + .type_name(move |ty, is_struct, is_union| match ty { + t if is_struct => format!("struct {}", t), + t if is_union => format!("union {}", t), + t => t.to_string(), + }); + cfg.generate("../src/lib.rs", "linux_ipv6.rs"); + } + + if linux || android { + // Test Elf64_Phdr and Elf32_Phdr + // These types have a field called `p_type`, but including + // "resolve.h" defines a `p_type` macro that expands to `__p_type` + // making the tests for these fails when both are included. + let mut cfg = ctest::TestGenerator::new(); + cfg.header("elf.h"); + cfg.skip_fn(|_| true) + .skip_static(|_| true) + .skip_fn(|_| true) + .skip_const(|_| true) + .type_name(move |ty, _is_struct, _is_union| ty.to_string()) + .skip_struct(move |ty| match ty { + "Elf64_Phdr" | "Elf32_Phdr" => false, + _ => true, + }) + .skip_type(move |ty| match ty { + "Elf64_Phdr" | "Elf32_Phdr" => false, + _ => true, + }); + cfg.generate("../src/lib.rs", "linux_elf.rs"); + } +} + +fn which_freebsd() -> Option<i32> { + let output = std::process::Command::new("freebsd-version") + .output() + .ok()?; + if !output.status.success() { + return None; + } + + let stdout = String::from_utf8(output.stdout).ok()?; + + match &stdout { + s if s.starts_with("11") => Some(11), + s if s.starts_with("12") => Some(12), + _ => None, + } } diff --git a/libc/libc-test/test/linux_elf.rs b/libc/libc-test/test/linux_elf.rs new file mode 100644 index 0000000..d149c9a --- /dev/null +++ b/libc/libc-test/test/linux_elf.rs @@ -0,0 +1,12 @@ +#![allow(bad_style, improper_ctypes, unused, deprecated)] + +extern crate libc; +use libc::*; + +#[cfg(target_os = "linux")] +include!(concat!(env!("OUT_DIR"), "/linux_elf.rs")); + +#[cfg(not(target_os = "linux"))] +fn main() { + println!("PASSED 0 tests"); +} diff --git a/libc/libc-test/test/linux_fcntl.rs b/libc/libc-test/test/linux_fcntl.rs index a54636c..49c06cc 100644 --- a/libc/libc-test/test/linux_fcntl.rs +++ b/libc/libc-test/test/linux_fcntl.rs @@ -7,4 +7,6 @@ use libc::*; include!(concat!(env!("OUT_DIR"), "/linux_fcntl.rs")); #[cfg(not(any(target_os = "linux", target_os = "android")))] -fn main() {} +fn main() { + println!("PASSED 0 tests"); +} diff --git a/libc/libc-test/test/linux_ipv6.rs b/libc/libc-test/test/linux_ipv6.rs new file mode 100644 index 0000000..83c389c --- /dev/null +++ b/libc/libc-test/test/linux_ipv6.rs @@ -0,0 +1,12 @@ +#![allow(bad_style, improper_ctypes, unused, deprecated)] + +extern crate libc; +use libc::*; + +#[cfg(target_os = "linux")] +include!(concat!(env!("OUT_DIR"), "/linux_ipv6.rs")); + +#[cfg(not(target_os = "linux"))] +fn main() { + println!("PASSED 0 tests"); +} diff --git a/libc/libc-test/test/linux_strerror_r.rs b/libc/libc-test/test/linux_strerror_r.rs new file mode 100644 index 0000000..17db959 --- /dev/null +++ b/libc/libc-test/test/linux_strerror_r.rs @@ -0,0 +1,12 @@ +#![allow(bad_style, improper_ctypes, unused, deprecated)] + +extern crate libc; +use libc::*; + +#[cfg(any(target_os = "linux", target_os = "android"))] +include!(concat!(env!("OUT_DIR"), "/linux_strerror_r.rs")); + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +fn main() { + println!("PASSED 0 tests"); +} diff --git a/libc/libc-test/test/linux_termios.rs b/libc/libc-test/test/linux_termios.rs new file mode 100644 index 0000000..703a9b9 --- /dev/null +++ b/libc/libc-test/test/linux_termios.rs @@ -0,0 +1,12 @@ +#![allow(bad_style, improper_ctypes, unused, deprecated)] + +extern crate libc; +use libc::*; + +#[cfg(any(target_os = "linux", target_os = "android"))] +include!(concat!(env!("OUT_DIR"), "/linux_termios.rs")); + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +fn main() { + println!("PASSED 0 tests"); +} |