From 565e0ecf51811a24d7fdaebf7dba37604957747e Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Wed, 3 Feb 2021 22:16:47 +0000 Subject: [PATCH 1/4] Make `sigval` an union --- libc-test/build.rs | 91 ++-------------------------------------------- src/fuchsia/mod.rs | 22 ++++++++--- src/unix/mod.rs | 28 +++++++++++--- 3 files changed, 44 insertions(+), 97 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 7690716dab042..01e14bb7dcaf2 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -331,9 +331,6 @@ fn test_apple(target: &str) { return true; } match ty { - // FIXME(union): actually a union - "sigval" => true, - // FIXME(macos): The size is changed in recent macOSes. "malloc_zone_t" => true, // it is a moving target, changing through versions @@ -429,14 +426,6 @@ fn test_apple(target: &str) { } }); - cfg.skip_field_type(move |struct_, field| { - match (struct_, field) { - // FIXME(union): actually a union - ("sigevent", "sigev_value") => true, - _ => false, - } - }); - cfg.volatile_item(|i| { use ctest::VolatileItemKind::*; match i { @@ -576,23 +565,8 @@ fn test_openbsd(target: &str) { "sys/param.h", } - cfg.skip_struct(move |ty| { - if ty.starts_with("__c_anonymous_") { - return true; - } - match ty { - // FIXME(union): actually a union - "sigval" => true, - - _ => false, - } - }); - cfg.skip_const(move |name| { match name { - // Removed in OpenBSD 7.7 - "ATF_COM" | "ATF_PERM" | "ATF_PUBL" | "ATF_USETRAILERS" => true, - // Removed in OpenBSD 7.8 "CTL_FS" | "SO_NETPROC" => true, @@ -720,9 +694,6 @@ fn test_cygwin(target: &str) { t if t.ends_with("_t") => t.to_string(), - // sigval is a struct in Rust, but a union in C: - "sigval" => "union sigval".to_string(), - // put `struct` in front of all structs:. t if is_struct => format!("struct {t}"), @@ -1174,8 +1145,6 @@ fn test_solarish(target: &str) { return true; } match ty { - // union, not a struct - "sigval" => true, // a bunch of solaris-only fields "utmpx" if is_illumos => true, _ => false, @@ -1195,8 +1164,6 @@ fn test_solarish(target: &str) { "sigaction" if field == "sa_sigaction" => true, // Missing in illumos "sigevent" if field == "ss_sp" => true, - // Avoid sigval union issues - "sigevent" if field == "sigev_value" => true, // const issues "sigevent" if field == "sigev_notify_attributes" => true, @@ -1423,8 +1390,6 @@ fn test_netbsd(target: &str) { cfg.skip_struct(move |ty| { match ty { - // This is actually a union, not a struct - "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. "termios2" => true, @@ -1476,8 +1441,6 @@ fn test_netbsd(target: &str) { (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") }); @@ -1606,9 +1569,6 @@ fn test_dragonflybsd(target: &str) { t if t.ends_with("_t") => t.to_string(), - // sigval is a struct in Rust, but a union in C: - "sigval" => "union sigval".to_string(), - // put `struct` in front of all structs:. t if is_struct => format!("struct {t}"), @@ -1701,8 +1661,6 @@ fn test_dragonflybsd(target: &str) { (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") }); @@ -1993,9 +1951,6 @@ fn test_android(target: &str) { t if t.ends_with("_t") => t.to_string(), - // sigval is a struct in Rust, but a union in C: - "sigval" => "union sigval".to_string(), - "Ioctl" => "int".to_string(), // put `struct` in front of all structs:. @@ -2300,8 +2255,6 @@ fn test_android(target: &str) { cfg.skip_field_type(move |struct_, field| { // This is a weird union, don't check the type. (struct_ == "ifaddrs" && field == "ifa_ifu") || - // sigval is actually a union, but we pretend it's a struct - (struct_ == "sigevent" && field == "sigev_value") || // this one is an anonymous union (struct_ == "ff_effect" && field == "u") || // FIXME(android): `sa_sigaction` has type `sighandler_t` but that type is @@ -2504,9 +2457,6 @@ fn test_freebsd(target: &str) { t if t.ends_with("_t") => t.to_string(), - // sigval is a struct in Rust, but a union in C: - "sigval" => "union sigval".to_string(), - // put `struct` in front of all structs:. t if is_struct => format!("struct {t}"), @@ -3141,7 +3091,8 @@ fn test_emscripten(target: &str) { return true; } match ty { - // This is actually a union, not a struct + // FIXME(emscripten): Investigate why the test fails. + // Skip for now to unblock CI. "sigval" => true, // FIXME(emscripten): Investigate why the test fails. @@ -3222,9 +3173,7 @@ fn test_emscripten(target: &str) { // 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") + (struct_ == "sigaction" && field == "sa_sigaction") }); cfg.skip_field(move |struct_, field| { @@ -3437,9 +3386,6 @@ fn test_neutrino(target: &str) { match ty { "Elf64_Phdr" | "Elf32_Phdr" => true, - // FIXME(union): This is actually a union, not a struct - "sigval" => true, - // union "_channel_connect_attr" => true, @@ -3494,8 +3440,6 @@ fn test_neutrino(target: &str) { }); cfg.skip_field_type(move |struct_, field| { - // sigval is actually a union, but we pretend it's a struct - struct_ == "sigevent" && field == "sigev_value" || // Anonymous structures struct_ == "_idle_hook" && field == "time" }); @@ -3506,8 +3450,6 @@ fn test_neutrino(target: &str) { ("__sched_param", "reserved") | ("sched_param", "reserved") | ("sigevent", "__padding1") // ensure alignment - | ("sigevent", "__padding2") // union - | ("sigevent", "__sigev_un2") // union | ("sigaction", "sa_sigaction") // sighandler_t type is super weird | ("syspage_entry", "__reserved") // does not exist ) @@ -3612,10 +3554,8 @@ fn test_vxworks(target: &str) { // FIXME(vxworks) cfg.skip_fn(move |name| match name { - // sigval - "sigqueue" | "_sigqueue" // sighandler_t - | "signal" + "signal" // not used in static linking by default | "dlerror" => true, _ => false, @@ -4053,9 +3993,6 @@ fn test_linux(target: &str) { // which is absent in glibc, has to be defined. "__timeval" => true, - // FIXME(union): This is actually a union, not a struct - "sigval" => true, - // This type is tested in the `linux_termios.rs` file since there // are header conflicts when including them with all the other // structs. @@ -4752,12 +4689,6 @@ fn test_linux(target: &str) { // Needs musl 1.2.3 or later. "pthread_getname_np" if old_musl => true, - // pthread_sigqueue uses sigval, which was initially declared - // as a struct but should be defined as a union. However due - // to the issues described here: https://github.com/rust-lang/libc/issues/2816 - // it can't be changed from struct. - "pthread_sigqueue" => true, - // There are two versions of basename(3) on Linux with glibc, see // // https://man7.org/linux/man-pages/man3/basename.3.html @@ -4791,8 +4722,6 @@ fn test_linux(target: &str) { (struct_ == "sigaction" && field == "sa_sigaction") || // __timeval type is a patch which doesn't exist in glibc (struct_ == "utmpx" && field == "ut_tv") || - // sigval is actually a union, but we pretend it's a struct - (struct_ == "sigevent" && field == "sigev_value") || // this one is an anonymous union (struct_ == "ff_effect" && field == "u") || // `__exit_status` type is a patch which is absent in musl @@ -5273,8 +5202,6 @@ fn test_haiku(target: &str) { return true; } match ty { - // FIXME(union): actually a union - "sigval" => true, // FIXME(haiku): locale_t does not exist on Haiku "locale_t" => true, // FIXME(haiku): rusage has a different layout on Haiku @@ -5381,10 +5308,8 @@ fn test_haiku(target: &str) { ("stat", "st_crtime_nsec") => true, // these are actually unions, but we cannot represent it well - ("siginfo_t", "sigval") => true, ("sem_t", "named_sem_id") => true, ("sigaction", "sa_sigaction") => true, - ("sigevent", "sigev_value") => true, ("fpu_state", "_fpreg") => true, ("cpu_topology_node_info", "data") => true, // these fields have a simplified data definition in libc @@ -5435,8 +5360,6 @@ fn test_haiku(target: &str) { ty.to_string() } - // is actually a union - "sigval" => "union sigval".to_string(), t if is_union => format!("union {t}"), t if t.ends_with("_t") => t.to_string(), t if is_struct => format!("struct {t}"), @@ -5575,9 +5498,6 @@ fn test_aix(target: &str) { "FILE" => ty.to_string(), "ACTION" => ty.to_string(), - // 'sigval' is a struct in Rust, but a union in C. - "sigval" => format!("union sigval"), - t if t.ends_with("_t") => t.to_string(), t if is_struct => format!("struct {}", t), t if is_union => format!("union {}", t), @@ -5614,9 +5534,6 @@ fn test_aix(target: &str) { cfg.skip_struct(move |ty| { match ty { - // FIXME(union): actually a union. - "sigval" => true, - // '__poll_ctl_ext_u' and '__pollfd_ext_u' are for unnamed unions. "__poll_ctl_ext_u" => true, "__pollfd_ext_u" => true, diff --git a/src/fuchsia/mod.rs b/src/fuchsia/mod.rs index ee465beee648c..a22ef7fff954f 100644 --- a/src/fuchsia/mod.rs +++ b/src/fuchsia/mod.rs @@ -240,11 +240,6 @@ s! { pub l_linger: c_int, } - pub struct sigval { - // Actually a union of an int and a void* - pub sival_ptr: *mut c_void, - } - // pub struct itimerval { pub it_interval: crate::timeval, @@ -1043,6 +1038,11 @@ s_no_extra_traits! { pub struct pthread_cond_t { size: [u8; crate::__SIZEOF_PTHREAD_COND_T], } + + pub union sigval { + pub sival_int: c_int, + pub sival_ptr: *mut c_void, + } } cfg_if! { @@ -1305,6 +1305,18 @@ cfg_if! { self.size.hash(state); } } + + impl PartialEq for sigval { + fn eq(&self, other: &sigval) -> bool { + unimplemented!("traits") + } + } + impl Eq for sigval {} + impl hash::Hash for sigval { + fn hash(&self, state: &mut H) { + unimplemented!("traits") + } + } } } diff --git a/src/unix/mod.rs b/src/unix/mod.rs index c9a8964eb1099..d12b9be8c856d 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -173,11 +173,6 @@ s! { pub l_linger: c_int, } - pub struct sigval { - // Actually a union of an int and a void* - pub sival_ptr: *mut c_void, - } - // pub struct itimerval { pub it_interval: crate::timeval, @@ -217,6 +212,29 @@ s! { } } +s_no_extra_traits! { + pub union sigval { + pub sival_int: c_int, + pub sival_ptr: *mut c_void, + } +} + +cfg_if! { + if #[cfg(feature = "extra_traits")] { + impl PartialEq for sigval { + fn eq(&self, _other: &sigval) -> bool { + unimplemented!("traits") + } + } + impl Eq for sigval {} + impl hash::Hash for sigval { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") + } + } + } +} + pub const INT_MIN: c_int = -2147483648; pub const INT_MAX: c_int = 2147483647; From 654db78357fa56812333e1017a59e9c73ec199fe Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Thu, 4 Feb 2021 12:40:05 +0000 Subject: [PATCH 2/4] Make `ifaddrs.ifa_ifu` an union --- src/fuchsia/mod.rs | 19 ++++++++++++++++++- src/unix/linux_like/mod.rs | 19 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/fuchsia/mod.rs b/src/fuchsia/mod.rs index a22ef7fff954f..ddce003dffc4b 100644 --- a/src/fuchsia/mod.rs +++ b/src/fuchsia/mod.rs @@ -462,7 +462,7 @@ s! { pub ifa_flags: c_uint, pub ifa_addr: *mut crate::sockaddr, pub ifa_netmask: *mut crate::sockaddr, - pub ifa_ifu: *mut crate::sockaddr, // FIXME(union) This should be a union + pub ifa_ifu: __c_anonymous_ifaddrs_ifa_ifu, pub ifa_data: *mut c_void, } @@ -1043,6 +1043,11 @@ s_no_extra_traits! { pub sival_int: c_int, pub sival_ptr: *mut c_void, } + + pub union __c_anonymous_ifaddrs_ifa_ifu { + ifu_broadaddr: *mut sockaddr, + ifu_dstaddr: *mut sockaddr, + } } cfg_if! { @@ -1317,6 +1322,18 @@ cfg_if! { unimplemented!("traits") } } + + impl PartialEq for __c_anonymous_ifaddrs_ifa_ifu { + fn eq(&self, _other: &__c_anonymous_ifaddrs_ifa_ifu) -> bool { + unimplemented!("traits") + } + } + impl Eq for __c_anonymous_ifaddrs_ifa_ifu {} + impl hash::Hash for __c_anonymous_ifaddrs_ifa_ifu { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") + } + } } } diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index d121abbafa9a5..408df8c8ce647 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -168,7 +168,7 @@ s! { pub ifa_flags: c_uint, pub ifa_addr: *mut crate::sockaddr, pub ifa_netmask: *mut crate::sockaddr, - pub ifa_ifu: *mut crate::sockaddr, // FIXME(union) This should be a union + pub ifa_ifu: __c_anonymous_ifaddrs_ifa_ifu, pub ifa_data: *mut c_void, } @@ -335,6 +335,11 @@ s_no_extra_traits! { pub sigev_notify: c_int, pub _sigev_un: __c_anonymous_sigev_un, } + + pub union __c_anonymous_ifaddrs_ifa_ifu { + ifu_broadaddr: *mut sockaddr, + ifu_dstaddr: *mut sockaddr, + } } cfg_if! { @@ -438,6 +443,18 @@ cfg_if! { self.domainname.hash(state); } } + + impl PartialEq for __c_anonymous_ifaddrs_ifa_ifu { + fn eq(&self, _other: &__c_anonymous_ifaddrs_ifa_ifu) -> bool { + unimplemented!("traits") + } + } + impl Eq for __c_anonymous_ifaddrs_ifa_ifu {} + impl hash::Hash for __c_anonymous_ifaddrs_ifa_ifu { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") + } + } } } From 598f7eaf9f42f33f25268478977e4cd660cfe03d Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Thu, 4 Feb 2021 13:56:20 +0000 Subject: [PATCH 3/4] Implement `epoll_data` union --- libc-test/build.rs | 12 ------------ src/fuchsia/mod.rs | 25 ++++++++++++++++++++++--- src/unix/linux_like/mod.rs | 27 +++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 01e14bb7dcaf2..3dbd1cab4d6ce 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -1098,8 +1098,6 @@ fn test_solarish(target: &str) { cfg.field_name(move |struct_, field| { match struct_ { - // rust struct uses raw u64, rather than union - "epoll_event" if field == "u64" => "data.u64".to_string(), // rust struct was committed with typo for Solaris "door_arg_t" if field == "dec_num" => "desc_num".to_string(), "stat" if field.ends_with("_nsec") => { @@ -1372,7 +1370,6 @@ fn test_netbsd(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - "u64" if struct_ == "epoll_event" => "data.u64".to_string(), s => s.to_string(), } }); @@ -1583,7 +1580,6 @@ fn test_dragonflybsd(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - "u64" if struct_ == "epoll_event" => "data.u64".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(), @@ -1965,8 +1961,6 @@ fn test_android(target: &str) { // Our stat *_nsec fields normally don't actually exist but are part // of a timeval struct s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.to_string(), - // FIXME(union): appears that `epoll_event.data` is an union - "u64" if struct_ == "epoll_event" => "data.u64".to_string(), // 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. @@ -3064,8 +3058,6 @@ fn test_emscripten(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - // Rust struct uses raw u64, rather than union - "u64" if struct_ == "epoll_event" => "data.u64".to_string(), s => s.to_string(), } }); @@ -3875,10 +3867,6 @@ fn test_linux(target: &str) { s if s.ends_with("_nsec") && struct_.starts_with("stat") => { s.replace("e_nsec", ".tv_nsec") } - // FIXME(linux): epoll_event.data is actually 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(), // 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. diff --git a/src/fuchsia/mod.rs b/src/fuchsia/mod.rs index ddce003dffc4b..6aa1dae11215a 100644 --- a/src/fuchsia/mod.rs +++ b/src/fuchsia/mod.rs @@ -408,7 +408,7 @@ s! { pub struct epoll_event { pub events: u32, - pub u64: u64, + pub data: epoll_data, } pub struct lconv { @@ -1044,6 +1044,13 @@ s_no_extra_traits! { pub sival_ptr: *mut c_void, } + pub union epoll_data { + pub ptr: *mut c_void, + pub fd: c_int, + pub u32: u32, + pub u64: u64, + } + pub union __c_anonymous_ifaddrs_ifa_ifu { ifu_broadaddr: *mut sockaddr, ifu_dstaddr: *mut sockaddr, @@ -1312,13 +1319,25 @@ cfg_if! { } impl PartialEq for sigval { - fn eq(&self, other: &sigval) -> bool { + fn eq(&self, _other: &sigval) -> bool { unimplemented!("traits") } } impl Eq for sigval {} impl hash::Hash for sigval { - fn hash(&self, state: &mut H) { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") + } + } + + impl PartialEq for epoll_data { + fn eq(&self, _other: &epoll_data) -> bool { + unimplemented!("traits") + } + } + impl Eq for epoll_data {} + impl hash::Hash for epoll_data { + fn hash(&self, _state: &mut H) { unimplemented!("traits") } } diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 408df8c8ce647..5ac962e2b553f 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -297,6 +297,13 @@ s_no_extra_traits! { )] pub struct epoll_event { pub events: u32, + pub data: epoll_data, + } + + pub union epoll_data { + pub ptr: *mut c_void, + pub fd: c_int, + pub u32: u32, pub u64: u64, } @@ -345,17 +352,29 @@ s_no_extra_traits! { cfg_if! { if #[cfg(feature = "extra_traits")] { impl PartialEq for epoll_event { - fn eq(&self, other: &epoll_event) -> bool { - self.events == other.events && self.u64 == other.u64 + fn eq(&self, _other: &epoll_event) -> bool { + unimplemented!("traits") } } impl Eq for epoll_event {} impl hash::Hash for epoll_event { fn hash(&self, state: &mut H) { let events = self.events; - let u64 = self.u64; + let data = self.data; events.hash(state); - u64.hash(state); + data.hash(state); + } + } + + impl PartialEq for epoll_data { + fn eq(&self, _other: &epoll_data) -> bool { + unimplemented!("traits") + } + } + impl Eq for epoll_data {} + impl hash::Hash for epoll_data { + fn hash(&self, _state: &mut H) { + unimplemented!("traits") } } From 978d655ed8965fe9aea515c00bee8b5ae2e67283 Mon Sep 17 00:00:00 2001 From: kellda <59569234+kellda@users.noreply.github.com> Date: Thu, 4 Feb 2021 14:50:57 +0000 Subject: [PATCH 4/4] Make `fpreg_t` an union --- libc-test/build.rs | 2 -- src/unix/linux_like/linux/gnu/b64/s390x.rs | 14 ++++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 3dbd1cab4d6ce..4c2e9b6fb89ea 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -4818,8 +4818,6 @@ fn test_linux(target: &str) { cfg.skip_roundtrip(move |s| match s { // FIXME(1.0): "mcontext_t" if s390x => true, - // FIXME(union): This is actually a union. - "fpreg_t" if s390x => true, // The test doesn't work on some env: "ipv6_mreq" diff --git a/src/unix/linux_like/linux/gnu/b64/s390x.rs b/src/unix/linux_like/linux/gnu/b64/s390x.rs index 029485c5b4a32..583630ed37c74 100644 --- a/src/unix/linux_like/linux/gnu/b64/s390x.rs +++ b/src/unix/linux_like/linux/gnu/b64/s390x.rs @@ -212,27 +212,25 @@ s! { } s_no_extra_traits! { - // FIXME(union): This is actually a union. - pub struct fpreg_t { + pub union fpreg_t { pub d: c_double, - // f: c_float, + pub f: c_float, } } cfg_if! { if #[cfg(feature = "extra_traits")] { impl PartialEq for fpreg_t { - fn eq(&self, other: &fpreg_t) -> bool { - self.d == other.d + fn eq(&self, _other: &fpreg_t) -> bool { + unimplemented!("traits") } } impl Eq for fpreg_t {} impl hash::Hash for fpreg_t { - fn hash(&self, state: &mut H) { - let d: u64 = self.d.to_bits(); - d.hash(state); + fn hash(&self, _state: &mut H) { + unimplemented!("traits") } } }