From f229422cc1a0d46d15a7f953f59d8e057ae03865 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 12 Mar 2019 10:58:30 -0700 Subject: [PATCH] SGX target: fix std unit tests --- src/libstd/Cargo.toml | 4 ++ src/libstd/env.rs | 3 +- src/libstd/fs.rs | 2 +- src/libstd/net/addr.rs | 6 +++ src/libstd/net/tcp.rs | 62 +++++++++++++++++------ src/libstd/net/test.rs | 10 ++-- src/libstd/net/udp.rs | 2 +- src/libstd/path.rs | 4 +- src/libstd/process.rs | 2 +- src/libstd/sync/condvar.rs | 4 ++ src/libstd/sync/mpsc/mod.rs | 23 ++++++--- src/libstd/sys/sgx/abi/mod.rs | 5 ++ src/libstd/sys/sgx/abi/panic.rs | 2 +- src/libstd/sys/sgx/abi/tls.rs | 39 ++------------ src/libstd/sys/sgx/abi/usercalls/alloc.rs | 9 +++- src/libstd/sys/sgx/alloc.rs | 2 + src/libstd/sys/sgx/args.rs | 3 ++ src/libstd/sys/sgx/condvar.rs | 3 +- src/libstd/sys/sgx/net.rs | 60 +++++++++++++++++++--- src/libstd/sys/sgx/os.rs | 4 ++ src/libstd/sys/sgx/rwlock.rs | 51 ++++++++++++++----- src/libstd/sys/sgx/stack_overflow.rs | 1 + src/libstd/sys/sgx/thread.rs | 5 ++ src/libstd/sys/sgx/waitqueue.rs | 12 ++++- src/libstd/thread/local.rs | 6 +-- src/libstd/thread/mod.rs | 5 +- src/tools/tidy/src/pal.rs | 1 + 27 files changed, 236 insertions(+), 94 deletions(-) diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 1a6b58f35b398..b2eaf956d0e2d 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -72,3 +72,7 @@ wasm-bindgen-threads = [] # https://github.com/rust-lang-nursery/stdsimd/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = [] std_detect_dlsym_getauxval = [] + +[package.metadata.fortanix-sgx] +# Maximum possible number of threads when testing +threads = 125 diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 97c67f562a7df..f723a2b0bb281 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -975,7 +975,7 @@ mod tests { use crate::path::Path; #[test] - #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] fn test_self_exe_path() { let path = current_exe(); assert!(path.is_ok()); @@ -989,6 +989,7 @@ mod tests { fn test() { assert!((!Path::new("test-path").is_absolute())); + #[cfg(not(target_env = "sgx"))] current_dir().unwrap(); } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 8c3d0da0a7e40..dfff44b88ea78 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -2095,7 +2095,7 @@ impl AsInnerMut for DirBuilder { } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::prelude::*; diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index f5a87cc3ea67a..eaa6a070154f7 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -941,7 +941,10 @@ mod tests { assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; } #[test] @@ -953,7 +956,10 @@ mod tests { assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] assert!(tsa("localhost:23924").unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; } #[test] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index ce0c5c0bb0dc7..7e14de7cc4f4a 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -929,12 +929,12 @@ impl fmt::Debug for TcpListener { #[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] mod tests { + use crate::fmt; use crate::io::{ErrorKind, IoVec, IoVecMut}; use crate::io::prelude::*; use crate::net::*; use crate::net::test::{next_test_ip4, next_test_ip6}; use crate::sync::mpsc::channel; - use crate::sys_common::AsInner; use crate::time::{Instant, Duration}; use crate::thread; @@ -1129,7 +1129,7 @@ mod tests { connect(i + 1, addr); t!(stream.write(&[i as u8])); }); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } } @@ -1162,7 +1162,7 @@ mod tests { connect(i + 1, addr); t!(stream.write(&[99])); }); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } } @@ -1377,6 +1377,8 @@ mod tests { } #[test] + // FIXME: https://github.com/fortanix/rust-sgx/issues/110 + #[cfg_attr(target_env = "sgx", ignore)] fn shutdown_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -1397,6 +1399,8 @@ mod tests { } #[test] + // FIXME: https://github.com/fortanix/rust-sgx/issues/110 + #[cfg_attr(target_env = "sgx", ignore)] fn close_readwrite_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -1550,30 +1554,51 @@ mod tests { #[test] fn debug() { - let name = if cfg!(windows) {"socket"} else {"fd"}; + #[cfg(not(target_env = "sgx"))] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr + } + #[cfg(target_env = "sgx")] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr.to_string() + } + + #[cfg(unix)] + use crate::os::unix::io::AsRawFd; + #[cfg(target_env = "sgx")] + use crate::os::fortanix_sgx::io::AsRawFd; + #[cfg(not(windows))] + fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { + addr.as_raw_fd() + } + #[cfg(windows)] + fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { + addr.as_raw_socket() + } + + let inner_name = if cfg!(windows) {"socket"} else {"fd"}; let socket_addr = next_test_ip4(); let listener = t!(TcpListener::bind(&socket_addr)); - let listener_inner = listener.0.socket().as_inner(); let compare = format!("TcpListener {{ addr: {:?}, {}: {:?} }}", - socket_addr, name, listener_inner); + render_socket_addr(&socket_addr), + inner_name, + render_inner(&listener)); assert_eq!(format!("{:?}", listener), compare); - let stream = t!(TcpStream::connect(&("localhost", - socket_addr.port()))); - let stream_inner = stream.0.socket().as_inner(); - let compare = format!("TcpStream {{ addr: {:?}, \ - peer: {:?}, {}: {:?} }}", - stream.local_addr().unwrap(), - stream.peer_addr().unwrap(), - name, - stream_inner); + let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + let compare = format!("TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", + render_socket_addr(&stream.local_addr().unwrap()), + render_socket_addr(&stream.peer_addr().unwrap()), + inner_name, + render_inner(&stream)); assert_eq!(format!("{:?}", stream), compare); } // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code // no longer has rounding errors. #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 #[test] fn timeouts() { let addr = next_test_ip4(); @@ -1601,6 +1626,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_read_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1618,6 +1644,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_read_with_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1661,6 +1688,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn nodelay() { let addr = next_test_ip4(); let _listener = t!(TcpListener::bind(&addr)); @@ -1675,6 +1703,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn ttl() { let ttl = 100; @@ -1691,6 +1720,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] fn set_nonblocking() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -1712,6 +1742,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn peek() { each_ip(&mut |addr| { let (txdone, rxdone) = channel(); @@ -1743,6 +1774,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn connect_timeout_valid() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs index 89fefd9d1d5e0..e2991cbdd8822 100644 --- a/src/libstd/net/test.rs +++ b/src/libstd/net/test.rs @@ -36,12 +36,16 @@ pub fn tsa(a: A) -> Result, String> { // all want to use ports. This function figures out which workspace // it is running in and assigns a port range based on it. fn base_port() -> u16 { - let cwd = env::current_dir().unwrap(); + let cwd = if cfg!(target_env = "sgx") { + String::from("sgx") + } else { + env::current_dir().unwrap().into_os_string().into_string().unwrap() + }; let dirs = ["32-opt", "32-nopt", "musl-64-opt", "cross-opt", "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt", - "all-opt", "snap3", "dist"]; + "all-opt", "snap3", "dist", "sgx"]; dirs.iter().enumerate().find(|&(_, dir)| { - cwd.to_str().unwrap().contains(dir) + cwd.contains(dir) }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600 } diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index edc9d665444a0..951f385fb3ea5 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -806,7 +806,7 @@ impl fmt::Debug for UdpSocket { } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::ErrorKind; use crate::net::*; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ea3fcd8ce2859..4048bc4da2557 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -3801,7 +3801,7 @@ mod tests { }); ); - if cfg!(unix) { + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { tp!("", "foo", "foo"); tp!("foo", "bar", "foo/bar"); tp!("foo/", "bar", "foo/bar"); @@ -3960,7 +3960,7 @@ mod tests { tfn!("foo", "bar", "bar"); tfn!("foo", "", ""); tfn!("", "foo", "foo"); - if cfg!(unix) { + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { tfn!(".", "foo", "./foo"); tfn!("foo/", "bar", "bar"); tfn!("foo/.", "bar", "bar"); diff --git a/src/libstd/process.rs b/src/libstd/process.rs index ad86acbb47de4..054b398b01f26 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1621,7 +1621,7 @@ impl Termination for ExitCode { } } -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] mod tests { use crate::io::prelude::*; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index c383f21dcd752..2e8182671dd6f 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -705,6 +705,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -724,6 +725,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_until_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -748,6 +750,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_until_wake() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair_copy = pair.clone(); @@ -771,6 +774,7 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn wait_timeout_wake() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 90c5c50c23b9c..4ed2bfb175a46 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1951,7 +1951,7 @@ mod tests { for _ in 0..10000 { assert_eq!(rx.recv().unwrap(), 1); } - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -1977,7 +1977,7 @@ mod tests { }); } drop(tx); - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -1996,8 +1996,8 @@ mod tests { tx2.send(1).unwrap(); } }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); } #[test] @@ -2011,7 +2011,7 @@ mod tests { for _ in 0..40 { tx.send(1).unwrap(); } - t.join().ok().unwrap(); + t.join().ok().expect("thread panicked"); } #[test] @@ -2026,8 +2026,8 @@ mod tests { tx1.send(1).unwrap(); assert_eq!(rx2.recv().unwrap(), 2); }); - t1.join().ok().unwrap(); - t2.join().ok().unwrap(); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); } #[test] @@ -2225,6 +2225,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn oneshot_single_thread_recv_timeout() { let (tx, rx) = channel(); tx.send(()).unwrap(); @@ -2235,6 +2236,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_two_threads() { let (tx, rx) = channel(); let stress = stress_factor() + 100; @@ -2265,6 +2267,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn recv_timeout_upgrade() { let (tx, rx) = channel::<()>(); let timeout = Duration::from_millis(1); @@ -2276,6 +2279,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_shared() { let (tx, rx) = channel(); let stress = stress_factor() + 100; @@ -2306,6 +2310,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn very_long_recv_timeout_wont_panic() { let (tx, rx) = channel::<()>(); let join_handle = thread::spawn(move || { @@ -2325,6 +2330,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn shared_recv_timeout() { let (tx, rx) = channel(); let total = 5; @@ -2550,6 +2556,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn recv_timeout() { let (tx, rx) = sync_channel::(1); assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); @@ -2639,6 +2646,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_two_threads() { let (tx, rx) = sync_channel::(0); @@ -2662,6 +2670,7 @@ mod sync_tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn stress_recv_timeout_shared() { const AMT: u32 = 1000; const NTHREADS: u32 = 8; diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 7426f7be9e961..85ec8be4aae69 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test + use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::Write; @@ -12,8 +14,10 @@ pub mod tls; #[macro_use] pub mod usercalls; +#[cfg(not(test))] global_asm!(include_str!("entry.S")); +#[cfg(not(test))] #[no_mangle] unsafe extern "C" fn tcs_init(secondary: bool) { // Be very careful when changing this code: it runs before the binary has been @@ -48,6 +52,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { // FIXME: this item should only exist if this is linked into an executable // (main function exists). If this is a library, the crate author should be // able to specify this +#[cfg(not(test))] #[no_mangle] extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) { // FIXME: how to support TLS in library mode? diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs index 83411cb5b4c26..de86394b4b88c 100644 --- a/src/libstd/sys/sgx/abi/panic.rs +++ b/src/libstd/sys/sgx/abi/panic.rs @@ -49,7 +49,7 @@ impl Write for SgxPanicOutput { } } -#[no_mangle] +#[cfg_attr(not(test), no_mangle)] pub extern "C" fn panic_msg(msg: &str) -> ! { let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes())); usercalls::exit(true) diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs index b2a812c7231da..6b9ab7e383c01 100644 --- a/src/libstd/sys/sgx/abi/tls.rs +++ b/src/libstd/sys/sgx/abi/tls.rs @@ -10,45 +10,16 @@ const USIZE_BITS: usize = 64; const TLS_KEYS: usize = 128; // Same as POSIX minimum const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE"] static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT; macro_rules! dup { ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* )); (() $($val:tt)*) => ([$($val),*]) } -static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = [ - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), - AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), -]; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE"] +static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0))); extern "C" { fn get_tls_ptr() -> *const u8; diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index b787bd1a5abac..449a5fe5ae308 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -188,8 +188,13 @@ impl User where T: UserSafe { // from outside as obtained by `super::alloc`. fn new_uninit_bytes(size: usize) -> Self { unsafe { - let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed"); - User(NonNull::new_userref(T::from_raw_sized(ptr as _, size))) + // Mustn't call alloc with size 0. + let ptr = if size > 0 { + super::alloc(size, T::align_of()).expect("User memory allocation failed") as _ + } else { + T::align_of() as _ // dangling pointer ok for size 0 + }; + User(NonNull::new_userref(T::from_raw_sized(ptr, size))) } } diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs index 94dc8ec25b587..98eb8397436bf 100644 --- a/src/libstd/sys/sgx/alloc.rs +++ b/src/libstd/sys/sgx/alloc.rs @@ -4,6 +4,8 @@ use super::waitqueue::SpinMutex; // Using a SpinMutex because we never want to exit the enclave waiting for the // allocator. +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"] static DLMALLOC: SpinMutex = SpinMutex::new(dlmalloc::DLMALLOC_INIT); #[stable(feature = "alloc_system_type", since = "1.28.0")] diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs index b73bf9213b772..a84ab4138761e 100644 --- a/src/libstd/sys/sgx/args.rs +++ b/src/libstd/sys/sgx/args.rs @@ -5,9 +5,12 @@ use crate::sys::os_str::Buf; use crate::sys_common::FromInner; use crate::slice; +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE"] static ARGS: AtomicUsize = AtomicUsize::new(0); type ArgsStore = Vec; +#[cfg_attr(test, allow(dead_code))] pub unsafe fn init(argc: isize, argv: *const *const u8) { if argc != 0 { let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _); diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs index e9a7684f74d00..f9a76f0baf51a 100644 --- a/src/libstd/sys/sgx/condvar.rs +++ b/src/libstd/sys/sgx/condvar.rs @@ -32,7 +32,8 @@ impl Condvar { mutex.lock() } - pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool { + mutex.unlock(); // don't hold the lock while panicking panic!("timeout not supported in SGX"); } diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index e167e917957f3..592b300ac667c 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -41,12 +41,29 @@ impl FromInner for Socket { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct TcpStream { inner: Socket, peer_addr: Option, } +impl fmt::Debug for TcpStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = f.debug_struct("TcpStream"); + + if let Some(ref addr) = self.inner.local_addr { + res.field("addr", addr); + } + + if let Some(ref peer) = self.peer_addr { + res.field("peer", peer); + } + + res.field("fd", &self.inner.inner.as_inner()) + .finish() + } +} + fn io_err_to_addr(result: io::Result<&SocketAddr>) -> io::Result { match result { Ok(saddr) => Ok(saddr.to_string()), @@ -75,16 +92,32 @@ impl TcpStream { Ok(TcpStream { inner: Socket::new(fd, local_addr), peer_addr: Some(peer_addr) }) } - pub fn connect_timeout(addr: &SocketAddr, _: Duration) -> io::Result { + pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result { + if dur == Duration::default() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } Self::connect(Ok(addr)) // FIXME: ignoring timeout } - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - sgx_ineffective(()) + pub fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + match dur { + Some(dur) if dur == Duration::default() => { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } + _ => sgx_ineffective(()) + } } - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - sgx_ineffective(()) + pub fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + match dur { + Some(dur) if dur == Duration::default() => { + return Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot set a 0 duration timeout")); + } + _ => sgx_ineffective(()) + } } pub fn read_timeout(&self) -> io::Result> { @@ -174,11 +207,24 @@ impl FromInner<(Socket, Option)> for TcpStream { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct TcpListener { inner: Socket, } +impl fmt::Debug for TcpListener { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = f.debug_struct("TcpListener"); + + if let Some(ref addr) = self.inner.local_addr { + res.field("addr", addr); + } + + res.field("fd", &self.inner.inner.as_inner()) + .finish() + } +} + impl TcpListener { pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { let addr = io_err_to_addr(addr)?; diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs index 2725e66ce5de4..0bb7b897058db 100644 --- a/src/libstd/sys/sgx/os.rs +++ b/src/libstd/sys/sgx/os.rs @@ -73,7 +73,11 @@ pub fn current_exe() -> io::Result { unsupported() } +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx2os3ENVE"] static ENV: AtomicUsize = AtomicUsize::new(0); +#[cfg_attr(test, linkage = "available_externally")] +#[export_name = "_ZN16__rust_internals3std3sys3sgx2os8ENV_INITE"] static ENV_INIT: Once = Once::new(); type EnvStore = Mutex>; diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 372760bbf26b4..7b113267865b6 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,6 +1,9 @@ +#[cfg(not(test))] use crate::alloc::{self, Layout}; use crate::num::NonZeroUsize; +#[cfg(not(test))] use crate::slice; +#[cfg(not(test))] use crate::str; use super::waitqueue::{ @@ -147,6 +150,7 @@ impl RWLock { // only used by __rust_rwlock_unlock below #[inline] + #[cfg_attr(test, allow(dead_code))] unsafe fn unlock(&self) { let rguard = self.readers.lock(); let wguard = self.writer.lock(); @@ -161,9 +165,11 @@ impl RWLock { pub unsafe fn destroy(&self) {} } +#[cfg(not(test))] const EINVAL: i32 = 22; // used by libunwind port +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -173,6 +179,7 @@ pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { return 0; } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -181,6 +188,7 @@ pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { (*p).write(); return 0; } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { if p.is_null() { @@ -192,6 +200,7 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { // the following functions are also used by the libunwind port. They're // included here to make sure parallel codegen and LTO don't mess things up. +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { if s < 0 { @@ -203,17 +212,20 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { } } +#[cfg(not(test))] #[no_mangle] // NB. used by both libunwind and libpanic_abort pub unsafe extern "C" fn __rust_abort() { crate::sys::abort_internal(); } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { alloc::alloc(Layout::from_size_align_unchecked(size, align)) } +#[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) @@ -221,15 +233,13 @@ pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usiz #[cfg(test)] mod tests { - use super::*; use core::array::FixedSizeArray; - use crate::mem::MaybeUninit; - use crate::{mem, ptr}; + use crate::mem::{self, MaybeUninit}; - // The below test verifies that the bytes of initialized RWLock are the ones - // we use in libunwind. - // If they change we need to update src/UnwindRustSgx.h in libunwind. + // Verify that the bytes of initialized RWLock are the same as in + // libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to + // be changed too. #[test] fn test_c_rwlock_initializer() { const RWLOCK_INIT: &[u8] = &[ @@ -251,11 +261,28 @@ mod tests { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ]; - let mut init = MaybeUninit::::zeroed(); - init.set(RWLock::new()); - assert_eq!( - mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(), - RWLOCK_INIT - ); + #[inline(never)] + fn zero_stack() { + test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed()); + } + + #[inline(never)] + unsafe fn rwlock_new(init: &mut MaybeUninit) { + init.set(RWLock::new()); + } + + unsafe { + // try hard to make sure that the padding/unused bytes in RWLock + // get initialized as 0. If the assertion below fails, that might + // just be an issue with the test code and not with the value of + // RWLOCK_INIT. + zero_stack(); + let mut init = MaybeUninit::::zeroed(); + rwlock_new(&mut init); + assert_eq!( + mem::transmute::<_, [u8; 128]>(init.into_initialized()).as_slice(), + RWLOCK_INIT + ) + }; } } diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs index c0e7c824615c8..e63fa2bed65d5 100644 --- a/src/libstd/sys/sgx/stack_overflow.rs +++ b/src/libstd/sys/sgx/stack_overflow.rs @@ -6,6 +6,7 @@ impl Handler { } } +#[cfg_attr(test, allow(dead_code))] pub unsafe fn init() { } diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 13569062ac184..a3637723ba1bd 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,3 +1,4 @@ +#![cfg_attr(test, allow(dead_code))] // why is this necessary? use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; @@ -33,7 +34,11 @@ mod task_queue { } } + #[cfg_attr(test, linkage = "available_externally")] + #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"] static TASK_QUEUE_INIT: Once = Once::new(); + #[cfg_attr(test, linkage = "available_externally")] + #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"] static mut TASK_QUEUE: Option>> = None; pub(super) fn lock() -> MutexGuard<'static, Vec> { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index 1dbf2afbf4987..3f5e03ddad69e 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -498,6 +498,7 @@ mod spin_mutex { use super::*; use crate::sync::Arc; use crate::thread; + use crate::time::{SystemTime, Duration}; #[test] fn sleep() { @@ -507,7 +508,13 @@ mod spin_mutex { let t1 = thread::spawn(move || { *mutex2.lock() = 1; }); - thread::sleep_ms(50); + + // "sleep" for 50ms + // FIXME: https://github.com/fortanix/rust-sgx/issues/31 + let start = SystemTime::now(); + let max = Duration::from_millis(50); + while start.elapsed().unwrap() < max {} + assert_eq!(*guard, 0); drop(guard); t1.join().unwrap(); @@ -530,7 +537,8 @@ mod tests { let locked = wq.lock(); let t1 = thread::spawn(move || { - assert!(WaitQueue::notify_one(wq2.lock()).is_none()) + // if we obtain the lock, the main thread should be waiting + assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); }); WaitQueue::wait(locked); diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 7ad6b124e3a38..b73c5856b8805 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -530,7 +530,7 @@ mod tests { thread::spawn(|| { assert!(FOO.try_with(|_| ()).is_ok()); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -584,7 +584,7 @@ mod tests { thread::spawn(move|| { drop(S1); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -600,7 +600,7 @@ mod tests { thread::spawn(move|| unsafe { K1.with(|s| *s.get() = Some(S1)); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } // Note that this test will deadlock if TLS destructors aren't run (this diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 08f0aa2f0d206..8f323b59bf8e1 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1497,7 +1497,7 @@ mod tests { fn test_unnamed_thread() { thread::spawn(move|| { assert!(thread::current().name().is_none()); - }).join().ok().unwrap(); + }).join().ok().expect("thread panicked"); } #[test] @@ -1691,6 +1691,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_park_timeout_unpark_not_called() { for _ in 0..10 { thread::park_timeout(Duration::from_millis(10)); @@ -1698,6 +1699,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn test_park_timeout_unpark_called_other_thread() { for _ in 0..10 { let th = thread::current(); @@ -1712,6 +1714,7 @@ mod tests { } #[test] + #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 fn sleep_ms_smoke() { thread::sleep(Duration::from_millis(2)); } diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index ed2218f09d26b..0be3ec839e9a2 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -54,6 +54,7 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libstd/f64.rs", // Integration test for platform-specific run-time feature detection: "src/libstd/tests/run-time-detect.rs" , + "src/libstd/net/test.rs", "src/libstd/sys_common/mod.rs", "src/libstd/sys_common/net.rs", "src/libterm", // Not sure how to make this crate portable, but test crate needs it.