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