From e6717e8ff516d56206f2de1a9cb1aeea53fa9ea7 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 2 Aug 2014 18:25:42 -0700 Subject: [PATCH 1/2] Add `repr_c_implicit_padding` lint (off by default) The `repr_c_implicit_padding` lint checks structures marked a u8 followed by a u64, which would require 7 bytes of padding to get the u64 aligned correctly. The reason for this is that in the BSD socket code, there is some shifty casting between structs which results in data being stored in padding bytes. Since the LLVM Load instruction does not copy padding, this can result in data loss. (This is also a problem in C, but since structs are rarely copied by value, instead using pointers and memcpy(), it is not as serious a problem.) We therefore need explicit padding for the socket structures, and this lint will make sure we get it. This is necessary because the recent pull https://github.com/rust-lang/rust/pull/16081 which is a fix for #15763, changes the return value semantics to involve a Load. Without padding fixes, this breaks the Tcp code. --- src/libnative/io/addrinfo.rs | 3 ++- src/librustc/lint/builtin.rs | 6 +++++- src/librustc/lint/context.rs | 10 ++++++++++ src/librustc/middle/trans/base.rs | 31 +++++++++++++++++++++++++++++++ src/librustuv/addrinfo.rs | 1 + 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/libnative/io/addrinfo.rs b/src/libnative/io/addrinfo.rs index 7a07b6221277f..99a484075185e 100644 --- a/src/libnative/io/addrinfo.rs +++ b/src/libnative/io/addrinfo.rs @@ -40,7 +40,8 @@ impl GetAddrInfoRequest { ai_addrlen: 0, ai_canonname: mut_null(), ai_addr: mut_null(), - ai_next: mut_null() + ai_next: mut_null(), + __padding: [0, ..4] } }); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 1667f2b6d5f0a..646ce73fe3e7f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1536,6 +1536,9 @@ declare_lint!(pub UNKNOWN_CRATE_TYPE, Deny, declare_lint!(pub VARIANT_SIZE_DIFFERENCE, Allow, "detects enums with widely varying variant sizes") +declare_lint!(pub REPR_C_IMPLICIT_PADDING, Allow, + "detects implicit padding, which cannot be memset reliably, in C structures") + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. pub struct HardwiredLints; @@ -1554,7 +1557,8 @@ impl LintPass for HardwiredLints { WARNINGS, UNKNOWN_FEATURES, UNKNOWN_CRATE_TYPE, - VARIANT_SIZE_DIFFERENCE + VARIANT_SIZE_DIFFERENCE, + REPR_C_IMPLICIT_PADDING ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 7d9ec29d70144..5c2fce2c21722 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -638,6 +638,16 @@ impl LintPass for GatherNodeLevels { _ => { } } }, + ast::ItemStruct(..) => { + let lint_id = LintId::of(builtin::REPR_C_IMPLICIT_PADDING); + match cx.lints.get_level_source(lint_id) { + lvlsrc @ (lvl, _) if lvl != Allow => { + cx.node_levels.borrow_mut() + .insert((it.id, lint_id), lvlsrc); + }, + _ => { } + } + } _ => { } } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f1e84b8da8105..9ee62c1f3a2c5 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1908,6 +1908,29 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, } } +fn struct_repr_padding_lint(ccx: &CrateContext, struct_def: &ast::StructDef, id: ast::NodeId) { + let levels = ccx.tcx.node_lint_levels.borrow(); + let lint_id = lint::LintId::of(lint::builtin::REPR_C_IMPLICIT_PADDING); + let lvlsrc = match levels.find(&(id, lint_id)) { + None | Some(&(lint::Allow, _)) => return, + Some(&lvlsrc) => lvlsrc, + }; + + let mut total_size = 0; + for field in struct_def.fields.iter() { + let align = llalign_of_min(ccx, sizing_type_of(ccx, + ty::node_id_to_type(&ccx.tcx, field.node.id))); + if total_size % align != 0 { + lint::raw_emit_lint(&ccx.tcx().sess, lint::builtin::REPR_C_IMPLICIT_PADDING, + lvlsrc, Some(field.span), + format!("field expects alignment of {} bytes, but is being \ + inserted after {}", align, total_size).as_slice()); + } + total_size += llsize_of_real(ccx, sizing_type_of(ccx, + ty::node_id_to_type(&ccx.tcx, field.node.id))); + } +} + pub struct TransItemVisitor<'a> { pub ccx: &'a CrateContext, } @@ -1977,6 +2000,14 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { ast::ItemForeignMod(ref foreign_mod) => { foreign::trans_foreign_mod(ccx, foreign_mod); } + ast::ItemStruct(ref struct_definition, _) => { + // Only run the struct padding lint if we have #[repr(C)] + if item.attrs.iter().fold(attr::ReprAny, |acc, attr| { + attr::find_repr_attr(ccx.tcx.sess.diagnostic(), attr, acc) + }) == attr::ReprExtern { + struct_repr_padding_lint(ccx, &**struct_definition, item.id); + } + } ast::ItemTrait(..) => { // Inside of this trait definition, we won't be actually translating any // functions, but the trait still needs to be walked. Otherwise default diff --git a/src/librustuv/addrinfo.rs b/src/librustuv/addrinfo.rs index 6eaab1c096170..7a940bc0e45e1 100644 --- a/src/librustuv/addrinfo.rs +++ b/src/librustuv/addrinfo.rs @@ -65,6 +65,7 @@ impl GetAddrInfoRequest { ai_canonname: mut_null(), ai_addr: mut_null(), ai_next: mut_null(), + __padding: [0, ..4] } }); let hint_ptr = hint.as_ref().map_or(null(), |x| { From 040d3d507d02ee68cae446c200e5d730a6142a18 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 2 Aug 2014 18:30:05 -0700 Subject: [PATCH 2/2] liblibc: Add #[repr(C)] and explicit padding to all network structures I have only added padding for the Linux structures -- when compiling on other systems (which I don't have available) the compiler will flag which fields require additional padding to be added. --- src/liblibc/lib.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 1bc64ffcc92ae..21313858f8812 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -78,6 +78,7 @@ #![allow(non_uppercase_statics)] #![allow(missing_doc)] #![allow(uppercase_variables)] +#![warn(repr_c_implicit_padding)] #[cfg(test)] extern crate std; #[cfg(test)] extern crate test; @@ -369,6 +370,7 @@ pub mod types { pub type pthread_t = c_ulong; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub gl_pathv: *mut *mut c_char, @@ -381,11 +383,13 @@ pub mod types { pub __unused5: *mut c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -402,24 +406,30 @@ pub mod types { pub type sa_family_t = u16; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_family: sa_family_t, + pub __ss_pad1: [u8, ..6], pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -427,23 +437,28 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, pub ai_protocol: c_int, pub ai_addrlen: socklen_t, + pub __padding: [u8, ..4], #[cfg(target_os = "linux")] pub ai_addr: *mut sockaddr, @@ -459,6 +474,7 @@ pub mod types { pub ai_next: *mut addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [c_char, ..108] @@ -618,6 +634,7 @@ pub mod types { pub type blksize_t = i32; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: c_ulong, pub st_pad1: [c_long, ..3], @@ -641,11 +658,13 @@ pub mod types { pub st_pad5: [c_long, ..14], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u32, ..9] } @@ -702,6 +721,7 @@ pub mod types { pub type nlink_t = u64; pub type blksize_t = i64; pub type blkcnt_t = i64; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -723,11 +743,13 @@ pub mod types { pub __unused: [c_long, ..3], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __size: [u64, ..7] } @@ -752,6 +774,7 @@ pub mod types { pub type pthread_t = uintptr_t; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: size_t, @@ -768,11 +791,13 @@ pub mod types { pub __unused8: *mut c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -789,11 +814,13 @@ pub mod types { pub type sa_family_t = u8; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, @@ -801,6 +828,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, @@ -808,9 +836,11 @@ pub mod types { pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, @@ -819,17 +849,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -840,6 +874,7 @@ pub mod types { pub ai_addr: *mut sockaddr, pub ai_next: *mut addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, @@ -898,6 +933,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i64; pub type fflags_t = u32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -923,6 +959,7 @@ pub mod types { pub __unused: [uint8_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, @@ -950,6 +987,7 @@ pub mod types { pub type pthread_t = uintptr_t; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: size_t, @@ -966,11 +1004,13 @@ pub mod types { pub __unused8: *mut c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -987,11 +1027,13 @@ pub mod types { pub type sa_family_t = u8; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, @@ -999,6 +1041,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, @@ -1006,9 +1049,11 @@ pub mod types { pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, @@ -1017,17 +1062,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -1038,6 +1087,7 @@ pub mod types { pub ai_addr: *mut sockaddr, pub ai_next: *mut addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, @@ -1098,6 +1148,7 @@ pub mod types { pub type blkcnt_t = i64; pub type fflags_t = u32; + #[repr(C)] pub struct stat { pub st_ino: ino_t, pub st_nlink: nlink_t, @@ -1122,6 +1173,7 @@ pub mod types { pub st_qspare1: int64_t, pub st_qspare2: int64_t, } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, @@ -1150,6 +1202,7 @@ pub mod types { // pub Note: this is the struct called stat64 in win32. Not stat, // nor stati64. + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, @@ -1165,16 +1218,19 @@ pub mod types { } // note that this is called utimbuf64 in win32 + #[repr(C)] pub struct utimbuf { pub actime: time64_t, pub modtime: time64_t, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -1191,24 +1247,29 @@ pub mod types { pub type sa_family_t = u16; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_family: sa_family_t, pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1216,17 +1277,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -1237,6 +1302,7 @@ pub mod types { pub ai_addr: *mut sockaddr, pub ai_next: *mut addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [c_char, ..108] @@ -1356,6 +1422,7 @@ pub mod types { pub type LPWCH = *mut WCHAR; pub type LPCH = *mut CHAR; + #[repr(C)] pub struct SECURITY_ATTRIBUTES { pub nLength: DWORD, pub lpSecurityDescriptor: LPVOID, @@ -1379,6 +1446,7 @@ pub mod types { pub type time64_t = i64; pub type int64 = i64; + #[repr(C)] pub struct STARTUPINFO { pub cb: DWORD, pub lpReserved: LPWSTR, @@ -1401,6 +1469,7 @@ pub mod types { } pub type LPSTARTUPINFO = *mut STARTUPINFO; + #[repr(C)] pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, @@ -1409,6 +1478,7 @@ pub mod types { } pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; + #[repr(C)] pub struct SYSTEM_INFO { pub wProcessorArchitecture: WORD, pub wReserved: WORD, @@ -1424,6 +1494,7 @@ pub mod types { } pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; + #[repr(C)] pub struct MEMORY_BASIC_INFORMATION { pub BaseAddress: LPVOID, pub AllocationBase: LPVOID, @@ -1435,6 +1506,7 @@ pub mod types { } pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION; + #[repr(C)] pub struct OVERLAPPED { pub Internal: *mut c_ulong, pub InternalHigh: *mut c_ulong, @@ -1445,6 +1517,7 @@ pub mod types { pub type LPOVERLAPPED = *mut OVERLAPPED; + #[repr(C)] pub struct FILETIME { pub dwLowDateTime: DWORD, pub dwHighDateTime: DWORD, @@ -1452,6 +1525,7 @@ pub mod types { pub type LPFILETIME = *mut FILETIME; + #[repr(C)] pub struct GUID { pub Data1: DWORD, pub Data2: WORD, @@ -1459,6 +1533,7 @@ pub mod types { pub Data4: [BYTE, ..8], } + #[repr(C)] pub struct WSAPROTOCOLCHAIN { pub ChainLen: c_int, pub ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN], @@ -1466,6 +1541,7 @@ pub mod types { pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN; + #[repr(C)] pub struct WSAPROTOCOL_INFO { pub dwServiceFlags1: DWORD, pub dwServiceFlags2: DWORD, @@ -1508,6 +1584,7 @@ pub mod types { pub type pthread_t = uintptr_t; + #[repr(C)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: c_int, @@ -1524,11 +1601,13 @@ pub mod types { pub __unused8: *mut c_void, } + #[repr(C)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } + #[repr(C)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, @@ -1546,11 +1625,13 @@ pub mod types { pub type sa_family_t = u8; pub type in_port_t = u16; pub type in_addr_t = u32; + #[repr(C)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8, ..14], } + #[repr(C)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, @@ -1558,6 +1639,7 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8, ..112], } + #[repr(C)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, @@ -1565,9 +1647,11 @@ pub mod types { pub sin_addr: in_addr, pub sin_zero: [u8, ..8], } + #[repr(C)] pub struct in_addr { pub s_addr: in_addr_t, } + #[repr(C)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, @@ -1576,17 +1660,21 @@ pub mod types { pub sin6_addr: in6_addr, pub sin6_scope_id: u32, } + #[repr(C)] pub struct in6_addr { pub s6_addr: [u16, ..8] } + #[repr(C)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } + #[repr(C)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } + #[repr(C)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, @@ -1597,6 +1685,7 @@ pub mod types { pub ai_addr: *mut sockaddr, pub ai_next: *mut addrinfo, } + #[repr(C)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, @@ -1654,6 +1743,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, @@ -1679,11 +1769,13 @@ pub mod types { pub st_qspare: [int64_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __sig: c_long, pub __opaque: [c_char, ..36] @@ -1694,6 +1786,7 @@ pub mod types { pub mod bsd44 { } pub mod extra { + #[repr(C)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32, @@ -1752,6 +1845,7 @@ pub mod types { pub type blksize_t = i64; pub type blkcnt_t = i32; + #[repr(C)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, @@ -1777,11 +1871,13 @@ pub mod types { pub st_qspare: [int64_t, ..2], } + #[repr(C)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } + #[repr(C)] pub struct pthread_attr_t { pub __sig: c_long, pub __opaque: [c_char, ..56] @@ -1792,6 +1888,7 @@ pub mod types { pub mod bsd44 { } pub mod extra { + #[repr(C)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32,