You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by rd...@apache.org on 2022/10/22 18:39:51 UTC
[incubator-teaclave-sgx-sdk] branch v2.0.0-preview updated: Support rust-nightly-2022-10-22
This is an automated email from the ASF dual-hosted git repository.
rduan pushed a commit to branch v2.0.0-preview
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-sgx-sdk.git
The following commit(s) were added to refs/heads/v2.0.0-preview by this push:
new 4e1860a4 Support rust-nightly-2022-10-22
4e1860a4 is described below
commit 4e1860a4f49f74fe2b8af120400d5abe870006ca
Author: volcano <vo...@163.com>
AuthorDate: Sun Oct 23 02:36:56 2022 +0800
Support rust-nightly-2022-10-22
---
rust-toolchain | 2 +-
rustlib/panic_abort/src/lib.rs | 13 +-
rustlib/panic_unwind/Cargo.toml | 1 -
rustlib/panic_unwind/src/gcc.rs | 78 -
rustlib/panic_unwind/src/lib.rs | 16 +-
.../hyper-rustls-https-server/enclave/src/lib.rs | 6 +-
samplecode/rpc/client/enclave/src/lib.rs | 8 +-
samplecode/rpc/server/enclave/src/lib.rs | 10 +-
samplecode/seal/enclave/src/lib.rs | 12 +-
samplecode/switchless/app/build.rs | 5 +-
samplecode/switchless/app/src/main.rs | 14 +-
.../zlib-lazy-static-sample/enclave/src/lib.rs | 8 +-
sgx_alloc/src/alignalloc.rs | 2 +-
sgx_alloc/src/alignbox.rs | 8 +-
sgx_backtrace/src/symbolize/libbacktrace.rs | 2 +-
sgx_build_helper/build_helper/src/lib.rs | 4 +-
sgx_dcap/tkey_exchange/src/session/manager.rs | 10 +-
sgx_dcap/tvl/src/capi.rs | 4 +-
sgx_demangle/src/legacy.rs | 6 +-
sgx_edl/edl/sgx_fd.edl | 3 +
sgx_ffi/src/c_str.rs | 1548 +-------------------
sgx_ffi/src/c_str/tests.rs | 200 ---
sgx_ffi/src/lib.rs | 11 -
sgx_key_exchange/message/src/message.rs | 4 +-
.../tkey_exchange/src/session/manager.rs | 6 +-
sgx_key_exchange/ukey_exchange/src/capi.rs | 4 +-
sgx_key_exchange/ukey_exchange/src/session.rs | 4 +-
sgx_libc/Cargo.toml | 2 +-
sgx_libc/sgx_tlibc_sys/src/lib.rs | 1 +
sgx_libc/src/linux/ocall/fd.rs | 20 +-
sgx_libc/src/linux/ocall/sync.rs | 12 +-
sgx_libc/src/linux/pthread/mod.rs | 6 +-
sgx_oc/src/lib.rs | 1 +
sgx_oc/src/linux/edl/fd.rs | 6 +
sgx_oc/src/linux/mod.rs | 12 +-
sgx_oc/src/linux/ocall/env.rs | 2 +-
sgx_oc/src/linux/ocall/fd.rs | 25 +-
sgx_oc/src/linux/ocall/mem.rs | 8 +-
sgx_oc/src/linux/ocall/mod.rs | 37 +-
sgx_oc/src/linux/ocall/socket.rs | 14 +-
sgx_oc/src/linux/ocall/socket_msg.rs | 16 +-
sgx_oc/src/linux/x86_64/mod.rs | 5 +-
sgx_protected_fs/tfs/src/capi.rs | 8 +-
sgx_protected_fs/tfs/src/sys/error.rs | 4 +-
sgx_protected_fs/ufs/src/lib.rs | 4 +-
sgx_rand/src/isaac.rs | 2 +-
sgx_rsrvmm/src/rsrvmm/area.rs | 6 +-
sgx_rsrvmm/src/rsrvmm/manager.rs | 2 +-
sgx_serialize/src/json.rs | 13 +-
sgx_serialize/src/lib.rs | 3 +-
sgx_serialize/src/opaque.rs | 2 +-
sgx_serialize/src/types.rs | 67 +-
sgx_sync/Cargo.toml | 1 +
sgx_sync/src/capi.rs | 24 +-
sgx_sync/src/condvar.rs | 19 +-
sgx_sync/src/condvar/check.rs | 29 +-
sgx_sync/src/futex.rs | 12 +-
sgx_sync/src/lazy_box.rs | 118 ++
sgx_sync/src/lazy_lock.rs | 88 ++
sgx_sync/src/lib.rs | 10 +-
sgx_sync/src/mutex.rs | 22 +-
sgx_sync/src/{lazy.rs => once_lock.rs} | 200 +--
sgx_sync/src/remutex.rs | 38 +-
sgx_sync/src/rwlock.rs | 24 +-
sgx_sync/src/sys/condvar.rs | 116 +-
sgx_sync/src/sys/futex.rs | 24 +-
sgx_sync/src/sys/mod.rs | 5 +-
sgx_sync/src/sys/mutex.rs | 269 ++--
sgx_sync/src/sys/ocall/mod.rs | 2 +-
sgx_sync/src/sys/rwlock.rs | 188 ++-
sgx_tdh/src/capi.rs | 10 +-
sgx_tests/cov/src/lib.rs | 10 +-
sgx_tests/utils/src/lib.rs | 2 -
sgx_tests/utils/src/stats.rs | 6 +-
sgx_trts/src/arch.rs | 2 +
sgx_trts/src/call/ocalloc.rs | 4 +-
sgx_trts/src/capi.rs | 30 +-
sgx_trts/src/elf/control_flow.rs | 2 +-
sgx_trts/src/elf/header.rs | 2 +-
sgx_trts/src/elf/program.rs | 2 +-
sgx_trts/src/elf/slice.rs | 1 +
sgx_trts/src/enclave/parse.rs | 9 +-
sgx_trts/src/enclave/state.rs | 7 +-
sgx_trts/src/feature/sys.rs | 5 +-
sgx_trts/src/inst/hyper/inst.rs | 2 +
sgx_trts/src/inst/sim/tls/gnu.rs | 1 +
sgx_trts/src/lib.rs | 10 +-
sgx_trts/src/sync/lazy.rs | 257 ++++
sgx_trts/src/sync/mod.rs | 6 +-
sgx_trts/src/sync/mutex.rs | 2 +-
sgx_trts/src/sync/rwlock.rs | 2 +-
sgx_trts/src/tcs/list.rs | 2 +-
sgx_trts/src/tcs/tc.rs | 2 +-
sgx_trts/src/thread/tls/bitset.rs | 3 +-
sgx_trts/src/thread/tls/mod.rs | 8 +-
sgx_trts/src/veh/exception.rs | 10 +-
sgx_trts/src/veh/list.rs | 2 +-
sgx_trts/src/xsave.rs | 6 +-
sgx_tse/src/capi.rs | 6 +-
sgx_tse/src/se.rs | 2 +-
sgx_tstd/src/alloc.rs | 29 +-
sgx_tstd/src/backtrace.rs | 15 +-
sgx_tstd/src/backtrace/tests.rs | 6 +-
sgx_tstd/src/collections/hash/benches/map.rs | 2 -
sgx_tstd/src/collections/hash/map.rs | 258 +++-
sgx_tstd/src/collections/hash/map/tests.rs | 33 +-
sgx_tstd/src/collections/hash/set.rs | 107 +-
sgx_tstd/src/collections/hash/set/tests.rs | 10 +-
sgx_tstd/src/collections/mod.rs | 9 +-
sgx_tstd/src/env.rs | 77 +-
sgx_tstd/src/error.rs | 909 +-----------
sgx_tstd/src/error/tests.rs | 11 +-
sgx_tstd/src/f32.rs | 68 +-
sgx_tstd/src/f64.rs | 69 +-
sgx_tstd/src/ffi/c_str.rs | 58 -
sgx_tstd/src/ffi/mod.rs | 15 +-
sgx_tstd/src/ffi/os_str.rs | 84 +-
sgx_tstd/src/ffi/os_str/tests.rs | 14 +
sgx_tstd/src/fs.rs | 169 ++-
sgx_tstd/src/fs/tests.rs | 16 +-
sgx_tstd/src/io/buffered/bufreader.rs | 105 +-
sgx_tstd/src/io/buffered/bufreader/buffer.rs | 139 ++
sgx_tstd/src/io/buffered/bufwriter.rs | 4 +-
sgx_tstd/src/io/buffered/linewriter.rs | 4 +-
sgx_tstd/src/io/buffered/tests.rs | 59 +-
sgx_tstd/src/io/copy.rs | 44 +-
sgx_tstd/src/io/cursor.rs | 182 ++-
sgx_tstd/src/io/cursor/tests.rs | 135 +-
sgx_tstd/src/io/error.rs | 108 +-
sgx_tstd/src/io/error/repr_unpacked.rs | 6 +-
sgx_tstd/src/io/error/tests.rs | 72 +-
sgx_tstd/src/io/impls.rs | 62 +-
sgx_tstd/src/io/mod.rs | 194 ++-
sgx_tstd/src/io/prelude.rs | 2 +-
sgx_tstd/src/io/readbuf.rs | 316 ++--
sgx_tstd/src/io/readbuf/tests.rs | 218 ++-
sgx_tstd/src/io/stdio.rs | 476 +++---
sgx_tstd/src/io/stdio/tests.rs | 6 +-
sgx_tstd/src/io/tests.rs | 52 +-
sgx_tstd/src/io/util.rs | 14 +-
sgx_tstd/src/io/util/tests.rs | 48 +-
sgx_tstd/src/lib.rs | 140 +-
sgx_tstd/src/macros.rs | 66 +-
sgx_tstd/src/net/display_buffer.rs | 57 +
sgx_tstd/src/net/{ip.rs => ip_addr.rs} | 411 +++---
sgx_tstd/src/net/{ip => ip_addr}/tests.rs | 123 +-
sgx_tstd/src/net/mod.rs | 24 +-
sgx_tstd/src/net/parser.rs | 158 +-
sgx_tstd/src/net/{addr.rs => socket_addr.rs} | 265 ++--
sgx_tstd/src/net/{addr => socket_addr}/tests.rs | 102 +-
sgx_tstd/src/net/tcp.rs | 15 +-
sgx_tstd/src/net/tcp/tests.rs | 11 +-
sgx_tstd/src/net/udp.rs | 14 +-
sgx_tstd/src/net/udp/tests.rs | 6 +-
sgx_tstd/src/num/benches.rs | 2 +-
sgx_tstd/src/os/fd/mod.rs | 14 +-
sgx_tstd/src/os/fd/owned.rs | 130 +-
sgx_tstd/src/os/fd/raw.rs | 87 +-
sgx_tstd/src/os/fd/tests.rs | 60 +
sgx_tstd/src/os/linux/fs.rs | 26 +-
sgx_tstd/src/os/linux/mod.rs | 2 +
sgx_tstd/src/os/{unix/io/raw.rs => linux/net.rs} | 4 +-
sgx_tstd/src/os/linux/raw.rs | 4 +-
sgx_tstd/src/os/mod.rs | 4 +-
sgx_tstd/src/os/{unix/io/fd.rs => net/mod.rs} | 7 +-
sgx_tstd/src/os/net/tcp.rs | 82 ++
sgx_tstd/src/{ffi/c_str => os/net}/tests.rs | 45 +-
sgx_tstd/src/os/raw/mod.rs | 92 +-
sgx_tstd/src/{sys/os_str => os/raw}/tests.rs | 19 +-
sgx_tstd/src/os/unix/fs.rs | 4 +-
sgx_tstd/src/os/unix/io/mod.rs | 72 +-
sgx_tstd/src/os/unix/io/{fd => }/tests.rs | 0
sgx_tstd/src/os/unix/net/addr.rs | 37 +-
sgx_tstd/src/os/unix/net/ancillary.rs | 16 +-
sgx_tstd/src/os/unix/net/datagram.rs | 46 +-
sgx_tstd/src/os/unix/net/listener.rs | 10 +-
sgx_tstd/src/os/unix/net/stream.rs | 34 +-
sgx_tstd/src/os/unix/net/tests.rs | 13 +-
sgx_tstd/src/os/unix/process.rs | 69 +-
sgx_tstd/src/panicking.rs | 183 ++-
sgx_tstd/src/path.rs | 76 +-
sgx_tstd/src/path/tests.rs | 44 +-
sgx_tstd/src/{io/prelude.rs => personality.rs} | 19 +-
.../src => sgx_tstd/src/personality}/dwarf/eh.rs | 32 +-
.../src => sgx_tstd/src/personality}/dwarf/mod.rs | 22 +-
.../{sys_common/net => personality/dwarf}/tests.rs | 28 +-
.../src => sgx_tstd/src/personality}/gcc.rs | 87 +-
sgx_tstd/src/prelude/mod.rs | 11 +
sgx_tstd/src/process.rs | 285 ++--
sgx_tstd/src/sync/condvar.rs | 3 +-
sgx_tstd/src/sync/lazy_lock.rs | 129 ++
sgx_tstd/src/sync/lazy_lock/tests.rs | 162 ++
sgx_tstd/src/sync/mod.rs | 8 +-
sgx_tstd/src/sync/mpsc/blocking.rs | 13 +-
sgx_tstd/src/sync/mpsc/mod.rs | 20 +-
sgx_tstd/src/sync/mpsc/mpsc_queue/tests.rs | 4 +-
sgx_tstd/src/sync/mpsc/oneshot.rs | 24 +-
sgx_tstd/src/sync/mpsc/shared.rs | 33 +-
sgx_tstd/src/sync/mpsc/spsc_queue/tests.rs | 9 +-
sgx_tstd/src/sync/mpsc/stream.rs | 31 +-
sgx_tstd/src/sync/mpsc/sync.rs | 1 +
sgx_tstd/src/sync/mpsc/sync_tests.rs | 29 +-
sgx_tstd/src/sync/mpsc/tests.rs | 24 +-
sgx_tstd/src/sync/mutex.rs | 57 +-
sgx_tstd/src/sync/mutex/tests.rs | 4 +-
sgx_tstd/src/sync/once.rs | 302 +---
sgx_tstd/src/{lazy.rs => sync/once_lock.rs} | 377 ++---
sgx_tstd/src/{lazy => sync/once_lock}/tests.rs | 167 +--
sgx_tstd/src/sync/poison.rs | 17 +-
sgx_tstd/src/sync/rwlock.rs | 139 +-
sgx_tstd/src/sync/rwlock/tests.rs | 4 +-
sgx_tstd/src/sys/args.rs | 4 +-
sgx_tstd/src/sys/backtrace/mod.rs | 8 +-
sgx_tstd/src/sys/cmath.rs | 3 +
.../src/{os/unix/io/raw.rs => sys/common/mod.rs} | 5 +-
sgx_tstd/src/sys/common/small_c_string.rs | 70 +
sgx_tstd/src/sys/common/tests.rs | 86 ++
sgx_tstd/src/sys/fd.rs | 23 +-
sgx_tstd/src/sys/fs.rs | 223 +--
sgx_tstd/src/sys/futex.rs | 41 +-
sgx_tstd/src/sys/io.rs | 18 +-
sgx_tstd/src/sys/kernel_copy.rs | 2 +-
sgx_tstd/src/sys/kernel_copy/tests.rs | 19 +-
sgx_tstd/src/sys/mod.rs | 1 +
sgx_tstd/src/sys/net.rs | 24 +-
sgx_tstd/src/sys/os.rs | 35 +-
sgx_tstd/src/sys/os_str.rs | 40 +-
sgx_tstd/src/sys/os_str/tests.rs | 10 +-
sgx_tstd/src/sys/path.rs | 3 +-
.../src/{sys_common/thread.rs => sys/process.rs} | 4 +-
sgx_tstd/src/sys/rand.rs | 18 +-
sgx_tstd/src/sys/stdio.rs | 46 +-
sgx_tstd/src/sys/thread.rs | 9 +-
sgx_tstd/src/sys/thread_local_key.rs | 5 -
sgx_tstd/src/sys/time.rs | 203 ++-
sgx_tstd/src/sys/unsupported/mod.rs | 2 -
sgx_tstd/src/sys/unsupported/process.rs | 68 +-
sgx_tstd/src/sys_common/backtrace.rs | 11 +-
sgx_tstd/src/sys_common/gnu/libbacktrace.rs | 2 +-
sgx_tstd/src/sys_common/mod.rs | 1 +
sgx_tstd/src/sys_common/net.rs | 107 +-
sgx_tstd/src/sys_common/net/tests.rs | 2 +-
sgx_tstd/src/sys_common/once/futex.rs | 151 ++
sgx_tstd/src/sys_common/once/generic.rs | 298 ++++
sgx_tstd/src/sys_common/once/mod.rs | 46 +
sgx_tstd/src/sys_common/remutex/tests.rs | 33 +-
sgx_tstd/src/sys_common/thread.rs | 1 -
sgx_tstd/src/sys_common/thread_local_dtor.rs | 2 +-
sgx_tstd/src/sys_common/thread_local_key.rs | 28 +-
sgx_tstd/src/sys_common/thread_local_key/tests.rs | 9 +-
sgx_tstd/src/sys_common/thread_parker/futex.rs | 29 +-
sgx_tstd/src/sys_common/thread_parker/generic.rs | 27 +-
sgx_tstd/src/sys_common/wtf8.rs | 102 +-
sgx_tstd/src/sys_common/wtf8/tests.rs | 296 +++-
sgx_tstd/src/thread/local.rs | 495 ++++++-
sgx_tstd/src/thread/local/tests.rs | 2 +-
sgx_tstd/src/thread/mod.rs | 394 ++++-
sgx_tstd/src/thread/scoped.rs | 94 +-
sgx_tstd/src/thread/tests.rs | 78 +-
sgx_tstd/src/time.rs | 39 +-
sgx_tstd/src/time/tests.rs | 8 +-
sgx_tstd/src/untrusted/time.rs | 10 +-
sgx_types/src/error/mod.rs | 8 +
sgx_types/src/lib.rs | 1 +
sgx_types/src/types/tdx.rs | 2 +-
sgx_unwind/src/lib.rs | 1 -
sgx_unwind/src/libunwind.rs | 4 +-
sgx_urts/src/enclave/mod.rs | 6 +-
sgx_urts/src/ocall/fd.rs | 17 +-
269 files changed, 8774 insertions(+), 7189 deletions(-)
diff --git a/rust-toolchain b/rust-toolchain
index 480e8aa7..cd5e8eb2 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2022-02-23
+nightly-2022-10-22
diff --git a/rustlib/panic_abort/src/lib.rs b/rustlib/panic_abort/src/lib.rs
index 36a1fc9f..1902efcf 100644
--- a/rustlib/panic_abort/src/lib.rs
+++ b/rustlib/panic_abort/src/lib.rs
@@ -9,7 +9,6 @@
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
-#![feature(nll)]
#![feature(panic_runtime)]
#![feature(std_internals)]
#![feature(staged_api)]
@@ -62,6 +61,14 @@ pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMe
// binaries, but it should never be called as we don't link in an unwinding
// runtime at all.
pub mod personalities {
- #[rustc_std_internal_symbol]
- pub extern "C" fn rust_eh_personality() {}
+ // In the past this module used to contain stubs for the personality
+ // functions of various platforms, but these where removed when personality
+ // functions were moved to std.
+
+ // This corresponds to the `eh_catch_typeinfo` lang item
+ // that's only used on Emscripten currently.
+ //
+ // Since panics don't generate exceptions and foreign exceptions are
+ // currently UB with -C panic=abort (although this may be subject to
+ // change), any catch_unwind calls will never use this typeinfo.
}
diff --git a/rustlib/panic_unwind/Cargo.toml b/rustlib/panic_unwind/Cargo.toml
index a6a65642..0689089e 100644
--- a/rustlib/panic_unwind/Cargo.toml
+++ b/rustlib/panic_unwind/Cargo.toml
@@ -31,5 +31,4 @@ bench = false
doc = false
[dependencies]
-sgx_types = { path = "../../sgx_types" }
sgx_unwind = { path = "../../sgx_unwind" }
diff --git a/rustlib/panic_unwind/src/gcc.rs b/rustlib/panic_unwind/src/gcc.rs
index c1599373..a539b590 100644
--- a/rustlib/panic_unwind/src/gcc.rs
+++ b/rustlib/panic_unwind/src/gcc.rs
@@ -39,8 +39,6 @@
use alloc::boxed::Box;
use core::any::Any;
-use crate::dwarf::eh::{self, EHAction, EHContext};
-use sgx_types::types::{c_int, uintptr_t};
use sgx_unwind as uw;
#[repr(C)]
@@ -89,79 +87,3 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
// M O Z \0 R U S T -- vendor, language
0x4d4f_5a00_5255_5354
}
-
-// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
-// and TargetLowering::getExceptionSelectorRegister() for each architecture,
-// then mapped to DWARF register numbers via register definition tables
-// (typically <arch>RegisterInfo.td, search for "DwarfRegNum").
-// See also https://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register.
-
-#[cfg(target_arch = "x86")]
-const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
-
-#[cfg(target_arch = "x86_64")]
-const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
-
-// The following code is based on GCC's C and C++ personality routines. For reference, see:
-// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
-// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
-
-unsafe extern "C" fn rust_eh_personality_impl(
- version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context,
-) -> uw::_Unwind_Reason_Code {
- if version != 1 {
- return uw::_URC_FATAL_PHASE1_ERROR;
- }
- let eh_action = match find_eh_action(context) {
- Ok(action) => action,
- Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
- };
- if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
- match eh_action {
- EHAction::None | EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
- EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
- EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
- }
- } else {
- match eh_action {
- EHAction::None => uw::_URC_CONTINUE_UNWIND,
- EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
- uw::_Unwind_SetIP(context, lpad);
- uw::_URC_INSTALL_CONTEXT
- }
- EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
- }
- }
-}
-
-#[lang = "eh_personality"]
-unsafe extern "C" fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context,
-) -> uw::_Unwind_Reason_Code {
- rust_eh_personality_impl(version, actions, exception_class, exception_object, context)
-}
-
-unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
- let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
- let mut ip_before_instr: c_int = 0;
- let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
- let eh_context = EHContext {
- // The return address points 1 byte past the call instruction,
- // which could be in the next IP range in LSDA range table.
- ip: if ip_before_instr != 0 { ip } else { ip - 1 },
- func_start: uw::_Unwind_GetRegionStart(context),
- get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
- get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
- };
- eh::find_eh_action(lsda, &eh_context)
-}
diff --git a/rustlib/panic_unwind/src/lib.rs b/rustlib/panic_unwind/src/lib.rs
index 1f58df13..ea3fdd2b 100644
--- a/rustlib/panic_unwind/src/lib.rs
+++ b/rustlib/panic_unwind/src/lib.rs
@@ -1,14 +1,21 @@
//! Implementation of panics via stack unwinding
//!
//! This crate is an implementation of panics in Rust using "most native" stack
-//! unwinding mechanism of the platform this is being compiled for.
+//! unwinding mechanism of the platform this is being compiled for. This
+//! essentially gets categorized into three buckets currently:
+//!
+//! 1. MSVC targets use SEH in the `seh.rs` file.
+//! 2. Emscripten uses C++ exceptions in the `emcc.rs` file.
+//! 3. All other targets use libunwind/libgcc in the `gcc.rs` file.
+//!
+//! More documentation about each implementation can be found in the respective
+//! module.
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
#![feature(core_intrinsics)]
#![feature(lang_items)]
-#![feature(nll)]
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(std_internals)]
@@ -19,7 +26,6 @@
#![feature(c_unwind)]
extern crate alloc;
-extern crate sgx_types;
extern crate sgx_unwind;
use alloc::boxed::Box;
@@ -38,8 +44,6 @@ extern "C" {
fn __rust_foreign_exception() -> !;
}
-mod dwarf;
-
/// # Safety
#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
@@ -51,7 +55,7 @@ pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any
// Entry point for raising an exception, just delegates to the platform-specific
// implementation.
#[rustc_std_internal_symbol]
-pub unsafe extern "C-unwind" fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
+pub unsafe fn __rust_start_panic(payload: *mut &mut dyn BoxMeUp) -> u32 {
let payload = Box::from_raw((*payload).take_box());
imp::panic(payload)
diff --git a/samplecode/hyper-rustls-https-server/enclave/src/lib.rs b/samplecode/hyper-rustls-https-server/enclave/src/lib.rs
index 7815a800..66ae597c 100644
--- a/samplecode/hyper-rustls-https-server/enclave/src/lib.rs
+++ b/samplecode/hyper-rustls-https-server/enclave/src/lib.rs
@@ -46,11 +46,11 @@ pub extern "C" fn run_server() -> SgxStatus {
match result {
Ok(Ok(_)) => SgxStatus::Success,
Ok(Err(e)) => {
- println!("Failed to run server: {}", e);
+ println!("Failed to run server: {e}");
SgxStatus::Unexpected
}
Err(e) => {
- println!("Failed to create tokio runtime in enclave: {}", e);
+ println!("Failed to create tokio runtime in enclave: {e}");
SgxStatus::Unexpected
}
}
@@ -88,7 +88,7 @@ async fn run_sample_server() -> Result<(), Box<dyn std::error::Error + Send + Sy
let server = Server::builder(TlsAcceptor::new(tls_cfg, incoming)).serve(service);
// Run the future, keep going until an error occurs.
- println!("Starting to serve on https://{}.", addr);
+ println!("Starting to serve on https://{addr}.");
server.await?;
Ok(())
}
diff --git a/samplecode/rpc/client/enclave/src/lib.rs b/samplecode/rpc/client/enclave/src/lib.rs
index 13a39b56..cd0d9876 100644
--- a/samplecode/rpc/client/enclave/src/lib.rs
+++ b/samplecode/rpc/client/enclave/src/lib.rs
@@ -39,7 +39,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = client.say_hello(request).await?;
- println!("RESPONSE={:?}", response);
+ println!("RESPONSE={response:?}");
Ok(())
}
@@ -56,11 +56,11 @@ pub extern "C" fn run_client() -> SgxStatus {
match result {
Ok(Ok(_)) => SgxStatus::Success,
Ok(Err(e)) => {
- println!("Failed to run client: {}", e);
+ println!("Failed to run client: {e}");
SgxStatus::Unexpected
}
Err(e) => {
- println!("Failed to create tokio runtime in enclave: {}", e);
+ println!("Failed to create tokio runtime in enclave: {e}");
SgxStatus::Unexpected
}
}
@@ -73,7 +73,7 @@ pub extern "C" fn run_client() -> SgxStatus {
//match main() {
// Ok(_) => SgxStatus::Success,
// Err(e) => {
- // println!("Failed to run client: {}", e);
+ // println!("Failed to run client: {e}");
// SgxStatus::Unexpected
// }
//}
diff --git a/samplecode/rpc/server/enclave/src/lib.rs b/samplecode/rpc/server/enclave/src/lib.rs
index 22e5bb0d..27fd42ac 100644
--- a/samplecode/rpc/server/enclave/src/lib.rs
+++ b/samplecode/rpc/server/enclave/src/lib.rs
@@ -37,7 +37,7 @@ impl Greeter for MyGreeter {
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
- println!("Got a request: {:?}", request);
+ println!("Got a request: {request:?}");
let reply = hello_world::HelloReply {
message: format!("Hello {}!", request.into_inner().name).into(),
@@ -54,7 +54,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let addr = "[::1]:50051".parse().unwrap();
let greeter = MyGreeter::default();
- println!("GreeterServer listening on {}", addr);
+ println!("GreeterServer listening on {addr}");
Server::builder()
.add_service(GreeterServer::new(greeter))
@@ -76,11 +76,11 @@ pub extern "C" fn run_server() -> SgxStatus {
match result {
Ok(Ok(_)) => SgxStatus::Success,
Ok(Err(e)) => {
- println!("Failed to run server: {}", e);
+ println!("Failed to run server: {e}");
SgxStatus::Unexpected
}
Err(e) => {
- println!("Failed to create tokio runtime in enclave: {}", e);
+ println!("Failed to create tokio runtime in enclave: {e}");
SgxStatus::Unexpected
}
}
@@ -93,7 +93,7 @@ pub extern "C" fn run_server() -> SgxStatus {
//match main() {
// Ok(_) => SgxStatus::Success,
// Err(e) => {
- // println!("Failed to run server: {}", e);
+ // println!("Failed to run server: {e}");
// SgxStatus::Unexpected
// }
//}
diff --git a/samplecode/seal/enclave/src/lib.rs b/samplecode/seal/enclave/src/lib.rs
index d4edd006..95c3f81f 100644
--- a/samplecode/seal/enclave/src/lib.rs
+++ b/samplecode/seal/enclave/src/lib.rs
@@ -59,12 +59,12 @@ pub unsafe extern "C" fn seal_data() -> SgxStatus {
rng.fill_bytes(data.as_mut());
let data = SealData::new(msg, data);
- println!("sealdata: {:?}", data);
+ println!("sealdata: {data:?}");
let sealed_bytes = match seal(data.clone(), aad.clone()) {
Ok(bytes) => bytes,
Err(e) => {
- println!("seal failed. {:?}", e);
+ println!("seal failed. {e:?}");
return e;
}
};
@@ -73,7 +73,7 @@ pub unsafe extern "C" fn seal_data() -> SgxStatus {
let sealed_bytes = match fs::read("sealed_data.txt") {
Ok(bytes) => bytes,
Err(e) => {
- println!("read sealed_data.txt failed. {:?}", e);
+ println!("read sealed_data.txt failed. {e:?}");
return SgxStatus::Unexpected;
}
};
@@ -82,13 +82,13 @@ pub unsafe extern "C" fn seal_data() -> SgxStatus {
let (unsealed_data, unsealed_aad) = match unseal(sealed_bytes) {
Ok(data) => data,
Err(e) => {
- println!("unseal failed. {:?}", e);
+ println!("unseal failed. {e:?}");
return e;
}
};
- println!("unsealed data: {:?}", unsealed_data);
- println!("aad: {:?}", unsealed_aad);
+ println!("unsealed data: {unsealed_data:?}");
+ println!("aad: {unsealed_aad:?}");
assert_eq!(data, unsealed_data);
assert_eq!(aad, unsealed_aad);
diff --git a/samplecode/switchless/app/build.rs b/samplecode/switchless/app/build.rs
index 0565b106..002ffed9 100644
--- a/samplecode/switchless/app/build.rs
+++ b/samplecode/switchless/app/build.rs
@@ -28,7 +28,10 @@ fn main() {
println!("cargo:rustc-link-lib=static=enclave_u");
println!("cargo:rustc-link-search=native={}/lib64", sdk_dir);
- println!("cargo:rustc-link-lib=static=sgx_uswitchless");
+ println!("cargo:rustc-link-arg=-Wl,--whole-archive");
+ println!("cargo:rustc-link-arg=-lsgx_uswitchless");
+ println!("cargo:rustc-link-arg=-Wl,--no-whole-archive");
+
match mode.as_ref() {
"SIM" | "SW" => println!("cargo:rustc-link-lib=dylib=sgx_urts_sim"),
"HYPER" => println!("cargo:rustc-link-lib=dylib=sgx_urts_hyper"),
diff --git a/samplecode/switchless/app/src/main.rs b/samplecode/switchless/app/src/main.rs
index ec344998..2bcad663 100644
--- a/samplecode/switchless/app/src/main.rs
+++ b/samplecode/switchless/app/src/main.rs
@@ -70,15 +70,12 @@ fn benchmark_empty_ocall(eid: EnclaveId, is_switchless: u32) {
_ => "switchless",
};
- println!(
- "Repeating an **{}** OCall that does nothing for {} times...",
- info, REPEATS
- );
+ println!("Repeating an **{info}** OCall that does nothing for {REPEATS} times...");
let start = Instant::now();
let _ = unsafe { ecall_repeat_ocalls(eid, REPEATS, is_switchless) };
let elapsed = start.elapsed();
- println!("Time elapsed {:?}", elapsed);
+ println!("Time elapsed {elapsed:?}");
}
fn benchmark_empty_ecall(eid: EnclaveId, is_switchless: u32) {
@@ -92,15 +89,12 @@ fn benchmark_empty_ecall(eid: EnclaveId, is_switchless: u32) {
_ => ecall_empty_switchless,
};
- println!(
- "Repeating an **{}** ECall that does nothing for {} times...",
- info, REPEATS
- );
+ println!("Repeating an **{info}** ECall that does nothing for {REPEATS} times...");
let start = Instant::now();
for _ in 0..REPEATS {
let _ = unsafe { ecall_fn(eid) };
}
let elapsed = start.elapsed();
- println!("Time elapsed {:?}", elapsed);
+ println!("Time elapsed {elapsed:?}");
}
diff --git a/samplecode/zlib-lazy-static-sample/enclave/src/lib.rs b/samplecode/zlib-lazy-static-sample/enclave/src/lib.rs
index ed4a9407..084ce515 100644
--- a/samplecode/zlib-lazy-static-sample/enclave/src/lib.rs
+++ b/samplecode/zlib-lazy-static-sample/enclave/src/lib.rs
@@ -21,11 +21,11 @@ use inflate::inflate_bytes_zlib;
use libflate::zlib::Encoder;
use sgx_types::error::SgxStatus;
use std::io::Write;
-use std::lazy::SyncLazy;
use std::str::from_utf8;
+use std::sync::LazyLock;
-static HELLOSTR: SyncLazy<String> =
- SyncLazy::new(|| String::from("This is a global rust String init by SyncLazy!"));
+static HELLOSTR: LazyLock<String> =
+ LazyLock::new(|| String::from("This is a global rust String init by LazyLock!"));
/// # Safety
#[no_mangle]
@@ -37,7 +37,7 @@ pub unsafe extern "C" fn zlib_sample() -> SgxStatus {
encoder.write_all(HELLOSTR.as_bytes()).unwrap();
let encoded_data = encoder.finish().into_result().unwrap();
- println!("After zlib compress : {:?}", encoded_data);
+ println!("After zlib compress : {encoded_data:?}");
let decoded = inflate_bytes_zlib(&encoded_data[..]).unwrap();
diff --git a/sgx_alloc/src/alignalloc.rs b/sgx_alloc/src/alignalloc.rs
index 3d3720fc..cc71359e 100644
--- a/sgx_alloc/src/alignalloc.rs
+++ b/sgx_alloc/src/alignalloc.rs
@@ -321,7 +321,7 @@ mod platform {
fn gen_alignmask(al: usize, a: usize, m: u64) -> i64 {
if a > al {
- gen_alignmask(al, (a >> 1) as usize, m | (m >> (a >> 1)))
+ gen_alignmask(al, a >> 1, m | (m >> (a >> 1)))
} else {
m as i64
}
diff --git a/sgx_alloc/src/alignbox.rs b/sgx_alloc/src/alignbox.rs
index fddd42f5..ebdc2c4b 100644
--- a/sgx_alloc/src/alignbox.rs
+++ b/sgx_alloc/src/alignbox.rs
@@ -60,25 +60,25 @@ impl<T> DerefMut for AlignBox<T> {
impl<T> AsRef<T> for AlignBox<T> {
fn as_ref(&self) -> &T {
- &**self
+ self
}
}
impl<T> AsMut<T> for AlignBox<T> {
fn as_mut(&mut self) -> &mut T {
- &mut **self
+ self
}
}
impl<T> borrow::Borrow<T> for AlignBox<T> {
fn borrow(&self) -> &T {
- &**self
+ self
}
}
impl<T> borrow::BorrowMut<T> for AlignBox<T> {
fn borrow_mut(&mut self) -> &mut T {
- &mut **self
+ self
}
}
diff --git a/sgx_backtrace/src/symbolize/libbacktrace.rs b/sgx_backtrace/src/symbolize/libbacktrace.rs
index f5bbdd79..b45d5ee3 100644
--- a/sgx_backtrace/src/symbolize/libbacktrace.rs
+++ b/sgx_backtrace/src/symbolize/libbacktrace.rs
@@ -241,7 +241,7 @@ extern "C" fn syminfo_cb(
let mut symname = symname;
if symname.is_null() {
let sym_address =
- uw::_Unwind_FindEnclosingFunction((pc as usize + 1) as *mut c_void) as usize;
+ uw::_Unwind_FindEnclosingFunction((pc + 1) as *mut c_void) as usize;
if sym_address == MmLayout::entry_address() {
symname = ENCLAVE_ENTRY_NAME as *const _ as *const c_char
}
diff --git a/sgx_build_helper/build_helper/src/lib.rs b/sgx_build_helper/build_helper/src/lib.rs
index 139bbec3..fc265532 100644
--- a/sgx_build_helper/build_helper/src/lib.rs
+++ b/sgx_build_helper/build_helper/src/lib.rs
@@ -176,7 +176,7 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path, filter: &[&str]) {
.read_dir()
.unwrap()
.map(|e| e.unwrap())
- .filter(|e| !is_in_filter_list(&*e.file_name(), filter))
+ .filter(|e| !is_in_filter_list(&e.file_name(), filter))
.collect::<Vec<_>>();
while let Some(entry) = stack.pop() {
let path = entry.path();
@@ -185,7 +185,7 @@ pub fn rerun_if_changed_anything_in_dir(dir: &Path, filter: &[&str]) {
path.read_dir()
.unwrap()
.map(|e| e.unwrap())
- .filter(|e| !is_in_filter_list(&*e.file_name(), filter)),
+ .filter(|e| !is_in_filter_list(&e.file_name(), filter)),
);
} else {
println!("cargo:rerun-if-changed={}", path.display());
diff --git a/sgx_dcap/tkey_exchange/src/session/manager.rs b/sgx_dcap/tkey_exchange/src/session/manager.rs
index 4353fe6d..eccf8243 100644
--- a/sgx_dcap/tkey_exchange/src/session/manager.rs
+++ b/sgx_dcap/tkey_exchange/src/session/manager.rs
@@ -22,7 +22,7 @@ use core::ops::Deref;
use core::ptr;
use core::sync::atomic::{AtomicU32, Ordering};
use sgx_crypto::ecc::{EcPrivateKey, EcPublicKey, EcShareKey};
-use sgx_sync::{SpinMutex, SpinRwLock, SyncLazy};
+use sgx_sync::{LazyLock, SpinMutex, SpinRwLock};
use sgx_types::types::{AlignKey128bit, EnclaveIdentity, QlQvResult, QuoteNonce, TargetInfo};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -168,11 +168,11 @@ impl Session {
}
}
-pub static INITIATOR_SESSION_MAGAGER: SyncLazy<SpinRwLock<SessionManager>> =
- SyncLazy::new(|| SpinRwLock::new(SessionManager::new()));
+pub static INITIATOR_SESSION_MAGAGER: LazyLock<SpinRwLock<SessionManager>> =
+ LazyLock::new(|| SpinRwLock::new(SessionManager::new()));
-pub static RESPONDER_SESSION_MAGAGER: SyncLazy<SpinRwLock<SessionManager>> =
- SyncLazy::new(|| SpinRwLock::new(SessionManager::new()));
+pub static RESPONDER_SESSION_MAGAGER: LazyLock<SpinRwLock<SessionManager>> =
+ LazyLock::new(|| SpinRwLock::new(SessionManager::new()));
struct Node {
sid: u32,
diff --git a/sgx_dcap/tvl/src/capi.rs b/sgx_dcap/tvl/src/capi.rs
index fc44f545..30b8d08e 100644
--- a/sgx_dcap/tvl/src/capi.rs
+++ b/sgx_dcap/tvl/src/capi.rs
@@ -16,12 +16,12 @@
// under the License..
use crate::QveReportInfo;
+use core::ptr;
use core::slice;
use sgx_types::error::Quote3Error;
use sgx_types::types::time_t;
use sgx_types::types::{QlQeReportInfo, QlQvResult};
-#[allow(unaligned_references)]
/// # Safety
#[no_mangle]
pub unsafe extern "C" fn sgx_tvl_verify_qve_report_and_identity(
@@ -58,7 +58,7 @@ pub unsafe extern "C" fn sgx_tvl_verify_qve_report_and_identity(
let qve_report_info = &*qve_report_info;
let qve_report_info = QveReportInfo {
- qve_report: &qve_report_info.qe_report,
+ qve_report: &*ptr::addr_of!(qve_report_info.qe_report),
expiration_time: expiration_check_date,
collateral_expiration_status,
quote_verification_result,
diff --git a/sgx_demangle/src/legacy.rs b/sgx_demangle/src/legacy.rs
index 7a1667d2..5f05d2a9 100644
--- a/sgx_demangle/src/legacy.rs
+++ b/sgx_demangle/src/legacy.rs
@@ -92,7 +92,7 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> {
let mut c = chars.next().ok_or(())?;
while c != 'E' {
// Decode an identifier element's length.
- if !c.is_digit(10) {
+ if !c.is_ascii_digit() {
return Err(());
}
let mut len = 0usize;
@@ -118,7 +118,7 @@ pub fn demangle(s: &str) -> Result<(Demangle, &str), ()> {
// Rust hashes are hex digits with an `h` prepended.
fn is_rust_hash(s: &str) -> bool {
- s.starts_with('h') && s[1..].chars().all(|c| c.is_digit(16))
+ s.starts_with('h') && s[1..].chars().all(|c| c.is_ascii_hexdigit())
}
impl<'a> fmt::Display for Demangle<'a> {
@@ -127,7 +127,7 @@ impl<'a> fmt::Display for Demangle<'a> {
let mut inner = self.inner;
for element in 0..self.elements {
let mut rest = inner;
- while rest.chars().next().unwrap().is_digit(10) {
+ while rest.chars().next().unwrap().is_ascii_digit() {
rest = &rest[1..];
}
let i: usize = inner[..(inner.len() - rest.len())].parse().unwrap();
diff --git a/sgx_edl/edl/sgx_fd.edl b/sgx_edl/edl/sgx_fd.edl
index cb1f3187..141753e7 100644
--- a/sgx_edl/edl/sgx_fd.edl
+++ b/sgx_edl/edl/sgx_fd.edl
@@ -17,6 +17,7 @@
enclave {
include "inc/stat.h"
+ include "time.h"
from "sgx_mem.edl" import *;
from "sgx_msbuf.edl" import *;
@@ -42,5 +43,7 @@ enclave {
int u_isatty_ocall([out] int *error, int fd);
int u_dup_ocall([out] int *error, int oldfd);
int u_eventfd_ocall([out] int *error, unsigned int initval, int flags);
+
+ int u_futimens_ocall([out] int *error, int fd, [in, count=2] const struct timespec *times);
};
};
diff --git a/sgx_ffi/src/c_str.rs b/sgx_ffi/src/c_str.rs
index 55ef9083..7c9b0f77 100644
--- a/sgx_ffi/src/c_str.rs
+++ b/sgx_ffi/src/c_str.rs
@@ -15,1549 +15,5 @@
// specific language governing permissions and limitations
// under the License..
-#[cfg(feature = "unit_test")]
-mod tests;
-
-use crate::ascii;
-use crate::memchr;
-use alloc::borrow::{Borrow, Cow, ToOwned};
-use alloc::boxed::Box;
-use alloc::rc::Rc;
-use alloc::slice;
-use alloc::str::{self, Utf8Error};
-use alloc::string::String;
-use alloc::sync::Arc;
-use alloc::vec::Vec;
-use core::cmp::Ordering;
-use core::fmt::{self, Write};
-use core::mem;
-use core::num::NonZeroU8;
-use core::ops;
-use core::ptr;
-use sgx_types::types::c_char;
-
-/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
-/// middle.
-///
-/// This type serves the purpose of being able to safely generate a
-/// C-compatible string from a Rust byte slice or vector. An instance of this
-/// type is a static guarantee that the underlying bytes contain no interior 0
-/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
-///
-/// `CString` is to <code>&[CStr]</code> as [`String`] is to <code>&[str]</code>: the former
-/// in each pair are owned strings; the latter are borrowed
-/// references.
-///
-/// # Creating a `CString`
-///
-/// A `CString` is created from either a byte slice or a byte vector,
-/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
-/// example, you can build a `CString` straight out of a [`String`] or
-/// a <code>&[str]</code>, since both implement that trait).
-///
-/// The [`CString::new`] method will actually check that the provided <code>&[[u8]]</code>
-/// does not have 0 bytes in the middle, and return an error if it
-/// finds one.
-///
-/// # Extracting a raw pointer to the whole C string
-///
-/// `CString` implements an [`as_ptr`][`CStr::as_ptr`] method through the [`Deref`]
-/// trait. This method will give you a `*const c_char` which you can
-/// feed directly to extern functions that expect a nul-terminated
-/// string, like C's `strdup()`. Notice that [`as_ptr`][`CStr::as_ptr`] returns a
-/// read-only pointer; if the C code writes to it, that causes
-/// undefined behavior.
-///
-/// # Extracting a slice of the whole C string
-///
-/// Alternatively, you can obtain a <code>&[[u8]]</code> slice from a
-/// `CString` with the [`CString::as_bytes`] method. Slices produced in this
-/// way do *not* contain the trailing nul terminator. This is useful
-/// when you will be calling an extern function that takes a `*const
-/// u8` argument which is not necessarily nul-terminated, plus another
-/// argument with the length of the string — like C's `strndup()`.
-/// You can of course get the slice's length with its
-/// [`len`][slice::len] method.
-///
-/// If you need a <code>&[[u8]]</code> slice *with* the nul terminator, you
-/// can use [`CString::as_bytes_with_nul`] instead.
-///
-/// Once you have the kind of slice you need (with or without a nul
-/// terminator), you can call the slice's own
-/// [`as_ptr`][slice::as_ptr] method to get a read-only raw pointer to pass to
-/// extern functions. See the documentation for that function for a
-/// discussion on ensuring the lifetime of the raw pointer.
-///
-/// [str]: prim@str "str"
-/// [`Deref`]: ops::Deref
-///
-/// # Examples
-///
-/// ```ignore (extern-declaration)
-/// # fn main() {
-/// use std::ffi::CString;
-/// use std::os::raw::c_char;
-///
-/// extern "C" {
-/// fn my_printer(s: *const c_char);
-/// }
-///
-/// // We are certain that our string doesn't have 0 bytes in the middle,
-/// // so we can .expect()
-/// let c_to_print = CString::new("Hello, world!").expect("CString::new failed");
-/// unsafe {
-/// my_printer(c_to_print.as_ptr());
-/// }
-/// # }
-/// ```
-///
-/// # Safety
-///
-/// `CString` is intended for working with traditional C-style strings
-/// (a sequence of non-nul bytes terminated by a single nul byte); the
-/// primary use case for these kinds of strings is interoperating with C-like
-/// code. Often you will need to transfer ownership to/from that external
-/// code. It is strongly recommended that you thoroughly read through the
-/// documentation of `CString` before use, as improper ownership management
-/// of `CString` instances can lead to invalid memory accesses, memory leaks,
-/// and other memory errors.
-#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")]
-pub struct CString {
- // Invariant 1: the slice ends with a zero byte and has a length of at least one.
- // Invariant 2: the slice contains only one zero byte.
- // Improper usage of unsafe function can break Invariant 2, but not Invariant 1.
- inner: Box<[u8]>,
-}
-
-/// Representation of a borrowed C string.
-///
-/// This type represents a borrowed reference to a nul-terminated
-/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
-/// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
-/// into an owned [`CString`].
-///
-/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
-/// in each pair are borrowed references; the latter are owned
-/// strings.
-///
-/// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
-/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
-/// a safe interface to other consumers.
-///
-/// # Examples
-///
-/// Inspecting a foreign C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// unsafe {
-/// let slice = CStr::from_ptr(my_string());
-/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
-/// }
-/// ```
-///
-/// Passing a Rust-originating C string:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::{CString, CStr};
-/// use std::os::raw::c_char;
-///
-/// fn work(data: &CStr) {
-/// extern "C" { fn work_with(data: *const c_char); }
-///
-/// unsafe { work_with(data.as_ptr()) }
-/// }
-///
-/// let s = CString::new("data data data data").expect("CString::new failed");
-/// work(&s);
-/// ```
-///
-/// Converting a foreign C string into a Rust [`String`]:
-///
-/// ```ignore (extern-declaration)
-/// use std::ffi::CStr;
-/// use std::os::raw::c_char;
-///
-/// extern "C" { fn my_string() -> *const c_char; }
-///
-/// fn my_string_safe() -> String {
-/// unsafe {
-/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
-/// }
-/// }
-///
-/// println!("string: {}", my_string_safe());
-/// ```
-///
-/// [str]: prim@str "str"
-#[derive(Hash)]
-#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
-// FIXME:
-// `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
-// on `CStr` being layout-compatible with `[u8]`.
-// When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`.
-// Anyway, `CStr` representation and layout are considered implementation detail, are
-// not documented and must not be relied upon.
-pub struct CStr {
- // FIXME: this should not be represented with a DST slice but rather with
- // just a raw `c_char` along with some form of marker to make
- // this an unsized type. Essentially `sizeof(&CStr)` should be the
- // same as `sizeof(&c_char)` but `CStr` should be an unsized type.
- inner: [c_char],
-}
-
-/// An error indicating that an interior nul byte was found.
-///
-/// While Rust strings may contain nul bytes in the middle, C strings
-/// can't, as that byte would effectively truncate the string.
-///
-/// This error is created by the [`new`][`CString::new`] method on
-/// [`CString`]. See its documentation for more.
-///
-/// # Examples
-///
-/// ```
-/// use std::ffi::{CString, NulError};
-///
-/// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err();
-/// ```
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct NulError(usize, Vec<u8>);
-
-impl fmt::Display for NulError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "nul byte found in provided data at position: {}", self.0)
- }
-}
-
-/// An error indicating that a nul byte was not in the expected position.
-///
-/// The slice used to create a [`CStr`] must have one and only one nul byte,
-/// positioned at the end.
-///
-/// This error is created by the [`CStr::from_bytes_with_nul`] method.
-/// See its documentation for more.
-///
-/// # Examples
-///
-/// ```
-/// use std::ffi::{CStr, FromBytesWithNulError};
-///
-/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
-/// ```
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FromBytesWithNulError {
- kind: FromBytesWithNulErrorKind,
-}
-
-impl fmt::Display for FromBytesWithNulError {
- #[allow(deprecated, deprecated_in_future)]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(self.__description())?;
- if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
- write!(f, " at byte pos {}", pos)?;
- }
- Ok(())
- }
-}
-
-impl FromBytesWithNulError {
- fn interior_nul(pos: usize) -> FromBytesWithNulError {
- FromBytesWithNulError {
- kind: FromBytesWithNulErrorKind::InteriorNul(pos),
- }
- }
-
- fn not_nul_terminated() -> FromBytesWithNulError {
- FromBytesWithNulError {
- kind: FromBytesWithNulErrorKind::NotNulTerminated,
- }
- }
-
- pub fn __description(&self) -> &str {
- match self.kind {
- FromBytesWithNulErrorKind::InteriorNul(..) => {
- "data provided contains an interior nul byte"
- }
- FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
- }
- }
-}
-
-/// An error indicating that a nul byte was not in the expected position.
-///
-/// The vector used to create a [`CString`] must have one and only one nul byte,
-/// positioned at the end.
-///
-/// This error is created by the [`CString::from_vec_with_nul`] method.
-/// See its documentation for more.
-///
-/// # Examples
-///
-/// ```
-/// use std::ffi::{CString, FromVecWithNulError};
-///
-/// let _: FromVecWithNulError = CString::from_vec_with_nul(b"f\0oo".to_vec()).unwrap_err();
-/// ```
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct FromVecWithNulError {
- error_kind: FromBytesWithNulErrorKind,
- bytes: Vec<u8>,
-}
-
-impl fmt::Display for FromVecWithNulError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.error_kind {
- FromBytesWithNulErrorKind::InteriorNul(pos) => {
- write!(
- f,
- "data provided contains an interior nul byte at pos {}",
- pos
- )
- }
- FromBytesWithNulErrorKind::NotNulTerminated => {
- write!(f, "data provided is not nul terminated")
- }
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum FromBytesWithNulErrorKind {
- InteriorNul(usize),
- NotNulTerminated,
-}
-
-impl FromVecWithNulError {
- /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`CString`].
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// // Some invalid bytes in a vector
- /// let bytes = b"f\0oo".to_vec();
- ///
- /// let value = CString::from_vec_with_nul(bytes.clone());
- ///
- /// assert_eq!(&bytes[..], value.unwrap_err().as_bytes());
- /// ```
- #[must_use]
- pub fn as_bytes(&self) -> &[u8] {
- &self.bytes[..]
- }
-
- /// Returns the bytes that were attempted to convert to a [`CString`].
- ///
- /// This method is carefully constructed to avoid allocation. It will
- /// consume the error, moving out the bytes, so that a copy of the bytes
- /// does not need to be made.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// // Some invalid bytes in a vector
- /// let bytes = b"f\0oo".to_vec();
- ///
- /// let value = CString::from_vec_with_nul(bytes.clone());
- ///
- /// assert_eq!(bytes, value.unwrap_err().into_bytes());
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_bytes(self) -> Vec<u8> {
- self.bytes
- }
-}
-
-/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
-///
-/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
-/// [`CString::into_string`] performs UTF-8 validation on those bytes and may
-/// return this error.
-///
-/// This `struct` is created by [`CString::into_string()`]. See
-/// its documentation for more.
-#[derive(Clone, PartialEq, Eq, Debug)]
-pub struct IntoStringError {
- inner: CString,
- error: Utf8Error,
-}
-
-impl IntoStringError {
- #[allow(deprecated)]
- pub fn __description(&self) -> &str {
- "C string contained non-utf8 bytes"
- }
-
- pub fn __source(&self) -> &Utf8Error {
- &self.error
- }
-}
-
-impl fmt::Display for IntoStringError {
- #[allow(deprecated, deprecated_in_future)]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.__description().fmt(f)
- }
-}
-
-impl CString {
- /// Creates a new C-compatible string from a container of bytes.
- ///
- /// This function will consume the provided data and use the
- /// underlying bytes to construct a new string, ensuring that
- /// there is a trailing 0 byte. This trailing 0 byte will be
- /// appended by this function; the provided data should *not*
- /// contain any 0 bytes in it.
- ///
- /// # Examples
- ///
- /// ```ignore (extern-declaration)
- /// use std::ffi::CString;
- /// use std::os::raw::c_char;
- ///
- /// extern "C" { fn puts(s: *const c_char); }
- ///
- /// let to_print = CString::new("Hello!").expect("CString::new failed");
- /// unsafe {
- /// puts(to_print.as_ptr());
- /// }
- /// ```
- ///
- /// # Errors
- ///
- /// This function will return an error if the supplied bytes contain an
- /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
- /// the position of the nul byte.
- pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
- trait SpecNewImpl {
- fn spec_new_impl(self) -> Result<CString, NulError>;
- }
-
- impl<T: Into<Vec<u8>>> SpecNewImpl for T {
- default fn spec_new_impl(self) -> Result<CString, NulError> {
- let bytes: Vec<u8> = self.into();
- match memchr::memchr(0, &bytes) {
- Some(i) => Err(NulError(i, bytes)),
- None => Ok(unsafe { CString::_from_vec_unchecked(bytes) }),
- }
- }
- }
-
- // Specialization for avoiding reallocation
- #[inline(always)] // Without that it is not inlined into specializations
- fn spec_new_impl_bytes(bytes: &[u8]) -> Result<CString, NulError> {
- // We cannot have such large slice that we would overflow here
- // but using `checked_add` allows LLVM to assume that capacity never overflows
- // and generate twice shorter code.
- // `saturating_add` doesn't help for some reason.
- let capacity = bytes.len().checked_add(1).unwrap();
-
- // Allocate before validation to avoid duplication of allocation code.
- // We still need to allocate and copy memory even if we get an error.
- let mut buffer = Vec::with_capacity(capacity);
- buffer.extend(bytes);
-
- // Check memory of self instead of new buffer.
- // This allows better optimizations if lto enabled.
- match memchr::memchr(0, bytes) {
- Some(i) => Err(NulError(i, buffer)),
- None => Ok(unsafe { CString::_from_vec_unchecked(buffer) }),
- }
- }
-
- impl SpecNewImpl for &'_ [u8] {
- fn spec_new_impl(self) -> Result<CString, NulError> {
- spec_new_impl_bytes(self)
- }
- }
-
- impl SpecNewImpl for &'_ str {
- fn spec_new_impl(self) -> Result<CString, NulError> {
- spec_new_impl_bytes(self.as_bytes())
- }
- }
-
- impl SpecNewImpl for &'_ mut [u8] {
- fn spec_new_impl(self) -> Result<CString, NulError> {
- spec_new_impl_bytes(self)
- }
- }
-
- t.spec_new_impl()
- }
-
- /// Creates a C-compatible string by consuming a byte vector,
- /// without checking for interior 0 bytes.
- ///
- /// Trailing 0 byte will be appended by this function.
- ///
- /// This method is equivalent to [`CString::new`] except that no runtime
- /// assertion is made that `v` contains no 0 bytes, and it requires an
- /// actual byte vector, not anything that can be converted to one with Into.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let raw = b"foo".to_vec();
- /// unsafe {
- /// let c_string = CString::from_vec_unchecked(raw);
- /// }
- /// ```
- #[must_use]
- pub unsafe fn from_vec_unchecked(v: Vec<u8>) -> Self {
- debug_assert!(memchr::memchr(0, &v).is_none());
- Self::_from_vec_unchecked(v)
- }
-
- unsafe fn _from_vec_unchecked(mut v: Vec<u8>) -> Self {
- v.reserve_exact(1);
- v.push(0);
- Self {
- inner: v.into_boxed_slice(),
- }
- }
-
- /// Retakes ownership of a `CString` that was transferred to C via
- /// [`CString::into_raw`].
- ///
- /// Additionally, the length of the string will be recalculated from the pointer.
- ///
- /// # Safety
- ///
- /// This should only ever be called with a pointer that was earlier
- /// obtained by calling [`CString::into_raw`]. Other usage (e.g., trying to take
- /// ownership of a string that was allocated by foreign code) is likely to lead
- /// to undefined behavior or allocator corruption.
- ///
- /// It should be noted that the length isn't just "recomputed," but that
- /// the recomputed length must match the original length from the
- /// [`CString::into_raw`] call. This means the [`CString::into_raw`]/`from_raw`
- /// methods should not be used when passing the string to C functions that can
- /// modify the string's length.
- ///
- /// > **Note:** If you need to borrow a string that was allocated by
- /// > foreign code, use [`CStr`]. If you need to take ownership of
- /// > a string that was allocated by foreign code, you will need to
- /// > make your own provisions for freeing it appropriately, likely
- /// > with the foreign code's API to do that.
- ///
- /// # Examples
- ///
- /// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
- /// ownership with `from_raw`:
- ///
- /// ```ignore (extern-declaration)
- /// use std::ffi::CString;
- /// use std::os::raw::c_char;
- ///
- /// extern "C" {
- /// fn some_extern_function(s: *mut c_char);
- /// }
- ///
- /// let c_string = CString::new("Hello!").expect("CString::new failed");
- /// let raw = c_string.into_raw();
- /// unsafe {
- /// some_extern_function(raw);
- /// let c_string = CString::from_raw(raw);
- /// }
- /// ```
- #[must_use = "call `drop(from_raw(ptr))` if you intend to drop the `CString`"]
- pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
- // SAFETY: This is called with a pointer that was obtained from a call
- // to `CString::into_raw` and the length has not been modified. As such,
- // we know there is a NUL byte (and only one) at the end and that the
- // information about the size of the allocation is correct on Rust's
- // side.
- let len = c::strlen(ptr) + 1; // Including the NUL byte
- let slice = slice::from_raw_parts_mut(ptr, len as usize);
- CString {
- inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]),
- }
- }
-
- /// Consumes the `CString` and transfers ownership of the string to a C caller.
- ///
- /// The pointer which this function returns must be returned to Rust and reconstituted using
- /// [`CString::from_raw`] to be properly deallocated. Specifically, one
- /// should *not* use the standard C `free()` function to deallocate
- /// this string.
- ///
- /// Failure to call [`CString::from_raw`] will lead to a memory leak.
- ///
- /// The C side must **not** modify the length of the string (by writing a
- /// `null` somewhere inside the string or removing the final one) before
- /// it makes it back into Rust using [`CString::from_raw`]. See the safety section
- /// in [`CString::from_raw`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new("foo").expect("CString::new failed");
- ///
- /// let ptr = c_string.into_raw();
- ///
- /// unsafe {
- /// assert_eq!(b'f', *ptr as u8);
- /// assert_eq!(b'o', *ptr.offset(1) as u8);
- /// assert_eq!(b'o', *ptr.offset(2) as u8);
- /// assert_eq!(b'\0', *ptr.offset(3) as u8);
- ///
- /// // retake pointer to free memory
- /// let _ = CString::from_raw(ptr);
- /// }
- /// ```
- #[inline]
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_raw(self) -> *mut c_char {
- Box::into_raw(self.into_inner()) as *mut c_char
- }
-
- /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
- ///
- /// On failure, ownership of the original `CString` is returned.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let valid_utf8 = vec![b'f', b'o', b'o'];
- /// let cstring = CString::new(valid_utf8).expect("CString::new failed");
- /// assert_eq!(cstring.into_string().expect("into_string() call failed"), "foo");
- ///
- /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
- /// let cstring = CString::new(invalid_utf8).expect("CString::new failed");
- /// let err = cstring.into_string().err().expect("into_string().err() failed");
- /// assert_eq!(err.utf8_error().valid_up_to(), 1);
- /// ```
- pub fn into_string(self) -> Result<String, IntoStringError> {
- String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError {
- error: e.utf8_error(),
- inner: unsafe { Self::_from_vec_unchecked(e.into_bytes()) },
- })
- }
-
- /// Consumes the `CString` and returns the underlying byte buffer.
- ///
- /// The returned buffer does **not** contain the trailing nul
- /// terminator, and it is guaranteed to not have any interior nul
- /// bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new("foo").expect("CString::new failed");
- /// let bytes = c_string.into_bytes();
- /// assert_eq!(bytes, vec![b'f', b'o', b'o']);
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_bytes(self) -> Vec<u8> {
- let mut vec = self.into_inner().into_vec();
- let _nul = vec.pop();
- debug_assert_eq!(_nul, Some(0u8));
- vec
- }
-
- /// Equivalent to [`CString::into_bytes()`] except that the
- /// returned vector includes the trailing nul terminator.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new("foo").expect("CString::new failed");
- /// let bytes = c_string.into_bytes_with_nul();
- /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_bytes_with_nul(self) -> Vec<u8> {
- self.into_inner().into_vec()
- }
-
- /// Returns the contents of this `CString` as a slice of bytes.
- ///
- /// The returned slice does **not** contain the trailing nul
- /// terminator, and it is guaranteed to not have any interior nul
- /// bytes. If you need the nul terminator, use
- /// [`CString::as_bytes_with_nul`] instead.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new("foo").expect("CString::new failed");
- /// let bytes = c_string.as_bytes();
- /// assert_eq!(bytes, &[b'f', b'o', b'o']);
- /// ```
- #[inline]
- #[must_use]
- pub fn as_bytes(&self) -> &[u8] {
- // SAFETY: CString has a length at least 1
- unsafe { self.inner.get_unchecked(..self.inner.len() - 1) }
- }
-
- /// Equivalent to [`CString::as_bytes()`] except that the
- /// returned slice includes the trailing nul terminator.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new("foo").expect("CString::new failed");
- /// let bytes = c_string.as_bytes_with_nul();
- /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
- /// ```
- #[inline]
- #[must_use]
- pub fn as_bytes_with_nul(&self) -> &[u8] {
- &self.inner
- }
-
- /// Extracts a [`CStr`] slice containing the entire string.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::{CString, CStr};
- ///
- /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
- /// let cstr = c_string.as_c_str();
- /// assert_eq!(cstr,
- /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
- /// ```
- #[inline]
- #[must_use]
- pub fn as_c_str(&self) -> &CStr {
- &*self
- }
-
- /// Converts this `CString` into a boxed [`CStr`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::{CString, CStr};
- ///
- /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
- /// let boxed = c_string.into_boxed_c_str();
- /// assert_eq!(&*boxed,
- /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_boxed_c_str(self) -> Box<CStr> {
- unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
- }
-
- /// Bypass "move out of struct which implements [`Drop`] trait" restriction.
- #[inline]
- fn into_inner(self) -> Box<[u8]> {
- // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
- // so we use `ManuallyDrop` to ensure `self` is not dropped.
- // Then we can return the box directly without invalidating it.
- // See https://github.com/rust-lang/rust/issues/62553.
- let this = mem::ManuallyDrop::new(self);
- unsafe { ptr::read(&this.inner) }
- }
-
- /// Converts a <code>[Vec]<[u8]></code> to a [`CString`] without checking the
- /// invariants on the given [`Vec`].
- ///
- /// # Safety
- ///
- /// The given [`Vec`] **must** have one nul byte as its last element.
- /// This means it cannot be empty nor have any other nul byte anywhere else.
- ///
- /// # Example
- ///
- /// ```
- /// use std::ffi::CString;
- /// assert_eq!(
- /// unsafe { CString::from_vec_with_nul_unchecked(b"abc\0".to_vec()) },
- /// unsafe { CString::from_vec_unchecked(b"abc".to_vec()) }
- /// );
- /// ```
- #[must_use]
- pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
- debug_assert!(memchr::memchr(0, &v).unwrap() + 1 == v.len());
- Self::_from_vec_with_nul_unchecked(v)
- }
-
- unsafe fn _from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
- Self {
- inner: v.into_boxed_slice(),
- }
- }
-
- /// Attempts to converts a <code>[Vec]<[u8]></code> to a [`CString`].
- ///
- /// Runtime checks are present to ensure there is only one nul byte in the
- /// [`Vec`], its last element.
- ///
- /// # Errors
- ///
- /// If a nul byte is present and not the last element or no nul bytes
- /// is present, an error will be returned.
- ///
- /// # Examples
- ///
- /// A successful conversion will produce the same result as [`CString::new`]
- /// when called without the ending nul byte.
- ///
- /// ```
- /// use std::ffi::CString;
- /// assert_eq!(
- /// CString::from_vec_with_nul(b"abc\0".to_vec())
- /// .expect("CString::from_vec_with_nul failed"),
- /// CString::new(b"abc".to_vec()).expect("CString::new failed")
- /// );
- /// ```
- ///
- /// An incorrectly formatted [`Vec`] will produce an error.
- ///
- /// ```
- /// use std::ffi::{CString, FromVecWithNulError};
- /// // Interior nul byte
- /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"a\0bc".to_vec()).unwrap_err();
- /// // No nul byte
- /// let _: FromVecWithNulError = CString::from_vec_with_nul(b"abc".to_vec()).unwrap_err();
- /// ```
- pub fn from_vec_with_nul(v: Vec<u8>) -> Result<Self, FromVecWithNulError> {
- let nul_pos = memchr::memchr(0, &v);
- match nul_pos {
- Some(nul_pos) if nul_pos + 1 == v.len() => {
- // SAFETY: We know there is only one nul byte, at the end
- // of the vec.
- Ok(unsafe { Self::_from_vec_with_nul_unchecked(v) })
- }
- Some(nul_pos) => Err(FromVecWithNulError {
- error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos),
- bytes: v,
- }),
- None => Err(FromVecWithNulError {
- error_kind: FromBytesWithNulErrorKind::NotNulTerminated,
- bytes: v,
- }),
- }
- }
-}
-
-// Turns this `CString` into an empty string to prevent
-// memory-unsafe code from working by accident. Inline
-// to prevent LLVM from optimizing it away in debug builds.
-impl Drop for CString {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- *self.inner.get_unchecked_mut(0) = 0;
- }
- }
-}
-
-impl ops::Deref for CString {
- type Target = CStr;
-
- #[inline]
- fn deref(&self) -> &CStr {
- unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
- }
-}
-
-impl fmt::Debug for CString {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
- }
-}
-
-impl From<CString> for Vec<u8> {
- /// Converts a [`CString`] into a <code>[Vec]<[u8]></code>.
- ///
- /// The conversion consumes the [`CString`], and removes the terminating NUL byte.
- #[inline]
- fn from(s: CString) -> Vec<u8> {
- s.into_bytes()
- }
-}
-
-impl fmt::Debug for CStr {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "\"")?;
- for byte in self
- .to_bytes()
- .iter()
- .flat_map(|&b| ascii::escape_default(b))
- {
- f.write_char(byte as char)?;
- }
- write!(f, "\"")
- }
-}
-
-impl Default for &CStr {
- fn default() -> Self {
- const SLICE: &[c_char] = &[0];
- unsafe { CStr::from_ptr(SLICE.as_ptr()) }
- }
-}
-
-impl Default for CString {
- /// Creates an empty `CString`.
- fn default() -> CString {
- let a: &CStr = Default::default();
- a.to_owned()
- }
-}
-
-impl Borrow<CStr> for CString {
- #[inline]
- fn borrow(&self) -> &CStr {
- self
- }
-}
-
-impl<'a> From<Cow<'a, CStr>> for CString {
- /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are
- /// borrowed.
- #[inline]
- fn from(s: Cow<'a, CStr>) -> Self {
- s.into_owned()
- }
-}
-
-impl From<&CStr> for Box<CStr> {
- /// Converts a `&CStr` into a `Box<CStr>`,
- /// by copying the contents into a newly allocated [`Box`].
- fn from(s: &CStr) -> Box<CStr> {
- let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
- unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
- }
-}
-
-impl From<Cow<'_, CStr>> for Box<CStr> {
- /// Converts a `Cow<'a, CStr>` into a `Box<CStr>`,
- /// by copying the contents if they are borrowed.
- #[inline]
- fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
- match cow {
- Cow::Borrowed(s) => Box::from(s),
- Cow::Owned(s) => Box::from(s),
- }
- }
-}
-
-impl From<Box<CStr>> for CString {
- /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
- #[inline]
- fn from(s: Box<CStr>) -> CString {
- s.into_c_string()
- }
-}
-
-impl From<Vec<NonZeroU8>> for CString {
- /// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without
- /// copying nor checking for inner null bytes.
- #[inline]
- fn from(v: Vec<NonZeroU8>) -> CString {
- unsafe {
- // Transmute `Vec<NonZeroU8>` to `Vec<u8>`.
- let v: Vec<u8> = {
- // SAFETY:
- // - transmuting between `NonZeroU8` and `u8` is sound;
- // - `alloc::Layout<NonZeroU8> == alloc::Layout<u8>`.
- let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
- Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
- };
- // SAFETY: `v` cannot contain null bytes, given the type-level
- // invariant of `NonZeroU8`.
- Self::_from_vec_unchecked(v)
- }
- }
-}
-
-impl Clone for Box<CStr> {
- #[inline]
- fn clone(&self) -> Self {
- (**self).into()
- }
-}
-
-impl From<CString> for Box<CStr> {
- /// Converts a [`CString`] into a <code>[Box]<[CStr]></code> without copying or allocating.
- #[inline]
- fn from(s: CString) -> Box<CStr> {
- s.into_boxed_c_str()
- }
-}
-
-impl<'a> From<CString> for Cow<'a, CStr> {
- /// Converts a [`CString`] into an owned [`Cow`] without copying or allocating.
- #[inline]
- fn from(s: CString) -> Cow<'a, CStr> {
- Cow::Owned(s)
- }
-}
-
-impl<'a> From<&'a CStr> for Cow<'a, CStr> {
- /// Converts a [`CStr`] into a borrowed [`Cow`] without copying or allocating.
- #[inline]
- fn from(s: &'a CStr) -> Cow<'a, CStr> {
- Cow::Borrowed(s)
- }
-}
-
-impl<'a> From<&'a CString> for Cow<'a, CStr> {
- /// Converts a `&`[`CString`] into a borrowed [`Cow`] without copying or allocating.
- #[inline]
- fn from(s: &'a CString) -> Cow<'a, CStr> {
- Cow::Borrowed(s.as_c_str())
- }
-}
-
-impl From<CString> for Arc<CStr> {
- /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> by moving the [`CString`]
- /// data into a new [`Arc`] buffer.
- #[inline]
- fn from(s: CString) -> Arc<CStr> {
- let arc: Arc<[u8]> = Arc::from(s.into_inner());
- unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
- }
-}
-
-impl From<&CStr> for Arc<CStr> {
- /// Converts a `&CStr` into a `Arc<CStr>`,
- /// by copying the contents into a newly allocated [`Arc`].
- #[inline]
- fn from(s: &CStr) -> Arc<CStr> {
- let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
- unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) }
- }
-}
-
-impl From<CString> for Rc<CStr> {
- /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> by moving the [`CString`]
- /// data into a new [`Arc`] buffer.
- #[inline]
- fn from(s: CString) -> Rc<CStr> {
- let rc: Rc<[u8]> = Rc::from(s.into_inner());
- unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
- }
-}
-
-impl From<&CStr> for Rc<CStr> {
- /// Converts a `&CStr` into a `Rc<CStr>`,
- /// by copying the contents into a newly allocated [`Rc`].
- #[inline]
- fn from(s: &CStr) -> Rc<CStr> {
- let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
- unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) }
- }
-}
-
-impl Default for Box<CStr> {
- fn default() -> Box<CStr> {
- let boxed: Box<[u8]> = Box::from([0]);
- unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
- }
-}
-
-impl NulError {
- /// Returns the position of the nul byte in the slice that caused
- /// [`CString::new`] to fail.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let nul_error = CString::new("foo\0bar").unwrap_err();
- /// assert_eq!(nul_error.nul_position(), 3);
- ///
- /// let nul_error = CString::new("foo bar\0").unwrap_err();
- /// assert_eq!(nul_error.nul_position(), 7);
- /// ```
- #[must_use]
- pub fn nul_position(&self) -> usize {
- self.0
- }
-
- /// Consumes this error, returning the underlying vector of bytes which
- /// generated the error in the first place.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let nul_error = CString::new("foo\0bar").unwrap_err();
- /// assert_eq!(nul_error.into_vec(), b"foo\0bar");
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_vec(self) -> Vec<u8> {
- self.1
- }
-}
-
-impl IntoStringError {
- /// Consumes this error, returning original [`CString`] which generated the
- /// error.
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_cstring(self) -> CString {
- self.inner
- }
-
- /// Access the underlying UTF-8 error that was the cause of this error.
- #[must_use]
- pub fn utf8_error(&self) -> Utf8Error {
- self.error
- }
-}
-
-impl CStr {
- /// Wraps a raw C string with a safe C string wrapper.
- ///
- /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
- /// allows inspection and interoperation of non-owned C strings. The total
- /// size of the raw C string must be smaller than `isize::MAX` **bytes**
- /// in memory due to calling the `slice::from_raw_parts` function.
- /// This method is unsafe for a number of reasons:
- ///
- /// * There is no guarantee to the validity of `ptr`.
- /// * The returned lifetime is not guaranteed to be the actual lifetime of
- /// `ptr`.
- /// * There is no guarantee that the memory pointed to by `ptr` contains a
- /// valid nul terminator byte at the end of the string.
- /// * It is not guaranteed that the memory pointed by `ptr` won't change
- /// before the `CStr` has been destroyed.
- ///
- /// > **Note**: This operation is intended to be a 0-cost cast but it is
- /// > currently implemented with an up-front calculation of the length of
- /// > the string. This is not guaranteed to always be the case.
- ///
- /// # Examples
- ///
- /// ```ignore (extern-declaration)
- /// # fn main() {
- /// use std::ffi::CStr;
- /// use std::os::raw::c_char;
- ///
- /// extern "C" {
- /// fn my_string() -> *const c_char;
- /// }
- ///
- /// unsafe {
- /// let slice = CStr::from_ptr(my_string());
- /// println!("string returned: {}", slice.to_str().unwrap());
- /// }
- /// # }
- /// ```
- #[inline]
- #[must_use]
- pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
- // SAFETY: The caller has provided a pointer that points to a valid C
- // string with a NUL terminator of size less than `isize::MAX`, whose
- // content remain valid and doesn't change for the lifetime of the
- // returned `CStr`.
- //
- // Thus computing the length is fine (a NUL byte exists), the call to
- // from_raw_parts is safe because we know the length is at most `isize::MAX`, meaning
- // the call to `from_bytes_with_nul_unchecked` is correct.
- //
- // The cast from c_char to u8 is ok because a c_char is always one byte.
- let len = c::strlen(ptr);
- let ptr = ptr as *const u8;
- Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
- }
-
- /// Creates a C string wrapper from a byte slice.
- ///
- /// This function will cast the provided `bytes` to a `CStr`
- /// wrapper after ensuring that the byte slice is nul-terminated
- /// and does not contain any interior nul bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"hello\0");
- /// assert!(cstr.is_ok());
- /// ```
- ///
- /// Creating a `CStr` without a trailing nul terminator is an error:
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"hello");
- /// assert!(cstr.is_err());
- /// ```
- ///
- /// Creating a `CStr` with an interior nul byte is an error:
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
- /// assert!(cstr.is_err());
- /// ```
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
- let nul_pos = memchr::memchr(0, bytes);
- match nul_pos {
- Some(nul_pos) if nul_pos + 1 == bytes.len() => {
- // SAFETY: We know there is only one nul byte, at the end
- // of the byte slice.
- Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) })
- }
- Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
- None => Err(FromBytesWithNulError::not_nul_terminated()),
- }
- }
-
- /// Unsafely creates a C string wrapper from a byte slice.
- ///
- /// This function will cast the provided `bytes` to a `CStr` wrapper without
- /// performing any sanity checks. The provided slice **must** be nul-terminated
- /// and not contain any interior nul bytes.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::{CStr, CString};
- ///
- /// unsafe {
- /// let cstring = CString::new("hello").expect("CString::new failed");
- /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
- /// assert_eq!(cstr, &*cstring);
- /// }
- /// ```
- #[inline]
- #[must_use]
- pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- // We're in a const fn, so this is the best we can do
- debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
- Self::_from_bytes_with_nul_unchecked(bytes)
- }
-
- #[inline]
- const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
- // SAFETY: Casting to CStr is safe because its internal representation
- // is a [u8] too (safe only inside std).
- // Dereferencing the obtained pointer is safe because it comes from a
- // reference. Making a reference is then safe because its lifetime
- // is bound by the lifetime of the given `bytes`.
- &*(bytes as *const [u8] as *const Self)
- }
-
- /// Returns the inner pointer to this C string.
- ///
- /// The returned pointer will be valid for as long as `self` is, and points
- /// to a contiguous region of memory terminated with a 0 byte to represent
- /// the end of the string.
- ///
- /// **WARNING**
- ///
- /// The returned pointer is read-only; writing to it (including passing it
- /// to C code that writes to it) causes undefined behavior.
- ///
- /// It is your responsibility to make sure that the underlying memory is not
- /// freed too early. For example, the following code will cause undefined
- /// behavior when `ptr` is used inside the `unsafe` block:
- ///
- /// ```no_run
- /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
- /// use std::ffi::CString;
- ///
- /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
- /// unsafe {
- /// // `ptr` is dangling
- /// *ptr;
- /// }
- /// ```
- ///
- /// This happens because the pointer returned by `as_ptr` does not carry any
- /// lifetime information and the [`CString`] is deallocated immediately after
- /// the `CString::new("Hello").expect("CString::new failed").as_ptr()`
- /// expression is evaluated.
- /// To fix the problem, bind the `CString` to a local variable:
- ///
- /// ```no_run
- /// # #![allow(unused_must_use)]
- /// use std::ffi::CString;
- ///
- /// let hello = CString::new("Hello").expect("CString::new failed");
- /// let ptr = hello.as_ptr();
- /// unsafe {
- /// // `ptr` is valid because `hello` is in scope
- /// *ptr;
- /// }
- /// ```
- ///
- /// This way, the lifetime of the [`CString`] in `hello` encompasses
- /// the lifetime of `ptr` and the `unsafe` block.
- #[inline]
- #[must_use]
- pub const fn as_ptr(&self) -> *const c_char {
- self.inner.as_ptr()
- }
-
- /// Converts this C string to a byte slice.
- ///
- /// The returned slice will **not** contain the trailing nul terminator that this C
- /// string has.
- ///
- /// > **Note**: This method is currently implemented as a constant-time
- /// > cast, but it is planned to alter its definition in the future to
- /// > perform the length calculation whenever this method is called.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_bytes(), b"foo");
- /// ```
- #[inline]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub fn to_bytes(&self) -> &[u8] {
- let bytes = self.to_bytes_with_nul();
- // SAFETY: to_bytes_with_nul returns slice with length at least 1
- unsafe { bytes.get_unchecked(..bytes.len() - 1) }
- }
-
- /// Converts this C string to a byte slice containing the trailing 0 byte.
- ///
- /// This function is the equivalent of [`CStr::to_bytes`] except that it
- /// will retain the trailing nul terminator instead of chopping it off.
- ///
- /// > **Note**: This method is currently implemented as a 0-cost cast, but
- /// > it is planned to alter its definition in the future to perform the
- /// > length calculation whenever this method is called.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
- /// ```
- #[inline]
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub fn to_bytes_with_nul(&self) -> &[u8] {
- unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
- }
-
- /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
- ///
- /// If the contents of the `CStr` are valid UTF-8 data, this
- /// function will return the corresponding <code>&[str]</code> slice. Otherwise,
- /// it will return an error with details of where UTF-8 validation failed.
- ///
- /// [str]: prim@str "str"
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_str(), Ok("foo"));
- /// ```
- pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
- // N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
- // instead of in `from_ptr()`, it may be worth considering if this should
- // be rewritten to do the UTF-8 check inline with the length calculation
- // instead of doing it afterwards.
- str::from_utf8(self.to_bytes())
- }
-
- /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
- ///
- /// If the contents of the `CStr` are valid UTF-8 data, this
- /// function will return a <code>[Cow]::[Borrowed]\(&[str])</code>
- /// with the corresponding <code>&[str]</code> slice. Otherwise, it will
- /// replace any invalid UTF-8 sequences with
- /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
- /// <code>[Cow]::[Owned]\(&[str])</code> with the result.
- ///
- /// [str]: prim@str "str"
- /// [Borrowed]: Cow::Borrowed
- /// [Owned]: Cow::Owned
- /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
- ///
- /// # Examples
- ///
- /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
- ///
- /// ```
- /// use std::borrow::Cow;
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
- /// .expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
- /// ```
- ///
- /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
- ///
- /// ```
- /// use std::borrow::Cow;
- /// use std::ffi::CStr;
- ///
- /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
- /// .expect("CStr::from_bytes_with_nul failed");
- /// assert_eq!(
- /// cstr.to_string_lossy(),
- /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
- /// );
- /// ```
- #[must_use = "this returns the result of the operation, \
- without modifying the original"]
- pub fn to_string_lossy(&self) -> Cow<'_, str> {
- String::from_utf8_lossy(self.to_bytes())
- }
-
- /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::ffi::CString;
- ///
- /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
- /// let boxed = c_string.into_boxed_c_str();
- /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
- /// ```
- #[must_use = "`self` will be dropped if the result is not used"]
- pub fn into_c_string(self: Box<CStr>) -> CString {
- let raw = Box::into_raw(self) as *mut [u8];
- CString {
- inner: unsafe { Box::from_raw(raw) },
- }
- }
-}
-
-impl PartialEq for CStr {
- fn eq(&self, other: &CStr) -> bool {
- self.to_bytes().eq(other.to_bytes())
- }
-}
-
-impl Eq for CStr {}
-
-impl PartialOrd for CStr {
- fn partial_cmp(&self, other: &CStr) -> Option<Ordering> {
- self.to_bytes().partial_cmp(other.to_bytes())
- }
-}
-
-impl Ord for CStr {
- fn cmp(&self, other: &CStr) -> Ordering {
- self.to_bytes().cmp(other.to_bytes())
- }
-}
-
-impl ToOwned for CStr {
- type Owned = CString;
-
- fn to_owned(&self) -> CString {
- CString {
- inner: self.to_bytes_with_nul().into(),
- }
- }
-
- fn clone_into(&self, target: &mut CString) {
- let mut b = Vec::from(mem::take(&mut target.inner));
- self.to_bytes_with_nul().clone_into(&mut b);
- target.inner = b.into_boxed_slice();
- }
-}
-
-impl From<&CStr> for CString {
- /// Copies the contents of the `&CStr` into a newly allocated `CString`.
- fn from(s: &CStr) -> CString {
- s.to_owned()
- }
-}
-
-impl ops::Index<ops::RangeFull> for CString {
- type Output = CStr;
-
- #[inline]
- fn index(&self, _index: ops::RangeFull) -> &CStr {
- self
- }
-}
-
-impl ops::Index<ops::RangeFrom<usize>> for CStr {
- type Output = CStr;
-
- fn index(&self, index: ops::RangeFrom<usize>) -> &CStr {
- let bytes = self.to_bytes_with_nul();
- // we need to manually check the starting index to account for the null
- // byte, since otherwise we could get an empty string that doesn't end
- // in a null.
- if index.start < bytes.len() {
- unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) }
- } else {
- panic!(
- "index out of bounds: the len is {} but the index is {}",
- bytes.len(),
- index.start
- );
- }
- }
-}
-
-impl AsRef<CStr> for CStr {
- #[inline]
- fn as_ref(&self) -> &CStr {
- self
- }
-}
-
-impl AsRef<CStr> for CString {
- #[inline]
- fn as_ref(&self) -> &CStr {
- self
- }
-}
-
-mod c {
- /// # Safety
- pub unsafe fn strlen(s: *const i8) -> usize {
- let mut result = 0;
- let mut p = s;
- while *p != 0 {
- p = p.offset(1);
- result += 1;
- }
- result
- }
-}
+pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
+pub use core::ffi::{CStr, FromBytesWithNulError};
diff --git a/sgx_ffi/src/c_str/tests.rs b/sgx_ffi/src/c_str/tests.rs
deleted file mode 100644
index 74098856..00000000
--- a/sgx_ffi/src/c_str/tests.rs
+++ /dev/null
@@ -1,200 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License..
-
-use super::*;
-use alloc::borrow::Cow::{Borrowed, Owned};
-use alloc::rc::Rc;
-use alloc::sync::Arc;
-use sgx_types::types::c_char;
-
-use sgx_test_utils::test_case;
-
-#[test_case]
-fn c_to_rust() {
- let data = b"123\0";
- let ptr = data.as_ptr() as *const c_char;
- unsafe {
- assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
- assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
- }
-}
-
-#[test_case]
-fn simple() {
- let s = CString::new("1234").unwrap();
- assert_eq!(s.as_bytes(), b"1234");
- assert_eq!(s.as_bytes_with_nul(), b"1234\0");
-}
-
-#[test_case]
-fn build_with_zero1() {
- assert!(CString::new(&b"\0"[..]).is_err());
-}
-
-#[test_case]
-fn build_with_zero2() {
- assert!(CString::new(vec![0]).is_err());
-}
-
-#[test_case]
-fn formatted() {
- let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
- assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
-}
-
-#[test_case]
-fn borrowed() {
- unsafe {
- let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
- assert_eq!(s.to_bytes(), b"12");
- assert_eq!(s.to_bytes_with_nul(), b"12\0");
- }
-}
-
-#[test_case]
-fn to_str() {
- let data = b"123\xE2\x80\xA6\0";
- let ptr = data.as_ptr() as *const c_char;
- unsafe {
- assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
- assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
- }
- let data = b"123\xE2\0";
- let ptr = data.as_ptr() as *const c_char;
- unsafe {
- assert!(CStr::from_ptr(ptr).to_str().is_err());
- assert_eq!(
- CStr::from_ptr(ptr).to_string_lossy(),
- Owned::<str>(format!("123\u{FFFD}"))
- );
- }
-}
-
-#[test_case]
-fn to_owned() {
- let data = b"123\0";
- let ptr = data.as_ptr() as *const c_char;
-
- let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
- assert_eq!(owned.as_bytes_with_nul(), data);
-}
-
-#[test_case]
-fn from_bytes_with_nul() {
- let data = b"123\0";
- let cstr = CStr::from_bytes_with_nul(data);
- assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..]));
- let cstr = CStr::from_bytes_with_nul(data);
- assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..]));
-
- unsafe {
- let cstr = CStr::from_bytes_with_nul(data);
- let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
- assert_eq!(cstr, Ok(cstr_unchecked));
- }
-}
-
-#[test_case]
-fn from_bytes_with_nul_unterminated() {
- let data = b"123";
- let cstr = CStr::from_bytes_with_nul(data);
- assert!(cstr.is_err());
-}
-
-#[test_case]
-fn from_bytes_with_nul_interior() {
- let data = b"1\023\0";
- let cstr = CStr::from_bytes_with_nul(data);
- assert!(cstr.is_err());
-}
-
-#[test_case]
-fn into_boxed() {
- let orig: &[u8] = b"Hello, world!\0";
- let cstr = CStr::from_bytes_with_nul(orig).unwrap();
- let boxed: Box<CStr> = Box::from(cstr);
- let cstring = cstr.to_owned().into_boxed_c_str().into_c_string();
- assert_eq!(cstr, &*boxed);
- assert_eq!(&*boxed, &*cstring);
- assert_eq!(&*cstring, cstr);
-}
-
-#[test_case]
-fn boxed_default() {
- let boxed = <Box<CStr>>::default();
- assert_eq!(boxed.to_bytes_with_nul(), &[0]);
-}
-
-#[test_case]
-fn test_c_str_clone_into() {
- let mut c_string = CString::new("lorem").unwrap();
- let c_ptr = c_string.as_ptr();
- let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap();
- c_str.clone_into(&mut c_string);
- assert_eq!(c_str, c_string.as_c_str());
- // The exact same size shouldn't have needed to move its allocation
- assert_eq!(c_ptr, c_string.as_ptr());
-}
-
-#[test_case]
-fn into_rc() {
- let orig: &[u8] = b"Hello, world!\0";
- let cstr = CStr::from_bytes_with_nul(orig).unwrap();
- let rc: Rc<CStr> = Rc::from(cstr);
- let arc: Arc<CStr> = Arc::from(cstr);
-
- assert_eq!(&*rc, cstr);
- assert_eq!(&*arc, cstr);
-
- let rc2: Rc<CStr> = Rc::from(cstr.to_owned());
- let arc2: Arc<CStr> = Arc::from(cstr.to_owned());
-
- assert_eq!(&*rc2, cstr);
- assert_eq!(&*arc2, cstr);
-}
-
-#[test_case]
-fn cstr_const_constructor() {
- const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") };
-
- assert_eq!(CSTR.to_str().unwrap(), "Hello, world!");
-}
-
-#[test_case]
-fn cstr_index_from() {
- let original = b"Hello, world!\0";
- let cstr = CStr::from_bytes_with_nul(original).unwrap();
- let result = CStr::from_bytes_with_nul(&original[7..]).unwrap();
-
- assert_eq!(&cstr[7..], result);
-}
-
-#[test_case]
-fn c_string_from_empty_string() {
- let original = "";
- let cstring = CString::new(original).unwrap();
- assert_eq!(original.as_bytes(), cstring.as_bytes());
- assert_eq!([b'\0'], cstring.as_bytes_with_nul());
-}
-
-#[test_case]
-fn c_str_from_empty_string() {
- let original = b"\0";
- let cstr = CStr::from_bytes_with_nul(original).unwrap();
- assert_eq!([] as [u8; 0], cstr.to_bytes());
- assert_eq!([b'\0'], cstr.to_bytes_with_nul());
-}
diff --git a/sgx_ffi/src/lib.rs b/sgx_ffi/src/lib.rs
index d141f7aa..fd8d5dc1 100644
--- a/sgx_ffi/src/lib.rs
+++ b/sgx_ffi/src/lib.rs
@@ -17,19 +17,8 @@
#![no_std]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
-#![allow(clippy::derive_hash_xor_eq)]
-#![allow(clippy::missing_safety_doc)]
-#![allow(incomplete_features)]
-#![feature(rustc_attrs)]
-#![feature(specialization)]
-#![feature(toowned_clone_into)]
-#![feature(vec_into_raw_parts)]
-#![cfg_attr(feature = "unit_test", allow(clippy::useless_format))]
-#[allow(unused_imports)]
-#[macro_use]
extern crate alloc;
-
extern crate sgx_types;
pub mod ascii;
diff --git a/sgx_key_exchange/message/src/message.rs b/sgx_key_exchange/message/src/message.rs
index 231e36e9..20959cd3 100644
--- a/sgx_key_exchange/message/src/message.rs
+++ b/sgx_key_exchange/message/src/message.rs
@@ -199,7 +199,7 @@ impl RaMsg2 {
raw_msg.kdf_id = self.kdf_id;
raw_msg.sign_gb_ga = self.sign_gb_ga.into();
raw_msg.mac = self.mac;
- raw_msg.sig_rl_size = raw_len - header_len as u32;
+ raw_msg.sig_rl_size = raw_len - header_len;
if let Some(sig_rl) = self.sig_rl.as_ref() {
bytes[header_len as usize..].copy_from_slice(sig_rl);
}
@@ -219,7 +219,7 @@ impl RaMsg2 {
raw_msg.kdf_id = self.kdf_id;
raw_msg.sign_gb_ga = self.sign_gb_ga.into();
raw_msg.mac = self.mac;
- raw_msg.sig_rl_size = raw_len - header_len as u32;
+ raw_msg.sig_rl_size = raw_len - header_len;
if let Some(sig_rl) = self.sig_rl.as_ref() {
bytes[header_len as usize..].copy_from_slice(sig_rl);
}
diff --git a/sgx_key_exchange/tkey_exchange/src/session/manager.rs b/sgx_key_exchange/tkey_exchange/src/session/manager.rs
index 468230b9..2ada71a9 100644
--- a/sgx_key_exchange/tkey_exchange/src/session/manager.rs
+++ b/sgx_key_exchange/tkey_exchange/src/session/manager.rs
@@ -23,7 +23,7 @@ use core::ops::Deref;
use core::ptr;
use core::sync::atomic::{AtomicU32, Ordering};
use sgx_crypto::ecc::{EcPrivateKey, EcPublicKey, EcShareKey};
-use sgx_sync::{SpinMutex, SpinRwLock, SyncLazy};
+use sgx_sync::{LazyLock, SpinMutex, SpinRwLock};
use sgx_types::error::SgxResult;
use sgx_types::types::{AlignKey128bit, Ec256SharedKey, PsSecPropDesc, QuoteNonce, TargetInfo};
@@ -119,8 +119,8 @@ impl Session {
}
}
-pub static SESSION_MAGAGER: SyncLazy<SpinRwLock<SessionManager>> =
- SyncLazy::new(|| SpinRwLock::new(SessionManager::new()));
+pub static SESSION_MAGAGER: LazyLock<SpinRwLock<SessionManager>> =
+ LazyLock::new(|| SpinRwLock::new(SessionManager::new()));
struct Node {
sid: u32,
diff --git a/sgx_key_exchange/ukey_exchange/src/capi.rs b/sgx_key_exchange/ukey_exchange/src/capi.rs
index 09fbef36..76b8cd9a 100644
--- a/sgx_key_exchange/ukey_exchange/src/capi.rs
+++ b/sgx_key_exchange/ukey_exchange/src/capi.rs
@@ -22,12 +22,12 @@ use sgx_types::types::{
AttKeyId, CRaMsg1, CRaMsg2, CRaMsg3, ECallGetGaFn, ECallGetMsg3Fn, ECallProcessMsg2Fn,
EnclaveId, RaContext,
};
-use std::lazy::SyncLazy;
use std::mem::ManuallyDrop;
use std::slice;
+use std::sync::LazyLock;
use std::sync::Mutex;
-static INITIATOR: SyncLazy<Mutex<Initiator>> = SyncLazy::new(|| Mutex::new(Initiator::new(0, 0)));
+static INITIATOR: LazyLock<Mutex<Initiator>> = LazyLock::new(|| Mutex::new(Initiator::new(0, 0)));
/// # Safety
#[no_mangle]
diff --git a/sgx_key_exchange/ukey_exchange/src/session.rs b/sgx_key_exchange/ukey_exchange/src/session.rs
index 66fac032..97cec698 100644
--- a/sgx_key_exchange/ukey_exchange/src/session.rs
+++ b/sgx_key_exchange/ukey_exchange/src/session.rs
@@ -187,7 +187,7 @@ impl Initiator {
&report as *const _,
att_key_id as *const _,
&mut qe_report_info as *mut _,
- (&mut c_msg3.quote).as_mut_ptr().cast(),
+ (c_msg3.quote).as_mut_ptr().cast(),
quote_size,
);
ensure!(status.is_success(), status);
@@ -203,7 +203,7 @@ impl Initiator {
sig_rl,
sig_rl_len,
&mut qe_report as *mut _,
- (&mut c_msg3.quote).as_mut_ptr().cast(),
+ (c_msg3.quote).as_mut_ptr().cast(),
quote_size,
);
ensure!(status.is_success(), status);
diff --git a/sgx_libc/Cargo.toml b/sgx_libc/Cargo.toml
index 78c1209d..a737a21e 100644
--- a/sgx_libc/Cargo.toml
+++ b/sgx_libc/Cargo.toml
@@ -32,7 +32,7 @@ crate-type = ["rlib"]
[features]
default = ["panic_on_unsupported_syscall"]
extra_traits = ["sgx_oc/extra_traits"]
-pthread = ["sgx_trts/thread"]
+pthread = ["sgx_trts/thread", "sgx_sync/capi"]
panic_on_unsupported_syscall = []
[target.'cfg(not(target_vendor = "teaclave"))'.dependencies]
diff --git a/sgx_libc/sgx_tlibc_sys/src/lib.rs b/sgx_libc/sgx_tlibc_sys/src/lib.rs
index f9a7d91e..04bce752 100644
--- a/sgx_libc/sgx_tlibc_sys/src/lib.rs
+++ b/sgx_libc/sgx_tlibc_sys/src/lib.rs
@@ -161,6 +161,7 @@ mod bindings {
#[cfg_attr(target_os = "linux", link_name = "__errno_location")]
pub fn errno_location() -> *mut c_int;
+ pub fn strerror(errnum: c_int) -> *const c_char;
pub fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int;
}
}
diff --git a/sgx_libc/src/linux/ocall/fd.rs b/sgx_libc/src/linux/ocall/fd.rs
index 140ac744..3ab67ba0 100644
--- a/sgx_libc/src/linux/ocall/fd.rs
+++ b/sgx_libc/src/linux/ocall/fd.rs
@@ -347,11 +347,7 @@ pub unsafe extern "C" fn close(fd: c_int) -> c_int {
#[no_mangle]
pub unsafe extern "C" fn isatty(fd: c_int) -> c_int {
- if ocall::isatty(fd).is_ok() {
- 1
- } else {
- 0
- }
+ i32::from(ocall::isatty(fd).is_ok())
}
#[no_mangle]
@@ -371,3 +367,17 @@ pub unsafe extern "C" fn eventfd(initval: c_uint, flags: c_int) -> c_int {
-1
}
}
+
+#[no_mangle]
+pub unsafe extern "C" fn futimens(fd: c_int, times: *const [timespec; 2]) -> c_int {
+ if times.is_null() {
+ set_errno(EINVAL);
+ return -1;
+ }
+
+ if ocall::futimens(fd, &*times).is_ok() {
+ 0
+ } else {
+ -1
+ }
+}
diff --git a/sgx_libc/src/linux/ocall/sync.rs b/sgx_libc/src/linux/ocall/sync.rs
index 7e3a1682..a05707a3 100644
--- a/sgx_libc/src/linux/ocall/sync.rs
+++ b/sgx_libc/src/linux/ocall/sync.rs
@@ -18,7 +18,7 @@
use crate::linux::*;
use core::convert::TryFrom;
use core::mem;
-use core::sync::atomic::AtomicI32;
+use core::sync::atomic::AtomicU32;
use core::time::Duration;
use sgx_sync::{Futex, FutexFlags, FutexOp, Timespec};
use sgx_trts::trts::is_within_enclave;
@@ -50,11 +50,11 @@ unsafe fn futex_inernal(
uaddr2: *const u32,
val3: u32,
) -> OsResult<isize> {
- let get_addr = |addr: *const u32| -> OsResult<&AtomicI32> {
+ let get_addr = |addr: *const u32| -> OsResult<&AtomicU32> {
if addr.is_null() || !is_within_enclave(addr as *const u8, mem::size_of::<c_int>()) {
Err(EINVAL)
} else {
- Ok(&*(addr as *const AtomicI32))
+ Ok(&*(addr as *const AtomicU32))
}
};
@@ -83,11 +83,11 @@ unsafe fn futex_inernal(
Some(t) => Duration::try_from(t).map(Some),
None => Ok(None),
})?;
- futex.wait(val as i32, timeout).map(|_| 0)
+ futex.wait(val, timeout).map(|_| 0)
}
FutexOp::WaitBitset => {
let timeout = get_timeout(timeout)?.map(|ts| (ts, flags.into()));
- futex.wait_bitset(val as i32, timeout, val3).map(|_| 0)
+ futex.wait_bitset(val, timeout, val3).map(|_| 0)
}
FutexOp::Wake => {
let count = get_val(val)?;
@@ -110,7 +110,7 @@ unsafe fn futex_inernal(
let nwakes = get_val(val)?;
let nrequeues = get_val(timeout as u32)?;
futex
- .cmp_requeue(nwakes, &new_futex, nrequeues, val3 as i32)
+ .cmp_requeue(nwakes, &new_futex, nrequeues, val3)
.map(|total| total as isize)
}
_ => {
diff --git a/sgx_libc/src/linux/pthread/mod.rs b/sgx_libc/src/linux/pthread/mod.rs
index 00f1abe2..4d1412a5 100644
--- a/sgx_libc/src/linux/pthread/mod.rs
+++ b/sgx_libc/src/linux/pthread/mod.rs
@@ -123,11 +123,7 @@ pub unsafe extern "C" fn pthread_self() -> pthread_t {
#[no_mangle]
pub unsafe extern "C" fn pthread_equal(t1: pthread_t, t2: pthread_t) -> c_int {
- if t1 == t2 {
- 1
- } else {
- 0
- }
+ i32::from(t1 == t2)
}
#[no_mangle]
diff --git a/sgx_oc/src/lib.rs b/sgx_oc/src/lib.rs
index 17743fff..58ec7c98 100644
--- a/sgx_oc/src/lib.rs
+++ b/sgx_oc/src/lib.rs
@@ -18,6 +18,7 @@
#![no_std]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
#![feature(allocator_api)]
+#![feature(error_in_core)]
#![feature(const_extern_fn)]
#![feature(negative_impls)]
#![feature(nonnull_slice_from_raw_parts)]
diff --git a/sgx_oc/src/linux/edl/fd.rs b/sgx_oc/src/linux/edl/fd.rs
index 45b9ee7d..77a1b30c 100644
--- a/sgx_oc/src/linux/edl/fd.rs
+++ b/sgx_oc/src/linux/edl/fd.rs
@@ -112,4 +112,10 @@ extern "C" {
initval: c_uint,
flags: c_int,
) -> sgx_status_t;
+ pub fn u_futimens_ocall(
+ result: *mut c_int,
+ errno: *mut c_int,
+ fd: c_int,
+ times: *const [timespec; 2],
+ ) -> sgx_status_t;
}
diff --git a/sgx_oc/src/linux/mod.rs b/sgx_oc/src/linux/mod.rs
index ca831660..1e0736ef 100644
--- a/sgx_oc/src/linux/mod.rs
+++ b/sgx_oc/src/linux/mod.rs
@@ -110,7 +110,7 @@ f! {
}
pub fn CMSG_FIRSTHDR(mhdr: *const msghdr) -> *mut cmsghdr {
- if (*mhdr).msg_controllen as usize >= mem::size_of::<cmsghdr>() {
+ if (*mhdr).msg_controllen >= mem::size_of::<cmsghdr>() {
(*mhdr).msg_control as *mut cmsghdr
} else {
core::ptr::null_mut::<cmsghdr>()
@@ -130,13 +130,13 @@ f! {
}
pub fn CMSG_NXTHDR(mhdr: *const msghdr, cmsg: *const cmsghdr) -> *mut cmsghdr {
- if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
+ if ((*cmsg).cmsg_len) < mem::size_of::<cmsghdr>() {
return core::ptr::null_mut::<cmsghdr>();
};
- let next = (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len as usize)) as *mut cmsghdr;
- let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen as usize;
+ let next = (cmsg as usize + CMSG_ALIGN((*cmsg).cmsg_len)) as *mut cmsghdr;
+ let max = (*mhdr).msg_control as usize + (*mhdr).msg_controllen;
if (next.offset(1)) as usize > max
- || next as usize + CMSG_ALIGN((*next).cmsg_len as usize) > max
+ || next as usize + CMSG_ALIGN((*next).cmsg_len) > max
{
core::ptr::null_mut::<cmsghdr>()
} else {
@@ -255,7 +255,7 @@ unsafe fn __sigdelset(set: *mut sigset_t, sig: c_int) {
unsafe fn __sigismember(set: *const sigset_t, sig: c_int) -> c_int {
let mask: u64 = __sigmask(sig);
let word: u64 = __sigword(sig);
- let val = if mask != 0 { 1 } else { 0 };
+ let val = u64::from(mask != 0);
((*set).__val[word as usize] & val) as c_int
}
diff --git a/sgx_oc/src/linux/ocall/env.rs b/sgx_oc/src/linux/ocall/env.rs
index 590407c1..87257552 100644
--- a/sgx_oc/src/linux/ocall/env.rs
+++ b/sgx_oc/src/linux/ocall/env.rs
@@ -46,7 +46,7 @@ pub unsafe fn getgid() -> OCallResult<gid_t> {
pub unsafe fn getcwd() -> OCallResult<CString> {
let mut result: c_int = 0;
let mut error: c_int = 0;
- let mut buf = Vec::with_capacity(1024);
+ let mut buf = Vec::with_capacity(512);
loop {
let bufsz = buf.capacity();
diff --git a/sgx_oc/src/linux/ocall/fd.rs b/sgx_oc/src/linux/ocall/fd.rs
index 7c620e33..c09049ee 100644
--- a/sgx_oc/src/linux/ocall/fd.rs
+++ b/sgx_oc/src/linux/ocall/fd.rs
@@ -88,7 +88,7 @@ pub unsafe fn readv(fd: c_int, mut iov: Vec<&mut [u8]>) -> OCallResult<size_t> {
let mut total_size: usize = 0;
for s in iov.iter() {
- check_enclave_buffer(*s)?;
+ check_enclave_buffer(s)?;
total_size = total_size
.checked_add(s.len())
.ok_or_else(|| OCallError::from_custom_error("Overflow"))?;
@@ -155,7 +155,7 @@ pub unsafe fn preadv64(fd: c_int, mut iov: Vec<&mut [u8]>, offset: off64_t) -> O
let mut total_size: usize = 0;
for s in iov.iter() {
- check_enclave_buffer(*s)?;
+ check_enclave_buffer(s)?;
total_size = total_size
.checked_add(s.len())
.ok_or_else(|| OCallError::from_custom_error("Overflow"))?;
@@ -276,7 +276,7 @@ pub unsafe fn writev(fd: c_int, iov: Vec<&[u8]>) -> OCallResult<size_t> {
let mut total_size: usize = 0;
for s in iov.iter() {
- check_enclave_buffer(*s)?;
+ check_enclave_buffer(s)?;
total_size = total_size
.checked_add(s.len())
.ok_or_else(|| OCallError::from_custom_error("Overflow"))?;
@@ -328,7 +328,7 @@ pub unsafe fn pwritev64(fd: c_int, iov: Vec<&[u8]>, offset: off64_t) -> OCallRes
let mut total_size: usize = 0;
for s in iov.iter() {
- check_enclave_buffer(*s)?;
+ check_enclave_buffer(s)?;
total_size = total_size
.checked_add(s.len())
.ok_or_else(|| OCallError::from_custom_error("Overflow"))?;
@@ -608,3 +608,20 @@ pub unsafe fn eventfd(initval: c_uint, flags: c_int) -> OCallResult<c_int> {
Ok(result)
}
+
+pub unsafe fn futimens(fd: c_int, times: &[timespec; 2]) -> OCallResult<c_int> {
+ let mut result: c_int = 0;
+ let mut error: c_int = 0;
+
+ let status = u_futimens_ocall(
+ &mut result as *mut c_int,
+ &mut error as *mut c_int,
+ fd,
+ times as *const [timespec; 2],
+ );
+
+ ensure!(status.is_success(), esgx!(status));
+ ensure!(result >= 0, eos!(error));
+
+ Ok(result)
+}
diff --git a/sgx_oc/src/linux/ocall/mem.rs b/sgx_oc/src/linux/ocall/mem.rs
index 84f409aa..dee68f2c 100644
--- a/sgx_oc/src/linux/ocall/mem.rs
+++ b/sgx_oc/src/linux/ocall/mem.rs
@@ -84,13 +84,13 @@ impl Drop for HeapBuffer {
impl AsRef<[u8]> for HeapBuffer {
fn as_ref(&self) -> &[u8] {
- &**self
+ self
}
}
impl AsMut<[u8]> for HeapBuffer {
fn as_mut(&mut self) -> &mut [u8] {
- &mut **self
+ self
}
}
@@ -132,7 +132,7 @@ unsafe impl Allocator for HostAlloc {
#[inline]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
if layout.size() != 0 && is_within_host(ptr.as_ptr(), layout.size()) {
- let _ = self.host_free(ptr);
+ self.host_free(ptr);
}
}
}
@@ -153,7 +153,7 @@ impl HostAlloc {
&mut error as *mut c_int,
size,
layout.align(),
- if zeroed { 1 } else { 0 },
+ i32::from(zeroed),
)
} else {
u_malloc_ocall(
diff --git a/sgx_oc/src/linux/ocall/mod.rs b/sgx_oc/src/linux/ocall/mod.rs
index f77fd035..bfa37a13 100644
--- a/sgx_oc/src/linux/ocall/mod.rs
+++ b/sgx_oc/src/linux/ocall/mod.rs
@@ -21,6 +21,7 @@ use alloc::str;
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::From;
+use core::error::Error;
use core::fmt;
use core::num::NonZeroUsize;
use core::ptr;
@@ -77,7 +78,7 @@ impl OCallError {
}
impl OCallError {
- pub fn description(&self) -> String {
+ pub fn error_description(&self) -> String {
match self {
Self::SgxError(status) => sgx_error_string(*status),
Self::OsError(errno) => os_error_string(*errno),
@@ -110,6 +111,28 @@ impl From<&'static str> for OCallError {
}
}
+impl Error for OCallError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ match self {
+ OCallError::SgxError(s) => s.description(),
+ OCallError::OsError(code) => os_error_str(*code),
+ OCallError::GaiError(code) => gai_error_str(*code),
+ OCallError::CustomError(s) => s,
+ }
+ }
+
+ #[allow(deprecated)]
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ OCallError::SgxError(ref s) => Some(s),
+ OCallError::OsError(..) => None,
+ OCallError::GaiError(..) => None,
+ OCallError::CustomError(..) => None,
+ }
+ }
+}
+
pub type OCallResult<T> = Result<T, OCallError>;
pub fn gai_error_cstr(errno: i32) -> &'static CStr {
@@ -161,6 +184,18 @@ pub fn gai_error_str(errno: i32) -> &'static str {
}
}
+pub fn os_error_str(errno: i32) -> &'static str {
+ extern "C" {
+ pub fn strerror(errnum: c_int) -> *const c_char;
+ }
+
+ unsafe {
+ let p = strerror(errno);
+ assert!(!p.is_null(), "strerror failure");
+ str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap()
+ }
+}
+
pub fn os_error_string(errno: i32) -> String {
const TMPBUF_SZ: usize = 128;
extern "C" {
diff --git a/sgx_oc/src/linux/ocall/socket.rs b/sgx_oc/src/linux/ocall/socket.rs
index 5a1c672f..5f9d23f7 100644
--- a/sgx_oc/src/linux/ocall/socket.rs
+++ b/sgx_oc/src/linux/ocall/socket.rs
@@ -468,7 +468,7 @@ impl SockAddr {
len as usize >= core::mem::size_of::<sockaddr_in>(),
ecust!("Malformed addr_len")
);
- let sockaddr: *const sockaddr_in = core::mem::transmute(addr);
+ let sockaddr: *const sockaddr_in = addr as *const _ as *const sockaddr_in;
Ok(SockAddr::from(*sockaddr))
}
AF_INET6 => {
@@ -476,11 +476,11 @@ impl SockAddr {
len as usize >= core::mem::size_of::<sockaddr_in6>(),
ecust!("Malformed addr_len")
);
- let sockaddr: *const sockaddr_in6 = core::mem::transmute(addr);
+ let sockaddr: *const sockaddr_in6 = addr as *const _ as *const sockaddr_in6;
Ok(SockAddr::from(*sockaddr))
}
AF_UNIX => {
- let sockaddr: *const sockaddr_un = core::mem::transmute(addr);
+ let sockaddr: *const sockaddr_un = addr as *const _ as *const sockaddr_un;
SockAddr::try_from_un(*sockaddr, len)
}
_ => {
@@ -499,7 +499,7 @@ impl SockAddr {
len as usize == core::mem::size_of::<sockaddr_in>(),
ecust!("Malformed addr_len")
);
- let sockaddr: *const sockaddr_in = core::mem::transmute(&storage);
+ let sockaddr: *const sockaddr_in = &storage as *const _ as *const sockaddr_in;
Ok(SockAddr::from(*sockaddr))
}
AF_INET6 => {
@@ -507,15 +507,15 @@ impl SockAddr {
len as usize == core::mem::size_of::<sockaddr_in6>(),
ecust!("Malformed addr_len")
);
- let sockaddr: *const sockaddr_in6 = core::mem::transmute(&storage);
+ let sockaddr: *const sockaddr_in6 = &storage as *const _ as *const sockaddr_in6;
Ok(SockAddr::from(*sockaddr))
}
AF_UNIX => {
- let sockaddr: *const sockaddr_un = core::mem::transmute(&storage);
+ let sockaddr: *const sockaddr_un = &storage as *const _ as *const sockaddr_un;
SockAddr::try_from_un(*sockaddr, len)
}
0 if len == 0 => {
- let sockaddr: *const sockaddr_un = core::mem::transmute(&storage);
+ let sockaddr: *const sockaddr_un = &storage as *const _ as *const sockaddr_un;
Ok(SockAddr::UN((*sockaddr, len)))
}
_ => {
diff --git a/sgx_oc/src/linux/ocall/socket_msg.rs b/sgx_oc/src/linux/ocall/socket_msg.rs
index 7ed5a985..9d2f3de2 100644
--- a/sgx_oc/src/linux/ocall/socket_msg.rs
+++ b/sgx_oc/src/linux/ocall/socket_msg.rs
@@ -55,11 +55,8 @@ pub struct MsgHdrMut<'a> {
impl<'a> MsgHdr<'a> {
pub unsafe fn from_raw(c_msg: &msghdr) -> Self {
let name = new_optional_slice(c_msg.msg_name as *const u8, c_msg.msg_namelen as usize);
- let iovs = new_optional_slice(c_msg.msg_iov as *const iovec, c_msg.msg_iovlen as usize);
- let control = new_optional_slice(
- c_msg.msg_control as *const u8,
- c_msg.msg_controllen as usize,
- );
+ let iovs = new_optional_slice(c_msg.msg_iov as *const iovec, c_msg.msg_iovlen);
+ let control = new_optional_slice(c_msg.msg_control as *const u8, c_msg.msg_controllen);
let flags = MsgHdrFlags::from_bits_truncate(c_msg.msg_flags);
let iovs = iovs
.map(|iovs_slice| {
@@ -82,9 +79,8 @@ impl<'a> MsgHdr<'a> {
impl<'a> MsgHdrMut<'a> {
pub unsafe fn from_raw(c_msg: &mut msghdr) -> Self {
let name = new_optional_slice_mut(c_msg.msg_name as *mut u8, c_msg.msg_namelen as usize);
- let iovs = new_optional_slice_mut(c_msg.msg_iov as *mut iovec, c_msg.msg_iovlen as usize);
- let control =
- new_optional_slice_mut(c_msg.msg_control as *mut u8, c_msg.msg_controllen as usize);
+ let iovs = new_optional_slice_mut(c_msg.msg_iov as *mut iovec, c_msg.msg_iovlen);
+ let control = new_optional_slice_mut(c_msg.msg_control as *mut u8, c_msg.msg_controllen);
let flags = MsgHdrFlags::from_bits_truncate(c_msg.msg_flags);
let iovs = iovs
.map(|iovs_slice| {
@@ -238,7 +234,7 @@ pub unsafe fn recvmsg(sockfd: c_int, msg: &mut MsgHdrMut, flags: c_int) -> OCall
let mut total_size: usize = 0;
for s in msg.iovs.iter() {
- check_trusted_enclave_buffer(*s)?;
+ check_trusted_enclave_buffer(s)?;
total_size = total_size
.checked_add(s.len())
.ok_or_else(|| OCallError::from_custom_error("Overflow"))?;
@@ -333,7 +329,7 @@ pub unsafe fn recvmsg(sockfd: c_int, msg: &mut MsgHdrMut, flags: c_int) -> OCall
}
}
- msg.name_len = msg_namelen_out as u32;
+ msg.name_len = msg_namelen_out;
msg.control_len = msg_controllen_out;
msg.flags = msg_flags;
diff --git a/sgx_oc/src/linux/x86_64/mod.rs b/sgx_oc/src/linux/x86_64/mod.rs
index 0c9b8f8f..c7f357c9 100644
--- a/sgx_oc/src/linux/x86_64/mod.rs
+++ b/sgx_oc/src/linux/x86_64/mod.rs
@@ -464,6 +464,9 @@ pub const AT_SYMLINK_NOFOLLOW: c_int = 0x100;
pub const AT_REMOVEDIR: c_int = 0x200;
pub const AT_SYMLINK_FOLLOW: c_int = 0x400;
+pub const UTIME_OMIT: c_long = 1073741822;
+pub const UTIME_NOW: c_long = 1073741823;
+
pub const CLOCK_REALTIME: clockid_t = 0;
pub const CLOCK_MONOTONIC: clockid_t = 1;
pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
@@ -1279,7 +1282,7 @@ pub const SA_NOCLDWAIT: c_int = 0x0000_0002;
pub const SIG_DFL: sighandler_t = 0_usize;
pub const SIG_IGN: sighandler_t = 1_usize;
-pub const SIG_ERR: sighandler_t = !0 as usize;
+pub const SIG_ERR: sighandler_t = !0;
pub const SIGHUP: c_int = 1;
pub const SIGINT: c_int = 2;
diff --git a/sgx_protected_fs/tfs/src/capi.rs b/sgx_protected_fs/tfs/src/capi.rs
index 77fd69f4..70f90c7e 100644
--- a/sgx_protected_fs/tfs/src/capi.rs
+++ b/sgx_protected_fs/tfs/src/capi.rs
@@ -351,11 +351,7 @@ pub unsafe extern "C" fn sgx_feof(file: RawProtectedFile) -> i32 {
}
let file = ManuallyDrop::new(SgxFile::from_raw(file));
- if file.is_eof() {
- 1
- } else {
- 0
- }
+ i32::from(file.is_eof())
}
/// # Safety
@@ -533,7 +529,7 @@ pub unsafe extern "C" fn sgx_fimport_auto_key(
KeyPolicy::MRSIGNER
};
- match fs_imp::import_key(name, *import_key, key_policy) {
+ match fs_imp::import_key(name, *import_key, Some(key_policy)) {
Ok(_) => 0,
Err(_) => -1,
}
diff --git a/sgx_protected_fs/tfs/src/sys/error.rs b/sgx_protected_fs/tfs/src/sys/error.rs
index df71b95a..6ee72820 100644
--- a/sgx_protected_fs/tfs/src/sys/error.rs
+++ b/sgx_protected_fs/tfs/src/sys/error.rs
@@ -133,13 +133,13 @@ impl Error for FsError {
#[macro_export]
macro_rules! esgx {
($status:expr) => {
- crate::sys::error::FsError::from_sgx_error($status)
+ $crate::sys::error::FsError::from_sgx_error($status)
};
}
#[macro_export]
macro_rules! eos {
($errno:expr) => {
- crate::sys::error::FsError::from_os_error($errno)
+ $crate::sys::error::FsError::from_os_error($errno)
};
}
diff --git a/sgx_protected_fs/ufs/src/lib.rs b/sgx_protected_fs/ufs/src/lib.rs
index 5054ee78..0ccce906 100644
--- a/sgx_protected_fs/ufs/src/lib.rs
+++ b/sgx_protected_fs/ufs/src/lib.rs
@@ -257,8 +257,8 @@ impl FileStream {
fn seek(&self, pos: SeekFrom) -> OsResult {
let (offset, whence) = match pos {
SeekFrom::Start(off) => (off as i64, libc::SEEK_SET),
- SeekFrom::End(off) => (off as i64, libc::SEEK_END),
- SeekFrom::Current(off) => (off as i64, libc::SEEK_CUR),
+ SeekFrom::End(off) => (off, libc::SEEK_END),
+ SeekFrom::Current(off) => (off, libc::SEEK_CUR),
};
if unsafe { libc::fseeko(self.stream, offset, whence) } != 0 {
bail!(errno())
diff --git a/sgx_rand/src/isaac.rs b/sgx_rand/src/isaac.rs
index a4e0e792..b25c40ac 100644
--- a/sgx_rand/src/isaac.rs
+++ b/sgx_rand/src/isaac.rs
@@ -534,7 +534,7 @@ impl Rng for Isaac64Rng {
// See corresponding location in IsaacRng.next_u32 for
// explanation.
debug_assert!(self.cnt < RAND_SIZE_64);
- self.rsl[(self.cnt % RAND_SIZE_64) as usize].0
+ self.rsl[(self.cnt % RAND_SIZE_64)].0
}
}
diff --git a/sgx_rsrvmm/src/rsrvmm/area.rs b/sgx_rsrvmm/src/rsrvmm/area.rs
index fe428d18..17765303 100644
--- a/sgx_rsrvmm/src/rsrvmm/area.rs
+++ b/sgx_rsrvmm/src/rsrvmm/area.rs
@@ -356,7 +356,7 @@ impl MmArea {
let (pe_needed, pr_needed) = self.is_needed_modify_perm(new_perm)?;
if pe_needed || pr_needed {
- let _ = modpr_ocall(self.start(), count, perm).unwrap();
+ modpr_ocall(self.start(), count, perm).unwrap();
}
let pages = PageRange::new(
@@ -378,10 +378,10 @@ impl MmArea {
}
if pr_needed && new_perm == MmPerm::None {
- let _ = mprotect_ocall(self.start(), count, perm).unwrap();
+ mprotect_ocall(self.start(), count, perm).unwrap();
}
} else {
- let _ = mprotect_ocall(self.start(), count, perm).unwrap();
+ mprotect_ocall(self.start(), count, perm).unwrap();
}
self.perm = new_perm;
diff --git a/sgx_rsrvmm/src/rsrvmm/manager.rs b/sgx_rsrvmm/src/rsrvmm/manager.rs
index 8ebd5bb8..ec89dcae 100644
--- a/sgx_rsrvmm/src/rsrvmm/manager.rs
+++ b/sgx_rsrvmm/src/rsrvmm/manager.rs
@@ -223,7 +223,7 @@ impl MmManager {
}
}
- if result_free_range == None
+ if result_free_range.is_none()
|| result_free_range.as_ref().unwrap().size() > free_range.size()
{
// Record the minimal free range that satisfies the contraints
diff --git a/sgx_serialize/src/json.rs b/sgx_serialize/src/json.rs
index b8e4ccf1..bb1ca227 100644
--- a/sgx_serialize/src/json.rs
+++ b/sgx_serialize/src/json.rs
@@ -17,6 +17,7 @@
#![forbid(non_camel_case_types)]
#![allow(missing_docs)]
+#![allow(clippy::derive_partial_eq_without_eq)]
//! JSON parsing and serialization
//!
@@ -237,7 +238,7 @@ pub struct AsPrettyJson<'a, T> {
/// The errors that can arise while parsing a JSON stream.
#[allow(clippy::upper_case_acronyms)]
-#[derive(Clone, Copy, PartialEq, Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ErrorCode {
InvalidSyntax,
InvalidNumber,
@@ -258,7 +259,7 @@ pub enum ErrorCode {
NotUtf8,
}
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum ParserError {
/// msg, line, col
SyntaxError(ErrorCode, usize, usize),
@@ -268,7 +269,7 @@ pub enum ParserError {
// Builder and Parser have the same errors.
pub type BuilderError = ParserError;
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum DecoderError {
ParseError(ParserError),
ExpectedError(string::String, string::String),
@@ -1321,7 +1322,7 @@ impl Index<usize> for Json {
}
/// The output of the streaming parser.
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum JsonEvent {
ObjectStart,
ObjectEnd,
@@ -1370,7 +1371,7 @@ pub struct Stack {
/// As an example, `StackElement::Key("foo")`, `StackElement::Key("bar")`,
/// `StackElement::Index(3)`, and `StackElement::Key("x")` are the
/// StackElements composing the stack that represents `foo.bar[3].x`.
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum StackElement<'l> {
Index(u32),
Key(&'l str),
@@ -1378,7 +1379,7 @@ pub enum StackElement<'l> {
// Internally, Key elements are stored as indices in a buffer to avoid
// allocating a string for every member of an object.
-#[derive(PartialEq, Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
enum InternalStackElement {
InternalIndex(u32),
InternalKey(u16, u16), // start, size
diff --git a/sgx_serialize/src/lib.rs b/sgx_serialize/src/lib.rs
index 02ead6c3..fa8f88ca 100644
--- a/sgx_serialize/src/lib.rs
+++ b/sgx_serialize/src/lib.rs
@@ -25,12 +25,13 @@ Core encoding and decoding interfaces.
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
#![feature(box_syntax)]
#![feature(never_type)]
-#![feature(nll)]
#![feature(associated_type_bounds)]
#![feature(min_specialization)]
#![feature(core_intrinsics)]
#![feature(maybe_uninit_slice)]
#![feature(new_uninit)]
+#![allow(clippy::borrow_deref_ref)]
+#![allow(clippy::explicit_auto_deref)]
#[cfg(all(feature = "tserialize", feature = "userialize"))]
compile_error!(
diff --git a/sgx_serialize/src/opaque.rs b/sgx_serialize/src/opaque.rs
index ba1d2b9c..910f2714 100644
--- a/sgx_serialize/src/opaque.rs
+++ b/sgx_serialize/src/opaque.rs
@@ -147,7 +147,7 @@ impl serialize::Encoder for Encoder {
#[inline]
fn emit_bool(&mut self, v: bool) -> EncodeResult {
- self.emit_u8(if v { 1 } else { 0 })
+ self.emit_u8(u8::from(v))
}
#[inline]
diff --git a/sgx_serialize/src/types.rs b/sgx_serialize/src/types.rs
index 1d35ef6d..9a417616 100644
--- a/sgx_serialize/src/types.rs
+++ b/sgx_serialize/src/types.rs
@@ -1551,7 +1551,6 @@ impl Decodable for TeeTcbSvn {
}
impl Encodable for TeeInfo {
- #[allow(unaligned_references)]
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
let TeeInfo {
attributes: ref _attributes,
@@ -1608,16 +1607,22 @@ impl Decodable for TeeInfo {
}
impl Encodable for TeeTcbInfo {
- #[allow(unaligned_references)]
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
- let TeeTcbInfo {
- valid: ref _valid,
- tee_tcb_svn: ref _tee_tcb_svn,
- mr_seam: ref _mr_seam,
- mr_seam_signer: ref _mr_seam_signer,
- attributes: ref _attributes,
- reserved: ref _reserved,
- } = *self;
+ // let TeeTcbInfo {
+ // valid: ref _valid,
+ // tee_tcb_svn: ref _tee_tcb_svn,
+ // mr_seam: ref _mr_seam,
+ // mr_seam_signer: ref _mr_seam_signer,
+ // attributes: ref _attributes,
+ // reserved: ref _reserved,
+ // } = *self;
+ let _valid = unsafe { &*core::ptr::addr_of!(self.valid) };
+ let _tee_tcb_svn = unsafe { &*core::ptr::addr_of!(self.tee_tcb_svn) };
+ let _mr_seam = unsafe { &*core::ptr::addr_of!(self.mr_seam) };
+ let _mr_seam_signer = unsafe { &*core::ptr::addr_of!(self.mr_seam_signer) };
+ let _attributes = unsafe { &*core::ptr::addr_of!(self.attributes) };
+ let _reserved = unsafe { &*core::ptr::addr_of!(self.reserved) };
+
e.emit_struct("TeeTcbInfo", 6usize, |e| -> _ {
e.emit_struct_field("valid", 0usize, |e| -> _ { Encodable::encode(&*_valid, e) })?;
e.emit_struct_field("tee_tcb_svn", 1usize, |e| -> _ {
@@ -1655,22 +1660,34 @@ impl Decodable for TeeTcbInfo {
}
impl Encodable for Report2Body {
- #[allow(unaligned_references)]
fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
- let Report2Body {
- tee_tcb_svn: ref _tee_tcb_svn,
- mr_seam: ref _mr_seam,
- mrsigner_seam: ref _mrsigner_seam,
- seam_attributes: ref _seam_attributes,
- td_attributes: ref _td_attributes,
- xfam: ref _xfam,
- mr_td: ref _mr_td,
- mr_config_id: ref _mr_config_id,
- mr_owner: ref _mr_owner,
- mr_owner_config: ref _mr_owner_config,
- rt_mr: ref _rt_mr,
- report_data: ref _report_data,
- } = *self;
+ // let Report2Body {
+ // tee_tcb_svn: ref _tee_tcb_svn,
+ // mr_seam: ref _mr_seam,
+ // mrsigner_seam: ref _mrsigner_seam,
+ // seam_attributes: ref _seam_attributes,
+ // td_attributes: ref _td_attributes,
+ // xfam: ref _xfam,
+ // mr_td: ref _mr_td,
+ // mr_config_id: ref _mr_config_id,
+ // mr_owner: ref _mr_owner,
+ // mr_owner_config: ref _mr_owner_config,
+ // rt_mr: ref _rt_mr,
+ // report_data: ref _report_data,
+ // } = *self;
+ let _tee_tcb_svn = unsafe { &*core::ptr::addr_of!(self.tee_tcb_svn) };
+ let _mr_seam = unsafe { &*core::ptr::addr_of!(self.mr_seam) };
+ let _mrsigner_seam = unsafe { &*core::ptr::addr_of!(self.mrsigner_seam) };
+ let _seam_attributes = unsafe { &*core::ptr::addr_of!(self.seam_attributes) };
+ let _td_attributes = unsafe { &*core::ptr::addr_of!(self.td_attributes) };
+ let _xfam = unsafe { &*core::ptr::addr_of!(self.xfam) };
+ let _mr_td = unsafe { &*core::ptr::addr_of!(self.mr_td) };
+ let _mr_config_id = unsafe { &*core::ptr::addr_of!(self.mr_config_id) };
+ let _mr_owner = unsafe { &*core::ptr::addr_of!(self.mr_owner) };
+ let _mr_owner_config = unsafe { &*core::ptr::addr_of!(self.mr_owner_config) };
+ let _rt_mr = unsafe { &*core::ptr::addr_of!(self.rt_mr) };
+ let _report_data = unsafe { &*core::ptr::addr_of!(self.report_data) };
+
e.emit_struct("Report2Body", 12usize, |e| -> _ {
e.emit_struct_field("tee_tcb_svn", 0usize, |e| -> _ {
Encodable::encode(&*_tee_tcb_svn, e)
diff --git a/sgx_sync/Cargo.toml b/sgx_sync/Cargo.toml
index c1d0c5d7..7e86c4f8 100644
--- a/sgx_sync/Cargo.toml
+++ b/sgx_sync/Cargo.toml
@@ -31,6 +31,7 @@ crate-type = ["rlib"]
[features]
default = []
+capi = []
[dependencies]
sgx_trts = { path = "../sgx_trts" }
diff --git a/sgx_sync/src/capi.rs b/sgx_sync/src/capi.rs
index 4f6bcb1e..9625723a 100644
--- a/sgx_sync/src/capi.rs
+++ b/sgx_sync/src/capi.rs
@@ -17,7 +17,7 @@
use crate::spin::SpinMutex;
use crate::sys::condvar::{Condvar, MovableCondvar};
-use crate::sys::mutex::{MovableMutex, Mutex, MutexControl};
+use crate::sys::mutex::{MovableMutex, MovableReentrantMutex, Mutex, MutexControl};
use crate::sys::rwlock::{MovableRwLock, RwLock};
use alloc::boxed::Box;
use core::mem;
@@ -126,8 +126,18 @@ pub unsafe extern "C" fn sgx_thread_mutex_init(
return EINVAL;
};
- let m = ManuallyDrop::new(MovableMutex::from(Mutex::new_with_control(control)));
- mutex.mutex = m.as_ref() as *const _ as *mut c_void;
+ let mutex_ptr = match control {
+ MutexControl::NonRecursive => {
+ let m = ManuallyDrop::new(MovableMutex::new());
+ &**m as *const _ as *mut c_void
+ }
+ MutexControl::Recursive => {
+ let m = ManuallyDrop::new(MovableReentrantMutex::new());
+ &**m as *const _ as *mut c_void
+ }
+ };
+
+ mutex.mutex = mutex_ptr;
0
}
@@ -207,8 +217,8 @@ pub unsafe extern "C" fn sgx_thread_cond_init(
) -> c_int {
check_param!(cond, sgx_thread_cond_t);
- let c = ManuallyDrop::new(MovableCondvar::from(Condvar::new()));
- (*cond).cond = c.as_ref() as *const _ as *mut c_void;
+ let c = ManuallyDrop::new(MovableCondvar::new());
+ (*cond).cond = &**c as *const _ as *mut c_void;
0
}
@@ -333,8 +343,8 @@ pub unsafe extern "C" fn sgx_thread_rwlock_init(
) -> c_int {
check_param!(rwlock, sgx_thread_rwlock_t);
- let rw = ManuallyDrop::new(MovableRwLock::from(RwLock::new()));
- (*rwlock).rwlock = rw.as_ref() as *const _ as *mut c_void;
+ let rw = ManuallyDrop::new(MovableRwLock::new());
+ (*rwlock).rwlock = &**rw as *const _ as *mut c_void;
0
}
diff --git a/sgx_sync/src/condvar.rs b/sgx_sync/src/condvar.rs
index 835e187c..4c1452fa 100644
--- a/sgx_sync/src/condvar.rs
+++ b/sgx_sync/src/condvar.rs
@@ -33,10 +33,10 @@ pub struct Condvar {
impl Condvar {
/// Creates a new condition variable for use.
- pub fn new() -> Condvar {
- let c = imp::MovableCondvar::from(imp::Condvar::new());
- Condvar {
- inner: c,
+ #[inline]
+ pub const fn new() -> Condvar {
+ Self {
+ inner: imp::MovableCondvar::new(),
check: CondvarCheck::new(),
}
}
@@ -63,7 +63,7 @@ impl Condvar {
#[inline]
pub unsafe fn wait(&self, mutex: &MovableMutex) {
self.check.verify(mutex);
- let r = self.inner.wait(mutex.as_ref());
+ let r = self.inner.wait(mutex.raw());
debug_assert_eq!(r, Ok(()));
}
@@ -76,19 +76,12 @@ impl Condvar {
#[inline]
pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool {
self.check.verify(mutex);
- let r = self.inner.wait_timeout(mutex.as_ref(), dur);
+ let r = self.inner.wait_timeout(mutex.raw(), dur);
debug_assert!(r == Err(ETIMEDOUT) || r == Ok(()));
r == Ok(())
}
}
-impl Drop for Condvar {
- fn drop(&mut self) {
- let r = unsafe { self.inner.destroy() };
- debug_assert_eq!(r, Ok(()));
- }
-}
-
impl Default for Condvar {
fn default() -> Condvar {
Condvar::new()
diff --git a/sgx_sync/src/condvar/check.rs b/sgx_sync/src/condvar/check.rs
index 97193af8..0f00e9b7 100644
--- a/sgx_sync/src/condvar/check.rs
+++ b/sgx_sync/src/condvar/check.rs
@@ -15,10 +15,11 @@
// specific language governing permissions and limitations
// under the License..
+use crate::lazy_box::{LazyBox, LazyInit};
use crate::mutex::MovableMutex;
-use crate::sys::mutex as mutex_imp;
-use alloc::boxed::Box;
-use core::sync::atomic::{AtomicUsize, Ordering};
+use crate::sys::mutex as imp;
+use core::ptr;
+use core::sync::atomic::{AtomicPtr, Ordering};
pub trait CondvarCheck {
type Check;
@@ -26,27 +27,31 @@ pub trait CondvarCheck {
/// For boxed mutexes, a `Condvar` will check it's only ever used with the same
/// mutex, based on its (stable) address.
-impl CondvarCheck for Box<mutex_imp::Mutex> {
+impl<T: LazyInit> CondvarCheck for LazyBox<T> {
type Check = SameMutexCheck;
}
pub struct SameMutexCheck {
- addr: AtomicUsize,
+ addr: AtomicPtr<()>,
}
#[allow(dead_code)]
impl SameMutexCheck {
pub const fn new() -> Self {
Self {
- addr: AtomicUsize::new(0),
+ addr: AtomicPtr::new(ptr::null_mut()),
}
}
pub fn verify(&self, mutex: &MovableMutex) {
- let addr = mutex.as_ref() as *const mutex_imp::Mutex as usize;
- match self
- .addr
- .compare_exchange(0, addr, Ordering::SeqCst, Ordering::SeqCst)
- {
+ let addr = mutex.raw() as *const imp::Mutex as *const () as *mut _;
+ // Relaxed is okay here because we never read through `self.addr`, and only use it to
+ // compare addresses.
+ match self.addr.compare_exchange(
+ ptr::null_mut(),
+ addr,
+ Ordering::Relaxed,
+ Ordering::Relaxed,
+ ) {
Ok(_) => {} // Stored the address
Err(n) if n == addr => {} // Lost a race to store the same address
_ => panic!("attempted to use a condition variable with two mutexes"),
@@ -56,7 +61,7 @@ impl SameMutexCheck {
/// Unboxed mutexes may move, so `Condvar` can not require its address to stay
/// constant.
-impl CondvarCheck for mutex_imp::Mutex {
+impl CondvarCheck for imp::Mutex {
type Check = NoCheck;
}
diff --git a/sgx_sync/src/futex.rs b/sgx_sync/src/futex.rs
index 3ab44053..06434510 100644
--- a/sgx_sync/src/futex.rs
+++ b/sgx_sync/src/futex.rs
@@ -18,7 +18,7 @@
use crate::sys::futex as imp;
use crate::Timespec;
use core::marker::PhantomData;
-use core::sync::atomic::AtomicI32;
+use core::sync::atomic::AtomicU32;
use core::time::Duration;
use sgx_types::error::OsResult;
@@ -72,11 +72,11 @@ impl_enum! {
pub struct Futex<'a> {
futex: imp::Futex,
- marker: PhantomData<&'a AtomicI32>,
+ marker: PhantomData<&'a AtomicU32>,
}
impl<'a> Futex<'a> {
- pub fn new(futex: &AtomicI32) -> Futex<'a> {
+ pub fn new(futex: &AtomicU32) -> Futex<'a> {
Futex {
futex: imp::Futex::new(futex as *const _ as usize),
marker: PhantomData,
@@ -84,14 +84,14 @@ impl<'a> Futex<'a> {
}
#[inline]
- pub fn wait(&self, expected: i32, timeout: Option<Duration>) -> OsResult {
+ pub fn wait(&self, expected: u32, timeout: Option<Duration>) -> OsResult {
self.futex.wait(expected, timeout)
}
#[inline]
pub fn wait_bitset(
&self,
- expected: i32,
+ expected: u32,
timeout: Option<(Timespec, FutexClockId)>,
bitset: u32,
) -> OsResult {
@@ -114,7 +114,7 @@ impl<'a> Futex<'a> {
nwakes: i32,
new_futex: &Futex,
nrequeues: i32,
- expected: i32,
+ expected: u32,
) -> OsResult<usize> {
self.futex.cmp_requeue(
nwakes as usize,
diff --git a/sgx_sync/src/lazy_box.rs b/sgx_sync/src/lazy_box.rs
new file mode 100644
index 00000000..c26e21f7
--- /dev/null
+++ b/sgx_sync/src/lazy_box.rs
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+#![allow(dead_code)] // Only used on some platforms.
+
+// This is used to wrap pthread {Mutex, Condvar, RwLock} in.
+
+use alloc::boxed::Box;
+use core::marker::PhantomData;
+use core::ops::{Deref, DerefMut};
+use core::ptr::null_mut;
+use core::sync::atomic::{
+ AtomicPtr,
+ Ordering::{AcqRel, Acquire},
+};
+
+pub struct LazyBox<T: LazyInit> {
+ ptr: AtomicPtr<T>,
+ _phantom: PhantomData<T>,
+}
+
+pub trait LazyInit {
+ /// This is called before the box is allocated, to provide the value to
+ /// move into the new box.
+ ///
+ /// It might be called more than once per LazyBox, as multiple threads
+ /// might race to initialize it concurrently, each constructing and initializing
+ /// their own box. All but one of them will be passed to `cancel_init` right after.
+ fn init() -> Box<Self>;
+
+ /// Any surplus boxes from `init()` that lost the initialization race
+ /// are passed to this function for disposal.
+ ///
+ /// The default implementation calls destroy().
+ fn cancel_init(x: Box<Self>) {
+ Self::destroy(x);
+ }
+
+ /// This is called to destroy a used box.
+ ///
+ /// The default implementation just drops it.
+ fn destroy(_: Box<Self>) {}
+}
+
+impl<T: LazyInit> LazyBox<T> {
+ #[inline]
+ pub const fn new() -> Self {
+ Self {
+ ptr: AtomicPtr::new(null_mut()),
+ _phantom: PhantomData,
+ }
+ }
+
+ #[inline]
+ fn get_pointer(&self) -> *mut T {
+ let ptr = self.ptr.load(Acquire);
+ if ptr.is_null() {
+ self.initialize()
+ } else {
+ ptr
+ }
+ }
+
+ #[cold]
+ fn initialize(&self) -> *mut T {
+ let new_ptr = Box::into_raw(T::init());
+ match self
+ .ptr
+ .compare_exchange(null_mut(), new_ptr, AcqRel, Acquire)
+ {
+ Ok(_) => new_ptr,
+ Err(ptr) => {
+ // Lost the race to another thread.
+ // Drop the box we created, and use the one from the other thread instead.
+ T::cancel_init(unsafe { Box::from_raw(new_ptr) });
+ ptr
+ }
+ }
+ }
+}
+
+impl<T: LazyInit> Deref for LazyBox<T> {
+ type Target = T;
+ #[inline]
+ fn deref(&self) -> &T {
+ unsafe { &*self.get_pointer() }
+ }
+}
+
+impl<T: LazyInit> DerefMut for LazyBox<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut T {
+ unsafe { &mut *self.get_pointer() }
+ }
+}
+
+impl<T: LazyInit> Drop for LazyBox<T> {
+ fn drop(&mut self) {
+ let ptr = *self.ptr.get_mut();
+ if !ptr.is_null() {
+ T::destroy(unsafe { Box::from_raw(ptr) });
+ }
+ }
+}
diff --git a/sgx_sync/src/lazy_lock.rs b/sgx_sync/src/lazy_lock.rs
new file mode 100644
index 00000000..bbdffe6a
--- /dev/null
+++ b/sgx_sync/src/lazy_lock.rs
@@ -0,0 +1,88 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+use crate::once_lock::OnceLock;
+use core::cell::Cell;
+use core::fmt;
+use core::ops::Deref;
+use core::panic::{RefUnwindSafe, UnwindSafe};
+
+/// A value which is initialized on the first access.
+///
+/// This type is a thread-safe `Lazy`, and can be used in statics.
+///
+pub struct LazyLock<T, F = fn() -> T> {
+ cell: OnceLock<T>,
+ init: Cell<Option<F>>,
+}
+
+impl<T, F> LazyLock<T, F> {
+ /// Creates a new lazy value with the given initializing
+ /// function.
+ pub const fn new(f: F) -> LazyLock<T, F> {
+ LazyLock {
+ cell: OnceLock::new(),
+ init: Cell::new(Some(f)),
+ }
+ }
+}
+
+impl<T, F: FnOnce() -> T> LazyLock<T, F> {
+ /// Forces the evaluation of this lazy value and
+ /// returns a reference to result. This is equivalent
+ /// to the `Deref` impl, but is explicit.
+ ///
+ pub fn force(this: &LazyLock<T, F>) -> &T {
+ this.cell.get_or_init(|| match this.init.take() {
+ Some(f) => f(),
+ None => panic!("Lazy instance has previously been poisoned"),
+ })
+ }
+}
+
+impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ LazyLock::force(self)
+ }
+}
+
+impl<T: Default> Default for LazyLock<T> {
+ /// Creates a new lazy value using `Default` as the initializing function.
+ fn default() -> LazyLock<T> {
+ LazyLock::new(T::default)
+ }
+}
+
+impl<T: fmt::Debug, F> fmt::Debug for LazyLock<T, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Lazy")
+ .field("cell", &self.cell)
+ .finish_non_exhaustive()
+ }
+}
+
+// We never create a `&F` from a `&LazyLock<T, F>` so it is fine
+// to not impl `Sync` for `F`
+// we do create a `&mut Option<F>` in `force`, but this is
+// properly synchronized, so it only happens once
+// so it also does not contribute to this impl.
+unsafe impl<T, F: Send> Sync for LazyLock<T, F> where OnceLock<T>: Sync {}
+// auto-derived `Send` impl is OK.
+
+impl<T, F: UnwindSafe> RefUnwindSafe for LazyLock<T, F> where OnceLock<T>: RefUnwindSafe {}
+impl<T, F: UnwindSafe> UnwindSafe for LazyLock<T, F> where OnceLock<T>: UnwindSafe {}
diff --git a/sgx_sync/src/lib.rs b/sgx_sync/src/lib.rs
index c57ac470..76d3818a 100644
--- a/sgx_sync/src/lib.rs
+++ b/sgx_sync/src/lib.rs
@@ -18,6 +18,7 @@
#![no_std]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
#![deny(unused_features)]
+#![feature(const_trait_impl)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(hashmap_internals)]
@@ -36,25 +37,30 @@ extern crate sgx_types;
mod barrier;
mod condvar;
mod futex;
-mod lazy;
+mod lazy_box;
+mod lazy_lock;
mod lock_api;
mod mutex;
mod once;
+mod once_lock;
mod remutex;
mod rwlock;
mod spin;
mod sys;
+#[cfg(feature = "capi")]
pub mod capi;
+
pub use sys::ocall::Timespec;
pub use barrier::{Barrier, BarrierWaitResult};
pub use condvar::Condvar;
pub use futex::{Futex, FutexClockId, FutexFlags, FutexOp};
-pub use lazy::{SyncLazy, SyncOnceCell};
+pub use lazy_lock::LazyLock;
pub use lock_api::{RawMutex, RawRwLock};
pub use mutex::{MovableMutex, StaticMutex, StaticMutexGuard};
pub use once::{Once, OnceState, ONCE_INIT};
+pub use once_lock::OnceLock;
pub use remutex::{ReentrantMutex, ReentrantMutexGuard};
pub use rwlock::{MovableRwLock, StaticRwLock, StaticRwLockReadGuard, StaticRwLockWriteGuard};
pub use spin::{SpinMutex, SpinMutexGuard, SpinRwLock, SpinRwLockReadGuard, SpinRwLockWriteGuard};
diff --git a/sgx_sync/src/mutex.rs b/sgx_sync/src/mutex.rs
index 76b1f943..922e7d50 100644
--- a/sgx_sync/src/mutex.rs
+++ b/sgx_sync/src/mutex.rs
@@ -34,6 +34,7 @@ unsafe impl Sync for StaticMutex {}
impl StaticMutex {
/// Creates a new mutex for use.
+ #[inline]
pub const fn new() -> StaticMutex {
StaticMutex(imp::Mutex::new())
}
@@ -65,13 +66,12 @@ impl Drop for StaticMutexGuard {
/// An SGX-based mutual exclusion lock.
///
-/// This mutex does *not* have a const constructor, cleans up its resources in
-/// its `Drop` implementation, may safely be moved (when not borrowed), and
-/// does not cause UB when used reentrantly.
+/// This mutex cleans up its resources in its `Drop` implementation, may safely
+/// be moved (when not borrowed), and does not cause UB when used reentrantly.
///
/// This mutex does not implement poisoning.
///
-/// This is either a wrapper around `Box<imp::Mutex>` or `imp::Mutex`,
+/// This is either a wrapper around `LazyBox<imp::Mutex>` or `imp::Mutex`,
/// depending on the platform. It is boxed on platforms where `imp::Mutex` may
/// not be moved.
pub struct MovableMutex(imp::MovableMutex);
@@ -80,11 +80,12 @@ unsafe impl Sync for MovableMutex {}
impl MovableMutex {
/// Creates a new mutex.
- pub fn new() -> MovableMutex {
- MovableMutex(imp::MovableMutex::from(imp::Mutex::new()))
+ #[inline]
+ pub const fn new() -> MovableMutex {
+ MovableMutex(imp::MovableMutex::new())
}
- pub(crate) fn as_ref(&self) -> &imp::Mutex {
+ pub(crate) fn raw(&self) -> &imp::Mutex {
&self.0
}
@@ -115,13 +116,6 @@ impl MovableMutex {
}
}
-impl Drop for MovableMutex {
- fn drop(&mut self) {
- let r = unsafe { self.0.destroy() };
- debug_assert_eq!(r, Ok(()));
- }
-}
-
impl Default for MovableMutex {
fn default() -> MovableMutex {
MovableMutex::new()
diff --git a/sgx_sync/src/lazy.rs b/sgx_sync/src/once_lock.rs
similarity index 64%
rename from sgx_sync/src/lazy.rs
rename to sgx_sync/src/once_lock.rs
index 03b5b067..bd54de13 100644
--- a/sgx_sync/src/lazy.rs
+++ b/sgx_sync/src/once_lock.rs
@@ -16,72 +16,30 @@
// under the License..
use crate::once::Once;
-use core::cell::{Cell, UnsafeCell};
+use core::cell::UnsafeCell;
use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
-use core::ops::{Deref, Drop};
+use core::ops::Drop;
+use core::panic::{RefUnwindSafe, UnwindSafe};
-pub struct SyncOnceCell<T> {
+/// A synchronization primitive which can be written to only once.
+///
+/// This type is a thread-safe `OnceCell`.
+///
+pub struct OnceLock<T> {
once: Once,
+ // Whether or not the value is initialized is tracked by `state_and_queue`.
value: UnsafeCell<MaybeUninit<T>>,
- // `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
+ /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl.
_marker: PhantomData<T>,
}
-unsafe impl<T: Sync + Send> Sync for SyncOnceCell<T> {}
-unsafe impl<T: Send> Send for SyncOnceCell<T> {}
-
-impl<T> Default for SyncOnceCell<T> {
- fn default() -> SyncOnceCell<T> {
- SyncOnceCell::new()
- }
-}
-
-impl<T: fmt::Debug> fmt::Debug for SyncOnceCell<T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.get() {
- Some(v) => f.debug_tuple("Once").field(v).finish(),
- None => f.write_str("Once(Uninit)"),
- }
- }
-}
-
-impl<T: Clone> Clone for SyncOnceCell<T> {
- fn clone(&self) -> SyncOnceCell<T> {
- let cell = SyncOnceCell::new();
- if let Some(value) = self.get() {
- match cell.set(value.clone()) {
- Ok(()) => (),
- Err(_) => unreachable!(),
- }
- }
- cell
- }
-}
-
-impl<T> From<T> for SyncOnceCell<T> {
- fn from(value: T) -> SyncOnceCell<T> {
- let cell = SyncOnceCell::new();
- match cell.set(value) {
- Ok(()) => cell,
- Err(_) => unreachable!(),
- }
- }
-}
-
-impl<T: PartialEq> PartialEq for SyncOnceCell<T> {
- fn eq(&self, other: &SyncOnceCell<T>) -> bool {
- self.get() == other.get()
- }
-}
-
-impl<T: Eq> Eq for SyncOnceCell<T> {}
-
-impl<T> SyncOnceCell<T> {
+impl<T> OnceLock<T> {
/// Creates a new empty cell.
- pub const fn new() -> SyncOnceCell<T> {
- SyncOnceCell {
+ #[must_use]
+ pub const fn new() -> OnceLock<T> {
+ OnceLock {
once: Once::new(),
value: UnsafeCell::new(MaybeUninit::uninit()),
_marker: PhantomData,
@@ -92,6 +50,7 @@ impl<T> SyncOnceCell<T> {
///
/// Returns `None` if the cell is empty, or being initialized. This
/// method never blocks.
+ ///
pub fn get(&self) -> Option<&T> {
if self.is_initialized() {
// Safe b/c checked is_initialized
@@ -115,7 +74,10 @@ impl<T> SyncOnceCell<T> {
/// Sets the contents of this cell to `value`.
///
- /// Returns `Ok(())` if the cell's value was updated.
+ /// May block if another thread is currently attempting to initialize the cell. The cell is
+ /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+ ///
+ /// Returns `Ok(())` if the cell's value was set by this call.
///
pub fn set(&self, value: T) -> Result<(), T> {
let mut value = Some(value);
@@ -171,7 +133,7 @@ impl<T> SyncOnceCell<T> {
{
// Fast path check
// NOTE: We need to perform an acquire on the state in this method
- // in order to correctly synchronize `SyncLazy::force`. This is
+ // in order to correctly synchronize `LazyLock::force`. This is
// currently done by calling `self.get()`, which in turn calls
// `self.is_initialized()`, which in turn performs the acquire.
if let Some(value) = self.get() {
@@ -185,16 +147,16 @@ impl<T> SyncOnceCell<T> {
Ok(unsafe { self.get_unchecked() })
}
- /// Consumes the `SyncOnceCell`, returning the wrapped value. Returns
+ /// Consumes the `OnceLock`, returning the wrapped value. Returns
/// `None` if the cell was empty.
///
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
- /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
+ /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state.
///
- /// Has no effect and returns `None` if the `SyncOnceCell` hasn't been initialized.
+ /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized.
///
/// Safety is guaranteed by requiring a mutable reference.
///
@@ -204,7 +166,7 @@ impl<T> SyncOnceCell<T> {
// SAFETY: `self.value` is initialized and contains a valid `T`.
// `self.once` is reset, so `is_initialized()` will be false again
// which prevents the value from being read twice.
- unsafe { Some((&*self.value.get()).assume_init_read()) }
+ unsafe { Some((*self.value.get()).assume_init_read()) }
} else {
None
}
@@ -228,7 +190,7 @@ impl<T> SyncOnceCell<T> {
self.once.call_once_force(|p| {
match f() {
Ok(value) => {
- unsafe { (&mut *slot.get()).write(value) };
+ unsafe { (*slot.get()).write(value) };
}
Err(e) => {
res = Err(e);
@@ -242,90 +204,86 @@ impl<T> SyncOnceCell<T> {
res
}
- /// Safety: The value must be initialized
+ /// # Safety
+ ///
+ /// The value must be initialized
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
- (&*self.value.get()).assume_init_ref()
+ (*self.value.get()).assume_init_ref()
}
- /// Safety: The value must be initialized
+ /// # Safety
+ ///
+ /// The value must be initialized
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_initialized());
- (&mut *self.value.get()).assume_init_mut()
+ (*self.value.get()).assume_init_mut()
}
}
-unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
- fn drop(&mut self) {
- if self.is_initialized() {
- // Safety: The cell is initialized and being dropped, so it can't
- // be accessed again. We also don't touch the `T` other than
- // dropping it, which validates our usage of #[may_dangle].
- unsafe { (&mut *self.value.get()).assume_init_drop() };
- }
- }
-}
+unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
+unsafe impl<T: Send> Send for OnceLock<T> {}
-/// A value which is initialized on the first access.
-///
-/// This type is a thread-safe `Lazy`, and can be used in statics.
-///
-pub struct SyncLazy<T, F = fn() -> T> {
- cell: SyncOnceCell<T>,
- init: Cell<Option<F>>,
+impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
+impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
+
+impl<T> const Default for OnceLock<T> {
+ /// Creates a new empty cell.
+ ///
+ fn default() -> OnceLock<T> {
+ OnceLock::new()
+ }
}
-impl<T: fmt::Debug, F> fmt::Debug for SyncLazy<T, F> {
+impl<T: fmt::Debug> fmt::Debug for OnceLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Lazy")
- .field("cell", &self.cell)
- .field("init", &"..")
- .finish()
+ match self.get() {
+ Some(v) => f.debug_tuple("Once").field(v).finish(),
+ None => f.write_str("Once(Uninit)"),
+ }
}
}
-// We never create a `&F` from a `&SyncLazy<T, F>` so it is fine
-// to not impl `Sync` for `F`
-// we do create a `&mut Option<F>` in `force`, but this is
-// properly synchronized, so it only happens once
-// so it also does not contribute to this impl.
-unsafe impl<T, F: Send> Sync for SyncLazy<T, F> where SyncOnceCell<T>: Sync {}
-// auto-derived `Send` impl is OK.
-
-impl<T, F> SyncLazy<T, F> {
- /// Creates a new lazy value with the given initializing
- /// function.
- pub const fn new(f: F) -> SyncLazy<T, F> {
- SyncLazy {
- cell: SyncOnceCell::new(),
- init: Cell::new(Some(f)),
+impl<T: Clone> Clone for OnceLock<T> {
+ fn clone(&self) -> OnceLock<T> {
+ let cell = Self::new();
+ if let Some(value) = self.get() {
+ match cell.set(value.clone()) {
+ Ok(()) => (),
+ Err(_) => unreachable!(),
+ }
}
+ cell
}
}
-impl<T, F: FnOnce() -> T> SyncLazy<T, F> {
- /// Forces the evaluation of this lazy value and
- /// returns a reference to result. This is equivalent
- /// to the `Deref` impl, but is explicit.
+impl<T> From<T> for OnceLock<T> {
+ /// Create a new cell with its contents set to `value`.
///
- pub fn force(this: &SyncLazy<T, F>) -> &T {
- this.cell.get_or_init(|| match this.init.take() {
- Some(f) => f(),
- None => panic!("Lazy instance has previously been poisoned"),
- })
+ fn from(value: T) -> Self {
+ let cell = Self::new();
+ match cell.set(value) {
+ Ok(()) => cell,
+ Err(_) => unreachable!(),
+ }
}
}
-impl<T, F: FnOnce() -> T> Deref for SyncLazy<T, F> {
- type Target = T;
- fn deref(&self) -> &T {
- SyncLazy::force(self)
+impl<T: PartialEq> PartialEq for OnceLock<T> {
+ fn eq(&self, other: &OnceLock<T>) -> bool {
+ self.get() == other.get()
}
}
-impl<T: Default> Default for SyncLazy<T> {
- /// Creates a new lazy value using `Default` as the initializing function.
- fn default() -> SyncLazy<T> {
- SyncLazy::new(T::default)
+impl<T: Eq> Eq for OnceLock<T> {}
+
+unsafe impl<#[may_dangle] T> Drop for OnceLock<T> {
+ fn drop(&mut self) {
+ if self.is_initialized() {
+ // SAFETY: The cell is initialized and being dropped, so it can't
+ // be accessed again. We also don't touch the `T` other than
+ // dropping it, which validates our usage of #[may_dangle].
+ unsafe { (*self.value.get()).assume_init_drop() };
+ }
}
}
diff --git a/sgx_sync/src/remutex.rs b/sgx_sync/src/remutex.rs
index 411fe530..c0f692c8 100644
--- a/sgx_sync/src/remutex.rs
+++ b/sgx_sync/src/remutex.rs
@@ -17,10 +17,8 @@
use crate::sys::mutex as sys;
use core::fmt;
-use core::marker::PhantomPinned;
use core::ops::Deref;
use core::panic::{RefUnwindSafe, UnwindSafe};
-use core::pin::Pin;
/// A re-entrant mutual exclusion
///
@@ -28,9 +26,8 @@ use core::pin::Pin;
/// available. The thread which has already locked the mutex can lock it
/// multiple times without blocking, preventing a common source of deadlocks.
pub struct ReentrantMutex<T> {
- inner: sys::ReentrantMutex,
+ inner: sys::MovableReentrantMutex,
data: T,
- _pinned: PhantomPinned,
}
unsafe impl<T: Send> Send for ReentrantMutex<T> {}
@@ -53,7 +50,7 @@ impl<T> RefUnwindSafe for ReentrantMutex<T> {}
/// guarded data.
#[must_use = "if unused the ReentrantMutex will immediately unlock"]
pub struct ReentrantMutexGuard<'a, T: 'a> {
- lock: Pin<&'a ReentrantMutex<T>>,
+ lock: &'a ReentrantMutex<T>,
}
impl<T> !Send for ReentrantMutexGuard<'_, T> {}
@@ -63,9 +60,8 @@ impl<T> ReentrantMutex<T> {
///
pub const fn new(t: T) -> ReentrantMutex<T> {
ReentrantMutex {
- inner: sys::ReentrantMutex::new(),
+ inner: sys::MovableReentrantMutex::new(),
data: t,
- _pinned: PhantomPinned,
}
}
@@ -81,11 +77,11 @@ impl<T> ReentrantMutex<T> {
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> {
+ pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
unsafe {
let _ = self.inner.lock();
}
- ReentrantMutexGuard::new(self)
+ ReentrantMutexGuard { lock: self }
}
/// Attempts to acquire this lock.
@@ -100,30 +96,18 @@ impl<T> ReentrantMutex<T> {
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return failure if the mutex would otherwise be
/// acquired.
- pub fn try_lock(self: Pin<&Self>) -> Option<ReentrantMutexGuard<'_, T>> {
+ pub fn try_lock(&self) -> Option<ReentrantMutexGuard<'_, T>> {
if unsafe { self.inner.try_lock().is_ok() } {
- Some(ReentrantMutexGuard::new(self))
+ Some(ReentrantMutexGuard { lock: self })
} else {
None
}
}
}
-impl<T> Drop for ReentrantMutex<T> {
- fn drop(&mut self) {
- // This is actually safe b/c we know that there is no further usage of
- // this mutex (it's up to the user to arrange for a mutex to get
- // dropped, that's not our job)
- unsafe {
- let _ = self.inner.destroy();
- }
- }
-}
-
impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let pin_lock = unsafe { Pin::new_unchecked(self) };
- match pin_lock.try_lock() {
+ match self.try_lock() {
Some(guard) => f
.debug_struct("ReentrantMutex")
.field("data", &*guard)
@@ -144,12 +128,6 @@ impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
}
}
-impl<'mutex, T> ReentrantMutexGuard<'mutex, T> {
- fn new(lock: Pin<&'mutex ReentrantMutex<T>>) -> ReentrantMutexGuard<'mutex, T> {
- ReentrantMutexGuard { lock }
- }
-}
-
impl<T> Deref for ReentrantMutexGuard<'_, T> {
type Target = T;
diff --git a/sgx_sync/src/rwlock.rs b/sgx_sync/src/rwlock.rs
index c047dc7d..c417ce75 100644
--- a/sgx_sync/src/rwlock.rs
+++ b/sgx_sync/src/rwlock.rs
@@ -28,6 +28,7 @@ pub struct StaticRwLock(imp::RwLock);
unsafe impl Sync for StaticRwLock {}
impl StaticRwLock {
+ #[inline]
pub const fn new() -> StaticRwLock {
StaticRwLock(imp::RwLock::new())
}
@@ -83,17 +84,23 @@ impl Drop for StaticRwLockWriteGuard {
/// An SGX-based reader-writer lock.
///
-/// This structure is entirely unsafe and serves as the lowest layer of a
-/// cross-platform binding of system rwlocks. It is recommended to use the
-/// safer types at the top level of this crate instead of this type.
+/// This rwlock cleans up its resources in its `Drop` implementation and may
+/// safely be moved (when not borrowed).
+///
+/// This rwlock does not implement poisoning.
+///
+/// This is either a wrapper around `LazyBox<imp::RwLock>` or `imp::RwLock`,
+/// depending on the platform. It is boxed on platforms where `imp::RwLock` may
+/// not be moved.
pub struct MovableRwLock(imp::MovableRwLock);
unsafe impl Sync for MovableRwLock {}
impl MovableRwLock {
/// Creates a new reader-writer lock for use.
- pub fn new() -> MovableRwLock {
- MovableRwLock(imp::MovableRwLock::from(imp::RwLock::new()))
+ #[inline]
+ pub const fn new() -> MovableRwLock {
+ MovableRwLock(imp::MovableRwLock::new())
}
/// Acquires shared access to the underlying lock, blocking the current
@@ -160,13 +167,6 @@ impl MovableRwLock {
}
}
-impl Drop for MovableRwLock {
- fn drop(&mut self) {
- let r = unsafe { self.0.destroy() };
- debug_assert_eq!(r, Ok(()));
- }
-}
-
impl Default for MovableRwLock {
fn default() -> MovableRwLock {
MovableRwLock::new()
diff --git a/sgx_sync/src/sys/condvar.rs b/sgx_sync/src/sys/condvar.rs
index 6eb8e5da..95bcf275 100644
--- a/sgx_sync/src/sys/condvar.rs
+++ b/sgx_sync/src/sys/condvar.rs
@@ -15,6 +15,7 @@
// specific language governing permissions and limitations
// under the License..
+use crate::lazy_box::{LazyBox, LazyInit};
use crate::sys::mutex::Mutex;
use crate::sys::ocall;
use alloc::boxed::Box;
@@ -28,6 +29,70 @@ use sgx_trts::tcs::{self, TcsId};
use sgx_types::error::errno::{EBUSY, ETIMEDOUT};
use sgx_types::error::OsResult;
+pub struct Condvar {
+ inner: UnsafeCell<CondvarInner>,
+}
+
+pub type MovableCondvar = LazyBox<Condvar>;
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+impl LazyInit for Condvar {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+}
+
+impl Condvar {
+ pub const fn new() -> Self {
+ Condvar {
+ inner: UnsafeCell::new(CondvarInner::new()),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn wait(&self, mutex: &Mutex) -> OsResult {
+ let condvar = &mut *self.inner.get();
+ condvar.wait(mutex)
+ }
+
+ #[inline]
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> OsResult {
+ let condvar = &mut *self.inner.get();
+ condvar.wait_timeout(mutex, dur)
+ }
+
+ #[inline]
+ pub unsafe fn notify_one(&self) -> OsResult {
+ let condvar = &mut *self.inner.get();
+ condvar.notify_one()
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) -> OsResult {
+ let condvar = &mut *self.inner.get();
+ condvar.notify_all()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) -> OsResult {
+ let condvar = &mut *self.inner.get();
+ condvar.destroy()
+ }
+}
+
+impl Drop for Condvar {
+ #[inline]
+ fn drop(&mut self) {
+ let r = unsafe { self.destroy() };
+ debug_assert_eq!(r, Ok(()));
+ }
+}
+
+struct CondvarInner {
+ inner: SpinMutex<Inner>,
+}
struct Inner {
queue: LinkedList<TcsId>,
}
@@ -40,10 +105,6 @@ impl Inner {
}
}
-struct CondvarInner {
- inner: SpinMutex<Inner>,
-}
-
impl CondvarInner {
pub const fn new() -> CondvarInner {
CondvarInner {
@@ -156,50 +217,3 @@ impl CondvarInner {
}
}
}
-
-pub type MovableCondvar = Box<Condvar>;
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-pub struct Condvar {
- inner: UnsafeCell<CondvarInner>,
-}
-
-impl Condvar {
- pub const fn new() -> Self {
- Condvar {
- inner: UnsafeCell::new(CondvarInner::new()),
- }
- }
-
- #[inline]
- pub unsafe fn wait(&self, mutex: &Mutex) -> OsResult {
- let condvar = &mut *self.inner.get();
- condvar.wait(mutex)
- }
-
- #[inline]
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> OsResult {
- let condvar = &mut *self.inner.get();
- condvar.wait_timeout(mutex, dur)
- }
-
- #[inline]
- pub unsafe fn notify_one(&self) -> OsResult {
- let condvar = &mut *self.inner.get();
- condvar.notify_one()
- }
-
- #[inline]
- pub unsafe fn notify_all(&self) -> OsResult {
- let condvar = &mut *self.inner.get();
- condvar.notify_all()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) -> OsResult {
- let condvar = &mut *self.inner.get();
- condvar.destroy()
- }
-}
diff --git a/sgx_sync/src/sys/futex.rs b/sgx_sync/src/sys/futex.rs
index 44dce0ca..0fb732f6 100644
--- a/sgx_sync/src/sys/futex.rs
+++ b/sgx_sync/src/sys/futex.rs
@@ -18,7 +18,7 @@
#![allow(deprecated)]
use crate::futex::FutexClockId;
-use crate::lazy::SyncLazy;
+use crate::lazy_lock::LazyLock;
use crate::sys::ocall::{self, Timeout, Timespec};
use alloc::collections::VecDeque;
use alloc::sync::Arc;
@@ -45,7 +45,7 @@ impl Futex {
}
#[inline]
- pub fn wait(&self, expected: i32, timeout: Option<Duration>) -> OsResult {
+ pub fn wait(&self, expected: u32, timeout: Option<Duration>) -> OsResult {
let timeout =
timeout.map(|dur| Timeout::new(dur.into(), FutexClockId::Monotonic as u32, false));
self.wait_with_timeout(expected, timeout, Self::FUTEX_BITSET_MATCH_ANY)
@@ -53,7 +53,7 @@ impl Futex {
pub fn wait_bitset(
&self,
- expected: i32,
+ expected: u32,
timeout: Option<(Timespec, FutexClockId)>,
bitset: u32,
) -> OsResult {
@@ -61,7 +61,7 @@ impl Futex {
self.wait_with_timeout(expected, timeout, bitset)
}
- fn wait_with_timeout(&self, expected: i32, timeout: Option<Timeout>, bitset: u32) -> OsResult {
+ fn wait_with_timeout(&self, expected: u32, timeout: Option<Timeout>, bitset: u32) -> OsResult {
let (_, bucket) = FUTEX_BUCKETS.get_bucket(self);
let mut futex_bucket = bucket.lock();
@@ -102,7 +102,7 @@ impl Futex {
max_nwakes: usize,
new_futex: &Futex,
max_nrequeues: usize,
- expected: i32,
+ expected: u32,
) -> OsResult<usize> {
self.requeue_internal(max_nwakes, new_futex, max_nrequeues, Some(expected))
.map(|(nwakes, nrequeues)| nwakes + nrequeues)
@@ -124,7 +124,7 @@ impl Futex {
max_nwakes: usize,
new_futex: &Futex,
max_nrequeues: usize,
- expected: Option<i32>,
+ expected: Option<u32>,
) -> OsResult<(usize, usize)> {
if max_nwakes > i32::MAX as usize || max_nrequeues > i32::MAX as usize {
bail!(EINVAL);
@@ -178,8 +178,8 @@ impl Futex {
Ok(total_number)
}
- fn load_val(&self) -> i32 {
- unsafe { intrinsics::atomic_load(self.0 as *const i32) }
+ fn load_val(&self) -> u32 {
+ unsafe { intrinsics::atomic_load_seqcst(self.0 as *const u32) }
}
fn addr(&self) -> usize {
@@ -272,10 +272,10 @@ impl Bucket {
}
}
-static BUCKET_COUNT: SyncLazy<usize> =
- SyncLazy::new(|| ((1 << 8) * (trts::cpu_core_num())).next_power_of_two() as usize);
-static BUCKET_MASK: SyncLazy<usize> = SyncLazy::new(|| *BUCKET_COUNT - 1);
-static FUTEX_BUCKETS: SyncLazy<FutexBuckets> = SyncLazy::new(|| FutexBuckets::new(*BUCKET_COUNT));
+static BUCKET_COUNT: LazyLock<usize> =
+ LazyLock::new(|| ((1 << 8) * (trts::cpu_core_num())).next_power_of_two() as usize);
+static BUCKET_MASK: LazyLock<usize> = LazyLock::new(|| *BUCKET_COUNT - 1);
+static FUTEX_BUCKETS: LazyLock<FutexBuckets> = LazyLock::new(|| FutexBuckets::new(*BUCKET_COUNT));
#[derive(Debug)]
struct FutexBuckets {
diff --git a/sgx_sync/src/sys/mod.rs b/sgx_sync/src/sys/mod.rs
index d52ecc01..89b6ad2a 100644
--- a/sgx_sync/src/sys/mod.rs
+++ b/sgx_sync/src/sys/mod.rs
@@ -16,8 +16,7 @@
// under the License..
pub mod condvar;
+pub mod futex;
pub mod mutex;
+pub mod ocall;
pub mod rwlock;
-
-pub(crate) mod futex;
-pub(crate) mod ocall;
diff --git a/sgx_sync/src/sys/mutex.rs b/sgx_sync/src/sys/mutex.rs
index 56a076b5..85cc835d 100644
--- a/sgx_sync/src/sys/mutex.rs
+++ b/sgx_sync/src/sys/mutex.rs
@@ -15,15 +15,190 @@
// specific language governing permissions and limitations
// under the License..
+use crate::lazy_box::{LazyBox, LazyInit};
use crate::sys::ocall;
use alloc::boxed::Box;
use alloc::collections::LinkedList;
use core::cell::UnsafeCell;
+use core::mem;
use sgx_trts::sync::SpinMutex;
use sgx_trts::tcs::{self, TcsId};
use sgx_types::error::errno::{EBUSY, EPERM};
use sgx_types::error::OsResult;
+pub struct Mutex {
+ inner: UnsafeCell<MutexInner>,
+}
+
+pub type MovableMutex = LazyBox<Mutex>;
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+impl LazyInit for Mutex {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+
+ fn destroy(mutex: Box<Self>) {
+ // We're not allowed to pthread_mutex_destroy a locked mutex,
+ // so check first if it's unlocked.
+ if unsafe { !mutex.is_locked() } {
+ drop(mutex);
+ } else {
+ // The mutex is locked. This happens if a MutexGuard is leaked.
+ // In this case, we just leak the Mutex too.
+ mem::forget(mutex);
+ }
+ }
+
+ fn cancel_init(_: Box<Self>) {
+ // In this case, we can just drop it without any checks,
+ // since it cannot have been locked yet.
+ }
+}
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex {
+ inner: UnsafeCell::new(MutexInner::new(MutexControl::NonRecursive)),
+ }
+ }
+
+ #[allow(dead_code)]
+ pub fn new_with_control(control: MutexControl) -> Mutex {
+ Mutex {
+ inner: UnsafeCell::new(MutexInner::new(control)),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn lock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.lock()
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.unlock()
+ }
+
+ #[inline]
+ pub unsafe fn unlock_lazy(&self) -> OsResult<Option<TcsId>> {
+ let mutex = &mut *self.inner.get();
+ mutex.unlock_lazy()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.destroy()
+ }
+
+ #[inline]
+ unsafe fn is_locked(&self) -> bool {
+ let mutex = &*self.inner.get();
+ mutex.is_locked()
+ }
+}
+
+impl Drop for Mutex {
+ #[inline]
+ fn drop(&mut self) {
+ let r = unsafe { self.destroy() };
+ debug_assert_eq!(r, Ok(()));
+ }
+}
+
+pub struct ReentrantMutex {
+ inner: UnsafeCell<MutexInner>,
+}
+
+pub type MovableReentrantMutex = LazyBox<ReentrantMutex>;
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl LazyInit for ReentrantMutex {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+
+ fn destroy(mutex: Box<Self>) {
+ // We're not allowed to pthread_mutex_destroy a locked mutex,
+ // so check first if it's unlocked.
+ if unsafe { !mutex.is_locked() } {
+ drop(mutex);
+ } else {
+ // The mutex is locked. This happens if a MutexGuard is leaked.
+ // In this case, we just leak the Mutex too.
+ mem::forget(mutex);
+ }
+ }
+
+ fn cancel_init(_: Box<Self>) {
+ // In this case, we can just drop it without any checks,
+ // since it cannot have been locked yet.
+ }
+}
+
+impl ReentrantMutex {
+ pub const fn new() -> ReentrantMutex {
+ ReentrantMutex {
+ inner: UnsafeCell::new(MutexInner::new(MutexControl::Recursive)),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn lock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.lock()
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.unlock()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) -> OsResult {
+ let mutex = &mut *self.inner.get();
+ mutex.destroy()
+ }
+
+ #[inline]
+ unsafe fn is_locked(&self) -> bool {
+ let mutex = &*self.inner.get();
+ mutex.is_locked()
+ }
+}
+
+impl Drop for ReentrantMutex {
+ #[inline]
+ fn drop(&mut self) {
+ let r = unsafe { self.destroy() };
+ debug_assert_eq!(r, Ok(()));
+ }
+}
+
+struct MutexInner {
+ inner: SpinMutex<Inner>,
+}
+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MutexControl {
NonRecursive,
@@ -48,10 +223,6 @@ impl Inner {
}
}
-struct MutexInner {
- inner: SpinMutex<Inner>,
-}
-
impl MutexInner {
const fn new(control: MutexControl) -> MutexInner {
MutexInner {
@@ -160,93 +331,9 @@ impl MutexInner {
Err(EBUSY)
}
}
-}
-
-pub type MovableMutex = Box<Mutex>;
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-pub struct Mutex {
- inner: UnsafeCell<MutexInner>,
-}
-
-impl Mutex {
- pub const fn new() -> Mutex {
- Mutex {
- inner: UnsafeCell::new(MutexInner::new(MutexControl::NonRecursive)),
- }
- }
-
- pub fn new_with_control(control: MutexControl) -> Mutex {
- Mutex {
- inner: UnsafeCell::new(MutexInner::new(control)),
- }
- }
-
- #[inline]
- pub unsafe fn lock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.lock()
- }
-
- #[inline]
- pub unsafe fn try_lock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.try_lock()
- }
-
- #[inline]
- pub unsafe fn unlock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.unlock()
- }
-
- #[inline]
- pub unsafe fn unlock_lazy(&self) -> OsResult<Option<TcsId>> {
- let mutex = &mut *self.inner.get();
- mutex.unlock_lazy()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.destroy()
- }
-}
-
-pub struct ReentrantMutex {
- inner: UnsafeCell<MutexInner>,
-}
-
-impl ReentrantMutex {
- pub const fn new() -> ReentrantMutex {
- ReentrantMutex {
- inner: UnsafeCell::new(MutexInner::new(MutexControl::Recursive)),
- }
- }
-
- #[inline]
- pub unsafe fn lock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.lock()
- }
- #[inline]
- pub unsafe fn try_lock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.try_lock()
- }
-
- #[inline]
- pub unsafe fn unlock(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.unlock()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) -> OsResult {
- let mutex = &mut *self.inner.get();
- mutex.destroy()
+ unsafe fn is_locked(&self) -> bool {
+ let inner_guard = self.inner.lock();
+ inner_guard.owner.is_some() || !inner_guard.queue.is_empty()
}
}
diff --git a/sgx_sync/src/sys/ocall/mod.rs b/sgx_sync/src/sys/ocall/mod.rs
index 85f4419b..7683b717 100644
--- a/sgx_sync/src/sys/ocall/mod.rs
+++ b/sgx_sync/src/sys/ocall/mod.rs
@@ -388,7 +388,7 @@ pub fn thread_wait_event_ex(tcs: TcsId, timeout: Option<Timeout>) -> OsResult {
timeout.as_ref().map_or((ptr::null(), 0, 0), |timeout| {
let ts_ptr = &timeout.ts.t as *const timespec;
let clockid = timeout.clockid as i32;
- let absolute_time = if timeout.absolute_time { 1 } else { 0 };
+ let absolute_time = i32::from(timeout.absolute_time);
(ts_ptr, clockid, absolute_time)
});
diff --git a/sgx_sync/src/sys/rwlock.rs b/sgx_sync/src/sys/rwlock.rs
index 21c75fcf..5532eef9 100644
--- a/sgx_sync/src/sys/rwlock.rs
+++ b/sgx_sync/src/sys/rwlock.rs
@@ -15,16 +15,122 @@
// specific language governing permissions and limitations
// under the License..
+use crate::lazy_box::{LazyBox, LazyInit};
use crate::sys::ocall;
use alloc::boxed::Box;
use alloc::collections::LinkedList;
use alloc::vec::Vec;
use core::cell::UnsafeCell;
+use core::mem;
use sgx_trts::sync::SpinMutex;
use sgx_trts::tcs::{self, TcsId};
use sgx_types::error::errno::{EBUSY, EDEADLK, EPERM};
use sgx_types::error::OsResult;
+pub struct RwLock {
+ inner: UnsafeCell<RwLockInner>,
+}
+
+pub type MovableRwLock = LazyBox<RwLock>;
+
+unsafe impl Send for RwLock {}
+unsafe impl Sync for RwLock {}
+
+impl LazyInit for RwLock {
+ fn init() -> Box<Self> {
+ Box::new(Self::new())
+ }
+
+ fn destroy(rwlock: Box<Self>) {
+ // We're not allowed to pthread_rwlock_destroy a locked rwlock,
+ // so check first if it's unlocked.
+ if unsafe { rwlock.is_locked() } {
+ // The rwlock is locked. This happens if a RwLock{Read,Write}Guard is leaked.
+ // In this case, we just leak the RwLock too.
+ mem::forget(rwlock);
+ }
+ }
+
+ fn cancel_init(_: Box<Self>) {
+ // In this case, we can just drop it without any checks,
+ // since it cannot have been locked yet.
+ }
+}
+
+impl RwLock {
+ pub const fn new() -> RwLock {
+ RwLock {
+ inner: UnsafeCell::new(RwLockInner::new()),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.read()
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.try_read()
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.write()
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.try_write()
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.read_unlock()
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.write_unlock()
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ pub unsafe fn unlock(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.unlock()
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) -> OsResult {
+ let rwlock = &mut *self.inner.get();
+ rwlock.destroy()
+ }
+
+ #[inline]
+ unsafe fn is_locked(&self) -> bool {
+ let rwlock = &*self.inner.get();
+ rwlock.is_locked()
+ }
+}
+
+impl Drop for RwLock {
+ fn drop(&mut self) {
+ let r = unsafe { self.destroy() };
+ debug_assert_eq!(r, Ok(()));
+ }
+}
+
+struct RwLockInner {
+ inner: SpinMutex<Inner>,
+}
+
struct Inner {
reader_count: u32,
writer_waiting: u32,
@@ -45,10 +151,6 @@ impl Inner {
}
}
-struct RwLockInner {
- inner: SpinMutex<Inner>,
-}
-
impl RwLockInner {
const fn new() -> RwLockInner {
RwLockInner {
@@ -199,81 +301,19 @@ impl RwLockInner {
}
unsafe fn destroy(&mut self) -> OsResult {
- let inner_guard = self.inner.lock();
- if inner_guard.owner.is_some()
- || inner_guard.reader_count != 0
- || inner_guard.writer_waiting != 0
- || !inner_guard.reader_queue.is_empty()
- || !inner_guard.writer_queue.is_empty()
- {
+ if self.is_locked() {
Err(EBUSY)
} else {
Ok(())
}
}
-}
-
-pub type MovableRwLock = Box<RwLock>;
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-pub struct RwLock {
- inner: UnsafeCell<RwLockInner>,
-}
-
-impl RwLock {
- pub const fn new() -> RwLock {
- RwLock {
- inner: UnsafeCell::new(RwLockInner::new()),
- }
- }
-
- #[inline]
- pub unsafe fn read(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.read()
- }
-
- #[inline]
- pub unsafe fn try_read(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.try_read()
- }
- #[inline]
- pub unsafe fn write(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.write()
- }
-
- #[inline]
- pub unsafe fn try_write(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.try_write()
- }
-
- #[inline]
- pub unsafe fn read_unlock(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.read_unlock()
- }
-
- #[inline]
- pub unsafe fn write_unlock(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.write_unlock()
- }
-
- #[inline]
- pub unsafe fn unlock(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.unlock()
- }
-
- #[inline]
- pub unsafe fn destroy(&self) -> OsResult {
- let rwlock = &mut *self.inner.get();
- rwlock.destroy()
+ unsafe fn is_locked(&self) -> bool {
+ let inner_guard = self.inner.lock();
+ inner_guard.owner.is_some()
+ || inner_guard.reader_count != 0
+ || inner_guard.writer_waiting != 0
+ || !inner_guard.reader_queue.is_empty()
+ || !inner_guard.writer_queue.is_empty()
}
}
diff --git a/sgx_tdh/src/capi.rs b/sgx_tdh/src/capi.rs
index 9ec3d42a..db7c1a6b 100644
--- a/sgx_tdh/src/capi.rs
+++ b/sgx_tdh/src/capi.rs
@@ -35,7 +35,7 @@ pub unsafe extern "C" fn sgx_dh_init_session(
if session.is_null() {
return SgxStatus::InvalidParameter;
}
- if !(&*session).is_enclave_range() {
+ if !(*session).is_enclave_range() {
return SgxStatus::InvalidParameter;
}
@@ -69,7 +69,7 @@ pub unsafe extern "C" fn sgx_dh_responder_gen_msg1(
if session.is_null() || msg1.is_null() {
return SgxStatus::InvalidParameter;
}
- if !(&*session).is_enclave_range() {
+ if !(*session).is_enclave_range() {
return SgxStatus::InvalidParameter;
}
@@ -107,7 +107,7 @@ pub unsafe extern "C" fn sgx_dh_responder_proc_msg2(
{
return SgxStatus::InvalidParameter;
}
- if !(&*session).is_enclave_range() {
+ if !(*session).is_enclave_range() {
return SgxStatus::InvalidParameter;
}
@@ -190,7 +190,7 @@ where
return SgxStatus::InvalidParameter;
}
- if !(&*session).is_enclave_range() {
+ if !(*session).is_enclave_range() {
return SgxStatus::InvalidParameter;
}
@@ -260,7 +260,7 @@ where
if session.is_null() || msg3.is_null() || aek.is_null() || responder_identity.is_null() {
return SgxStatus::InvalidParameter;
}
- if !(&*session).is_enclave_range() {
+ if !(*session).is_enclave_range() {
return SgxStatus::InvalidParameter;
}
diff --git a/sgx_tests/cov/src/lib.rs b/sgx_tests/cov/src/lib.rs
index 61256476..eff7f227 100644
--- a/sgx_tests/cov/src/lib.rs
+++ b/sgx_tests/cov/src/lib.rs
@@ -31,9 +31,9 @@ use sgx_types::types::c_char;
use std::ffi::CStr;
use std::io::Write;
use std::io::{Error, ErrorKind};
-use std::lazy::SyncLazy;
use std::slice;
use std::string::String;
+use std::sync::LazyLock;
use std::sync::{Mutex, Once};
use std::untrusted::fs::{copy, File, OpenOptions};
use std::vec::Vec;
@@ -45,10 +45,10 @@ const GCOV_TAG_COUNTER_ARCS: u32 = 0x01a1_0000;
const GCOV_TAG_OBJECT_SUMMARY: u32 = 0xa100_0000;
const GCOV_TAG_PROGRAM_SUMMARY: u32 = 0xa300_0000;
-static GCDA_FILE: SyncLazy<Mutex<(Option<File>, u32)>> =
- SyncLazy::new(|| Mutex::new((None, u32::MAX)));
-static WROUT_FNS: SyncLazy<Mutex<Vec<extern "C" fn()>>> = SyncLazy::new(|| Mutex::new(Vec::new()));
-static RND: SyncLazy<Mutex<u32>> = SyncLazy::new(|| Mutex::new(0));
+static GCDA_FILE: LazyLock<Mutex<(Option<File>, u32)>> =
+ LazyLock::new(|| Mutex::new((None, u32::MAX)));
+static WROUT_FNS: LazyLock<Mutex<Vec<extern "C" fn()>>> = LazyLock::new(|| Mutex::new(Vec::new()));
+static RND: LazyLock<Mutex<u32>> = LazyLock::new(|| Mutex::new(0));
pub fn cov_writeout() {
for f in WROUT_FNS.lock().unwrap().iter() {
diff --git a/sgx_tests/utils/src/lib.rs b/sgx_tests/utils/src/lib.rs
index 15854d2b..8cd222a5 100644
--- a/sgx_tests/utils/src/lib.rs
+++ b/sgx_tests/utils/src/lib.rs
@@ -17,9 +17,7 @@
#![no_std]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
-#![feature(bench_black_box)]
#![feature(core_intrinsics)]
-#![feature(total_cmp)]
#[macro_use]
extern crate alloc;
diff --git a/sgx_tests/utils/src/stats.rs b/sgx_tests/utils/src/stats.rs
index f808eb8e..4fb17b8a 100644
--- a/sgx_tests/utils/src/stats.rs
+++ b/sgx_tests/utils/src/stats.rs
@@ -306,11 +306,7 @@ pub fn winsorize(samples: &mut [f64], pct: f64) {
let hundred = 100_f64;
let hi = percentile_of_sorted(&tmp, hundred - pct);
for samp in samples {
- if *samp > hi {
- *samp = hi
- } else if *samp < lo {
- *samp = lo
- }
+ *samp = (*samp).clamp(lo, hi);
}
}
#[inline]
diff --git a/sgx_trts/src/arch.rs b/sgx_trts/src/arch.rs
index a788248f..c1d695a5 100644
--- a/sgx_trts/src/arch.rs
+++ b/sgx_trts/src/arch.rs
@@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License..
+#![allow(clippy::enum_variant_names)]
+
use crate::edmm::{PageInfo, PageType};
use crate::tcs::tc;
use crate::version::*;
diff --git a/sgx_trts/src/call/ocalloc.rs b/sgx_trts/src/call/ocalloc.rs
index e4be53ab..34be0448 100644
--- a/sgx_trts/src/call/ocalloc.rs
+++ b/sgx_trts/src/call/ocalloc.rs
@@ -101,13 +101,13 @@ impl Drop for OcBuffer {
impl AsRef<[u8]> for OcBuffer {
fn as_ref(&self) -> &[u8] {
- &**self
+ self
}
}
impl AsMut<[u8]> for OcBuffer {
fn as_mut(&mut self) -> &mut [u8] {
- &mut **self
+ self
}
}
diff --git a/sgx_trts/src/capi.rs b/sgx_trts/src/capi.rs
index babc4e99..12f23921 100644
--- a/sgx_trts/src/capi.rs
+++ b/sgx_trts/src/capi.rs
@@ -53,11 +53,7 @@ pub unsafe extern "C" fn sgx_register_exception_handler(
pub unsafe extern "C" fn sgx_unregister_exception_handler(handle: *const c_void) -> i32 {
let handle = Handle::from_raw(handle as u64);
let result = unregister(handle);
- if result {
- 1
- } else {
- 0
- }
+ i32::from(result)
}
#[inline]
@@ -129,11 +125,7 @@ pub extern "C" fn sgx_get_rsrvmm_default_perm() -> u32 {
#[link_section = ".nipx"]
#[no_mangle]
pub extern "C" fn sgx_is_enclave_crashed() -> i32 {
- if enclave::state::is_crashed() {
- 1
- } else {
- 0
- }
+ i32::from(enclave::state::is_crashed())
}
#[inline]
@@ -169,21 +161,13 @@ pub extern "C" fn sgx_is_supported_edmm() -> bool {
#[inline]
#[no_mangle]
pub unsafe extern "C" fn sgx_is_within_enclave(p: *const u8, len: usize) -> i32 {
- if enclave::is_within_enclave(p, len) {
- 1
- } else {
- 0
- }
+ i32::from(enclave::is_within_enclave(p, len))
}
#[inline]
#[no_mangle]
pub unsafe extern "C" fn sgx_is_outside_enclave(p: *const u8, len: usize) -> i32 {
- if enclave::is_within_host(p, len) {
- 1
- } else {
- 0
- }
+ i32::from(enclave::is_within_host(p, len))
}
#[inline]
@@ -304,11 +288,7 @@ pub unsafe extern "C" fn sgx_thread_self() -> sgx_thread_t {
#[inline]
#[no_mangle]
pub unsafe extern "C" fn sgx_thread_equal(a: sgx_thread_t, b: sgx_thread_t) -> i32 {
- if a == b {
- 1
- } else {
- 0
- }
+ i32::from(a == b)
}
#[cfg(not(feature = "hyper"))]
diff --git a/sgx_trts/src/elf/control_flow.rs b/sgx_trts/src/elf/control_flow.rs
index ba84d608..887ff67d 100644
--- a/sgx_trts/src/elf/control_flow.rs
+++ b/sgx_trts/src/elf/control_flow.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License..
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ControlFlow<C, B> {
Continue(C),
Break(B),
diff --git a/sgx_trts/src/elf/header.rs b/sgx_trts/src/elf/header.rs
index a5a5d821..91011fa2 100644
--- a/sgx_trts/src/elf/header.rs
+++ b/sgx_trts/src/elf/header.rs
@@ -428,7 +428,7 @@ impl fmt::Debug for Machine_ {
}
}
-#[allow(non_camel_case_types)]
+#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Machine {
None,
diff --git a/sgx_trts/src/elf/program.rs b/sgx_trts/src/elf/program.rs
index eeebbc13..8907c9f5 100644
--- a/sgx_trts/src/elf/program.rs
+++ b/sgx_trts/src/elf/program.rs
@@ -236,7 +236,7 @@ macro_rules! ph_impl {
pub fn raw_data<'a>(&self, elf_file: &ElfFile<'a>) -> &'a [u8] {
assert!(match self.get_type() {
- Ok(typ) => typ != Type::Null,
+ Ok(_) => self.type_.0 != 0,
Err(_) => false,
});
unsafe {
diff --git a/sgx_trts/src/elf/slice.rs b/sgx_trts/src/elf/slice.rs
index 3807bde5..59defb9d 100644
--- a/sgx_trts/src/elf/slice.rs
+++ b/sgx_trts/src/elf/slice.rs
@@ -46,6 +46,7 @@ pub trait AsSlice<T> {
}
impl<T> AsSlice<T> for [T] {
+ #[inline(always)]
fn as_slice(&self) -> Slice<T> {
Slice { rust: self }
}
diff --git a/sgx_trts/src/enclave/parse.rs b/sgx_trts/src/enclave/parse.rs
index 7ded28dc..f1fe6175 100644
--- a/sgx_trts/src/enclave/parse.rs
+++ b/sgx_trts/src/enclave/parse.rs
@@ -317,21 +317,20 @@ unsafe fn relocate_elf_rela(elf: &ElfFile, sym_offset: u64, rel_offset: u64, rel
}
sections::R_X86_64_GLOB_DAT | sections::R_X86_64_JMP_SLOT | sections::R_X86_64_64 => {
if let Some(sym) = get_sym(sym_table, rel.get_symbol_table_index()) {
- *reloc_addr = elf.input.as_slice().as_ptr() as u64
- + sym.value()
- + rel.get_addend() as u64;
+ *reloc_addr =
+ elf.input.as_slice().as_ptr() as u64 + sym.value() + rel.get_addend();
}
}
sections::R_X86_64_DTPMOD64 => *reloc_addr = 1_u64,
sections::R_X86_64_DTPOFF64 => {
if let Some(sym) = get_sym(sym_table, rel.get_symbol_table_index()) {
- *reloc_addr = sym.value() + rel.get_addend() as u64;
+ *reloc_addr = sym.value() + rel.get_addend();
}
}
sections::R_X86_64_TPOFF64 => {
if let Some(sym) = get_sym(sym_table, rel.get_symbol_table_index()) {
if let Some(tls_size) = tls_size(elf) {
- *reloc_addr = sym.value() + rel.get_addend() as u64 - tls_size;
+ *reloc_addr = sym.value() + rel.get_addend() - tls_size;
}
}
}
diff --git a/sgx_trts/src/enclave/state.rs b/sgx_trts/src/enclave/state.rs
index 5f65477e..7bfcdf4c 100644
--- a/sgx_trts/src/enclave/state.rs
+++ b/sgx_trts/src/enclave/state.rs
@@ -77,8 +77,11 @@ pub fn lock_state() -> State {
const IN_PROGRESS: u32 = 1;
let state = unsafe {
- let (state, _) =
- core::intrinsics::atomic_cxchg(&mut ENCLAVE_STATE, NOT_STARTED, IN_PROGRESS);
+ let (state, _) = core::intrinsics::atomic_cxchg_seqcst_seqcst(
+ &mut ENCLAVE_STATE,
+ NOT_STARTED,
+ IN_PROGRESS,
+ );
state
};
match state {
diff --git a/sgx_trts/src/feature/sys.rs b/sgx_trts/src/feature/sys.rs
index 61404f7b..537b5a5b 100644
--- a/sgx_trts/src/feature/sys.rs
+++ b/sgx_trts/src/feature/sys.rs
@@ -73,7 +73,8 @@ impl SystemFeatures {
#[cfg(feature = "hyper")]
{
use crate::inst::GlobalHyper;
- GlobalHyper::get_mut().set_msbuf_info(&features.msbuf_info)?;
+ let msbuf_info = ptr::addr_of!(features.msbuf_info);
+ GlobalHyper::get_mut().set_msbuf_info(&ptr::read_unaligned(msbuf_info))?;
}
Ok(features)
@@ -85,7 +86,7 @@ impl SystemFeatures {
cmp::min(self.size, mem::size_of::<Self>())
} else {
let b = self as *const _ as usize;
- let p = &self.size as *const _ as usize;
+ let p = ptr::addr_of!(self.size) as usize;
p - b
};
diff --git a/sgx_trts/src/inst/hyper/inst.rs b/sgx_trts/src/inst/hyper/inst.rs
index ba5ffa80..be4c2da5 100644
--- a/sgx_trts/src/inst/hyper/inst.rs
+++ b/sgx_trts/src/inst/hyper/inst.rs
@@ -15,6 +15,8 @@
// specific language governing permissions and limitations
// under the License..
+#![allow(clippy::enum_variant_names)]
+
use crate::arch::Secinfo;
use crate::inst::INVALID_LEAF;
use crate::se::{
diff --git a/sgx_trts/src/inst/sim/tls/gnu.rs b/sgx_trts/src/inst/sim/tls/gnu.rs
index 11f156bf..357381a0 100644
--- a/sgx_trts/src/inst/sim/tls/gnu.rs
+++ b/sgx_trts/src/inst/sim/tls/gnu.rs
@@ -25,6 +25,7 @@ pub union Dtv {
}
#[repr(C)]
+#[derive(Clone, Copy, Debug)]
struct Pointer {
value: usize,
is_static: i32,
diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs
index 9bfabe7c..2a1babfc 100644
--- a/sgx_trts/src/lib.rs
+++ b/sgx_trts/src/lib.rs
@@ -20,24 +20,20 @@
#![no_std]
#![cfg_attr(target_vendor = "teaclave", feature(rustc_private))]
#![feature(allocator_api)]
-#![feature(atomic_from_mut)]
+#![feature(const_trait_impl)]
#![feature(core_intrinsics)]
#![feature(drain_filter)]
-#![feature(linkage)]
+#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(negative_impls)]
+#![feature(never_type)]
#![feature(nonnull_slice_from_raw_parts)]
-#![feature(once_cell)]
#![feature(ptr_internals)]
#![feature(thread_local)]
-#![feature(untagged_unions)]
#![cfg_attr(feature = "sim", feature(unchecked_math))]
-#![allow(clippy::enum_variant_names)]
#![allow(clippy::missing_safety_doc)]
-#![allow(clippy::upper_case_acronyms)]
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-#![allow(unaligned_references)]
#[cfg(all(feature = "sim", feature = "hyper"))]
compile_error!("feature \"sim\" and feature \"hyper\" cannot be enabled at the same time");
diff --git a/sgx_trts/src/sync/lazy.rs b/sgx_trts/src/sync/lazy.rs
new file mode 100644
index 00000000..10aa1b2b
--- /dev/null
+++ b/sgx_trts/src/sync/lazy.rs
@@ -0,0 +1,257 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License..
+
+use core::cell::{Cell, UnsafeCell};
+use core::fmt;
+use core::mem;
+use core::ops::Deref;
+
+/// A cell which can be written to only once.
+///
+/// Unlike `RefCell`, a `OnceCell` only provides shared `&T` references to its value.
+/// Unlike `Cell`, a `OnceCell` doesn't require copying or replacing the value to access it.
+///
+pub struct OnceCell<T> {
+ // Invariant: written to at most once.
+ inner: UnsafeCell<Option<T>>,
+}
+
+impl<T> Default for OnceCell<T> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for OnceCell<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.get() {
+ Some(v) => f.debug_tuple("OnceCell").field(v).finish(),
+ None => f.write_str("OnceCell(Uninit)"),
+ }
+ }
+}
+
+impl<T: Clone> Clone for OnceCell<T> {
+ fn clone(&self) -> OnceCell<T> {
+ let res = OnceCell::new();
+ if let Some(value) = self.get() {
+ match res.set(value.clone()) {
+ Ok(()) => (),
+ Err(_) => unreachable!(),
+ }
+ }
+ res
+ }
+}
+
+impl<T: PartialEq> PartialEq for OnceCell<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.get() == other.get()
+ }
+}
+
+impl<T: Eq> Eq for OnceCell<T> {}
+
+impl<T> const From<T> for OnceCell<T> {
+ /// Creates a new `OnceCell<T>` which already contains the given `value`.
+ fn from(value: T) -> Self {
+ OnceCell {
+ inner: UnsafeCell::new(Some(value)),
+ }
+ }
+}
+
+impl<T> OnceCell<T> {
+ /// Creates a new empty cell.
+ #[must_use]
+ pub const fn new() -> OnceCell<T> {
+ OnceCell {
+ inner: UnsafeCell::new(None),
+ }
+ }
+
+ /// Gets the reference to the underlying value.
+ ///
+ /// Returns `None` if the cell is empty.
+ pub fn get(&self) -> Option<&T> {
+ // SAFETY: Safe due to `inner`'s invariant
+ unsafe { &*self.inner.get() }.as_ref()
+ }
+
+ /// Gets the mutable reference to the underlying value.
+ ///
+ /// Returns `None` if the cell is empty.
+ pub fn get_mut(&mut self) -> Option<&mut T> {
+ self.inner.get_mut().as_mut()
+ }
+
+ /// Sets the contents of the cell to `value`.
+ ///
+ /// # Errors
+ ///
+ /// This method returns `Ok(())` if the cell was empty and `Err(value)` if
+ /// it was full.
+ ///
+ pub fn set(&self, value: T) -> Result<(), T> {
+ // SAFETY: Safe because we cannot have overlapping mutable borrows
+ let slot = unsafe { &*self.inner.get() };
+ if slot.is_some() {
+ return Err(value);
+ }
+
+ // SAFETY: This is the only place where we set the slot, no races
+ // due to reentrancy/concurrency are possible, and we've
+ // checked that slot is currently `None`, so this write
+ // maintains the `inner`'s invariant.
+ let slot = unsafe { &mut *self.inner.get() };
+ *slot = Some(value);
+ Ok(())
+ }
+
+ /// Gets the contents of the cell, initializing it with `f`
+ /// if the cell was empty.
+ ///
+ /// # Panics
+ ///
+ /// If `f` panics, the panic is propagated to the caller, and the cell
+ /// remains uninitialized.
+ ///
+ /// It is an error to reentrantly initialize the cell from `f`. Doing
+ /// so results in a panic.
+ ///
+ pub fn get_or_init<F>(&self, f: F) -> &T
+ where
+ F: FnOnce() -> T,
+ {
+ match self.get_or_try_init(|| Ok::<T, !>(f())) {
+ Ok(val) => val,
+ Err(_) => unreachable!(),
+ }
+ }
+
+ /// Gets the contents of the cell, initializing it with `f` if
+ /// the cell was empty. If the cell was empty and `f` failed, an
+ /// error is returned.
+ ///
+ /// # Panics
+ ///
+ /// If `f` panics, the panic is propagated to the caller, and the cell
+ /// remains uninitialized.
+ ///
+ /// It is an error to reentrantly initialize the cell from `f`. Doing
+ /// so results in a panic.
+ ///
+ pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
+ where
+ F: FnOnce() -> Result<T, E>,
+ {
+ if let Some(val) = self.get() {
+ return Ok(val);
+ }
+ /// Avoid inlining the initialization closure into the common path that fetches
+ /// the already initialized value
+ #[cold]
+ fn outlined_call<F, T, E>(f: F) -> Result<T, E>
+ where
+ F: FnOnce() -> Result<T, E>,
+ {
+ f()
+ }
+ let val = outlined_call(f)?;
+ // Note that *some* forms of reentrant initialization might lead to
+ // UB (see `reentrant_init` test). I believe that just removing this
+ // `assert`, while keeping `set/get` would be sound, but it seems
+ // better to panic, rather than to silently use an old value.
+ assert!(self.set(val).is_ok(), "reentrant init");
+ Ok(self.get().unwrap())
+ }
+
+ /// Consumes the cell, returning the wrapped value.
+ ///
+ /// Returns `None` if the cell was empty.
+ ///
+ pub fn into_inner(self) -> Option<T> {
+ // Because `into_inner` takes `self` by value, the compiler statically verifies
+ // that it is not currently borrowed. So it is safe to move out `Option<T>`.
+ self.inner.into_inner()
+ }
+
+ /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state.
+ ///
+ /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized.
+ ///
+ /// Safety is guaranteed by requiring a mutable reference.
+ ///
+ pub fn take(&mut self) -> Option<T> {
+ mem::take(self).into_inner()
+ }
+}
+
+/// A value which is initialized on the first access.
+///
+pub struct Lazy<T, F = fn() -> T> {
+ cell: OnceCell<T>,
+ init: Cell<Option<F>>,
+}
+
+impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Lazy")
+ .field("cell", &self.cell)
+ .field("init", &"..")
+ .finish()
+ }
+}
+
+impl<T, F> Lazy<T, F> {
+ /// Creates a new lazy value with the given initializing function.
+ ///
+ pub const fn new(init: F) -> Lazy<T, F> {
+ Lazy {
+ cell: OnceCell::new(),
+ init: Cell::new(Some(init)),
+ }
+ }
+}
+
+impl<T, F: FnOnce() -> T> Lazy<T, F> {
+ /// Forces the evaluation of this lazy value and returns a reference to
+ /// the result.
+ ///
+ /// This is equivalent to the `Deref` impl, but is explicit.
+ ///
+ pub fn force(this: &Lazy<T, F>) -> &T {
+ this.cell.get_or_init(|| match this.init.take() {
+ Some(f) => f(),
+ None => panic!("`Lazy` instance has previously been poisoned"),
+ })
+ }
+}
+
+impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ Lazy::force(self)
+ }
+}
+
+impl<T: Default> Default for Lazy<T> {
+ /// Creates a new lazy value using `Default` as the initializing function.
+ fn default() -> Lazy<T> {
+ Lazy::new(T::default)
+ }
+}
diff --git a/sgx_trts/src/sync/mod.rs b/sgx_trts/src/sync/mod.rs
index 1644daf4..92193b80 100644
--- a/sgx_trts/src/sync/mod.rs
+++ b/sgx_trts/src/sync/mod.rs
@@ -15,12 +15,16 @@
// specific language governing permissions and limitations
// under the License..
+mod lazy;
mod lock_api;
mod mutex;
mod once;
mod rwlock;
+#[allow(unused_imports)]
+pub(crate) use lazy::{Lazy, OnceCell};
+pub(crate) use once::Once;
+
pub use lock_api::{RawMutex, RawRwLock};
pub use mutex::{SpinMutex, SpinMutexGuard};
-pub(crate) use once::Once;
pub use rwlock::{SpinRwLock, SpinRwLockReadGuard, SpinRwLockWriteGuard};
diff --git a/sgx_trts/src/sync/mutex.rs b/sgx_trts/src/sync/mutex.rs
index 4d3f0d96..0b909ac8 100644
--- a/sgx_trts/src/sync/mutex.rs
+++ b/sgx_trts/src/sync/mutex.rs
@@ -118,7 +118,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for SpinMutex<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_lock() {
Some(guard) => write!(f, "SpinMutex {{ value: ")
- .and_then(|()| (&*guard).fmt(f))
+ .and_then(|()| (*guard).fmt(f))
.and_then(|()| write!(f, "}}")),
None => write!(f, "SpinMutex {{ <locked> }}"),
}
diff --git a/sgx_trts/src/sync/rwlock.rs b/sgx_trts/src/sync/rwlock.rs
index 1dbded74..5f4d9ccc 100644
--- a/sgx_trts/src/sync/rwlock.rs
+++ b/sgx_trts/src/sync/rwlock.rs
@@ -155,7 +155,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for SpinRwLock<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.try_read() {
Some(guard) => write!(f, "SpinRwLock {{ value: ")
- .and_then(|()| (&*guard).fmt(f))
+ .and_then(|()| (*guard).fmt(f))
.and_then(|()| write!(f, "}}")),
None => write!(f, "SpinRwLock {{ <locked> }}"),
}
diff --git a/sgx_trts/src/tcs/list.rs b/sgx_trts/src/tcs/list.rs
index c83913e5..2111ec19 100644
--- a/sgx_trts/src/tcs/list.rs
+++ b/sgx_trts/src/tcs/list.rs
@@ -17,10 +17,10 @@
use crate::arch::Tcs;
use crate::rand::Rng;
+use crate::sync::OnceCell;
use crate::sync::SpinMutex;
use alloc::collections::linked_list::{Iter, LinkedList};
use core::fmt;
-use core::lazy::OnceCell;
use core::num::NonZeroUsize;
use core::ptr::NonNull;
diff --git a/sgx_trts/src/tcs/tc.rs b/sgx_trts/src/tcs/tc.rs
index cff18f8d..09e4bcfc 100644
--- a/sgx_trts/src/tcs/tc.rs
+++ b/sgx_trts/src/tcs/tc.rs
@@ -20,8 +20,8 @@ use crate::enclave::parse;
use crate::error;
use crate::feature::SysFeatures;
use crate::rand::Rng;
+use crate::sync::OnceCell;
use core::convert::From;
-use core::lazy::OnceCell;
use core::mem;
use core::num::NonZeroUsize;
use core::ptr;
diff --git a/sgx_trts/src/thread/tls/bitset.rs b/sgx_trts/src/thread/tls/bitset.rs
index 7a93ed8c..7441dea4 100644
--- a/sgx_trts/src/thread/tls/bitset.rs
+++ b/sgx_trts/src/thread/tls/bitset.rs
@@ -50,7 +50,8 @@ impl Bitset {
self.0[hi].fetch_and(!lo, Ordering::Relaxed);
}
- // Sets any unset bit. Not atomic. Returns `None` if all bits were observed to be set.
+ /// Sets any unset bit. Not atomic. Returns `None` if all bits were
+ /// observed to be set.
pub fn set(&self) -> Option<usize> {
'elems: for (idx, elem) in self.0.iter().enumerate() {
let mut current = elem.load(Ordering::Relaxed);
diff --git a/sgx_trts/src/thread/tls/mod.rs b/sgx_trts/src/thread/tls/mod.rs
index 8d4802e4..cb77ef5d 100644
--- a/sgx_trts/src/thread/tls/mod.rs
+++ b/sgx_trts/src/thread/tls/mod.rs
@@ -160,7 +160,9 @@ impl<'a> !Send for ActiveTls<'a> {}
impl<'a> Drop for ActiveTls<'a> {
fn drop(&mut self) {
- let value_with_destructor = |storage: &'a StorageNode| {
+ fn value_with_destructor(
+ storage: &StorageNode,
+ ) -> Option<(&Cell<*mut u8>, unsafe extern "C" fn(*mut u8))> {
let index = storage.key.to_index();
if TLS_KEY_IN_USE.get(index) {
let ptr = TLS_DESTRUCTOR[index].load(Ordering::Relaxed);
@@ -169,13 +171,13 @@ impl<'a> Drop for ActiveTls<'a> {
} else {
None
}
- };
+ }
let tls_storage = self.tls.data.borrow();
let mut any_non_null_dtor = true;
while any_non_null_dtor {
any_non_null_dtor = false;
- for (value, dtor) in tls_storage.iter().filter_map(&value_with_destructor) {
+ for (value, dtor) in tls_storage.iter().filter_map(value_with_destructor) {
let value = value.replace(ptr::null_mut());
if !value.is_null() {
any_non_null_dtor = true;
diff --git a/sgx_trts/src/veh/exception.rs b/sgx_trts/src/veh/exception.rs
index 0c8c82fd..92d5fb85 100644
--- a/sgx_trts/src/veh/exception.rs
+++ b/sgx_trts/src/veh/exception.rs
@@ -26,6 +26,7 @@ use crate::veh::MAX_REGISTER_COUNT;
use crate::veh::{ExceptionHandler, ExceptionInfo, ExceptionType, ExceptionVector, HandleResult};
use core::convert::TryFrom;
use core::mem;
+use core::mem::MaybeUninit;
use sgx_types::error::{SgxResult, SgxStatus};
macro_rules! try_error {
@@ -232,10 +233,13 @@ extern "C" fn internal_handle(info: &mut ExceptionInfo) {
error::abort();
}
- let mut handlers: [ExceptionHandler; MAX_REGISTER_COUNT] = unsafe { mem::zeroed() };
+ let mut handlers: [MaybeUninit<ExceptionHandler>; MAX_REGISTER_COUNT] =
+ MaybeUninit::uninit_array();
+
+ // let mut handlers: [ExceptionHandler; MAX_REGISTER_COUNT] = unsafe { mem::zeroed() };
let mut len = 0_usize;
for (i, f) in list_guard.iter().enumerate().take(MAX_REGISTER_COUNT) {
- handlers[i] = f;
+ handlers[i].write(f);
len += 1;
}
(handlers, len)
@@ -245,7 +249,7 @@ extern "C" fn internal_handle(info: &mut ExceptionInfo) {
let mut result = HandleResult::Search;
for f in &handlers[..len] {
- result = (*f)(info);
+ result = (unsafe { f.assume_init_ref() })(info);
if result == HandleResult::Execution {
break;
}
diff --git a/sgx_trts/src/veh/list.rs b/sgx_trts/src/veh/list.rs
index ffbafeff..2cc2eb76 100644
--- a/sgx_trts/src/veh/list.rs
+++ b/sgx_trts/src/veh/list.rs
@@ -33,11 +33,11 @@
// under the License..
use crate::rand::Rng;
+use crate::sync::OnceCell;
use crate::sync::SpinMutex;
use crate::veh::{ExceptionHandler, Handle};
use alloc::collections::linked_list::{Iter, LinkedList};
use core::fmt;
-use core::lazy::OnceCell;
use core::mem;
use core::num::NonZeroUsize;
diff --git a/sgx_trts/src/xsave.rs b/sgx_trts/src/xsave.rs
index 1e4adb58..6dd6d597 100644
--- a/sgx_trts/src/xsave.rs
+++ b/sgx_trts/src/xsave.rs
@@ -34,11 +34,7 @@ pub fn get_xfrm() -> u64 {
}
}
- let enbaled = if xfrm == types::XFRM_LEGACY {
- 0_i32
- } else {
- 1_i32
- };
+ let enbaled = i32::from(xfrm != types::XFRM_LEGACY);
unsafe {
set_xsave_enabled(enbaled);
}
diff --git a/sgx_tse/src/capi.rs b/sgx_tse/src/capi.rs
index 62593699..617a731f 100644
--- a/sgx_tse/src/capi.rs
+++ b/sgx_tse/src/capi.rs
@@ -52,7 +52,7 @@ pub unsafe extern "C" fn sgx_verify_report(report: *const Report) -> SgxStatus {
return SgxStatus::InvalidParameter;
}
- match (&*report).verify() {
+ match (*report).verify() {
Ok(_) => SgxStatus::Success,
Err(e) => e,
}
@@ -84,7 +84,7 @@ pub unsafe extern "C" fn sgx_get_key(
return SgxStatus::InvalidParameter;
}
- match (&*key_request).get_key() {
+ match (*key_request).get_key() {
Ok(k) => {
*key = k;
SgxStatus::Success
@@ -100,7 +100,7 @@ pub unsafe extern "C" fn sgx_verify_report2(report_mac: *const Report2Mac) -> Sg
return SgxStatus::InvalidParameter;
}
- match (&*report_mac).verify() {
+ match (*report_mac).verify() {
Ok(_) => SgxStatus::Success,
Err(e) => e,
}
diff --git a/sgx_tse/src/se.rs b/sgx_tse/src/se.rs
index f92f2034..af55bb10 100644
--- a/sgx_tse/src/se.rs
+++ b/sgx_tse/src/se.rs
@@ -188,7 +188,7 @@ impl LAv2ProtoSpec {
let mut to = 0_i32;
for i in 1..(self.ts_count() + 1) as usize {
- let size = (1 << (self.target_spec[i] & 0xF)) as i32;
+ let size = 1 << (self.target_spec[i] & 0xF);
to += size - 1;
to &= -size;
diff --git a/sgx_tstd/src/alloc.rs b/sgx_tstd/src/alloc.rs
index c07dea5a..6d6569d0 100644
--- a/sgx_tstd/src/alloc.rs
+++ b/sgx_tstd/src/alloc.rs
@@ -59,8 +59,6 @@
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! ```rust,ignore (demonstrates crates.io usage)
-//! extern crate jemallocator;
-//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
@@ -93,6 +91,20 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(alloc_error_hook)]
+///
+/// use std::alloc::{Layout, set_alloc_error_hook};
+///
+/// fn custom_alloc_error_hook(layout: Layout) {
+/// panic!("memory allocation of {} bytes failed", layout.size());
+/// }
+///
+/// set_alloc_error_hook(custom_alloc_error_hook);
+/// ```
pub fn set_alloc_error_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst);
}
@@ -108,7 +120,18 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
}
fn default_alloc_error_hook(layout: Layout) {
- rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
+ extern "Rust" {
+ // This symbol is emitted by rustc next to __rust_alloc_error_handler.
+ // Its value depends on the -Zoom={panic,abort} compiler option.
+ static __rust_alloc_error_handler_should_panic: u8;
+ }
+
+ #[allow(unused_unsafe)]
+ if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
+ panic!("memory allocation of {} bytes failed\n", layout.size());
+ } else {
+ rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
+ }
}
#[doc(hidden)]
diff --git a/sgx_tstd/src/backtrace.rs b/sgx_tstd/src/backtrace.rs
index 12e65edf..5f6266d6 100644
--- a/sgx_tstd/src/backtrace.rs
+++ b/sgx_tstd/src/backtrace.rs
@@ -26,19 +26,13 @@
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
-//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
-//! > can learn more about its status in the [tracking issue].
-//!
-//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
-//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
-//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! are provided about the exact accuracy of a backtrace. Instruction pointers,
//! symbol names, filenames, line numbers, etc, may all be incorrect when
-//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
-//! are always welcome to indicate areas of improvement!
+//! reported. Accuracy is attempted on a best-effort basis, however, any bug
+//! reports are always welcome to indicate areas of improvement!
//!
//! For most platforms a backtrace with a filename/line number requires that
//! programs be compiled with debug information. Without debug information
@@ -303,7 +297,7 @@ impl Backtrace {
// `ip`
fn create(ip: usize) -> Backtrace {
// SAFETY: We don't attempt to lock this reentrantly.
- let _lock = unsafe { lock() };
+ let _lock = lock();
let mut frames = Vec::new();
let mut actual_start = None;
unsafe {
@@ -444,8 +438,7 @@ impl Capture {
// Use the global backtrace lock to synchronize this as it's a
// requirement of the `backtrace` crate, and then actually resolve
// everything.
- // SAFETY: We don't attempt to lock this reentrantly.
- let _lock = unsafe { lock() };
+ let _lock = lock();
for frame in self.frames.iter_mut() {
let symbols = &mut frame.symbols;
let frame = match &frame.frame {
diff --git a/sgx_tstd/src/backtrace/tests.rs b/sgx_tstd/src/backtrace/tests.rs
index 07f67657..cc8dc5f6 100644
--- a/sgx_tstd/src/backtrace/tests.rs
+++ b/sgx_tstd/src/backtrace/tests.rs
@@ -76,10 +76,10 @@ fn test_debug() {
\n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\
\n]";
- assert_eq!(format!("{:#?}", backtrace), expected);
+ assert_eq!(format!("{backtrace:#?}"), expected);
// Format the backtrace a second time, just to make sure lazily resolved state is stable
- assert_eq!(format!("{:#?}", backtrace), expected);
+ assert_eq!(format!("{backtrace:#?}"), expected);
}
#[test_case]
@@ -110,5 +110,5 @@ fn test_frames() {
let mut iter = frames.iter().zip(expected.iter());
- assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e));
+ assert!(iter.all(|(f, e)| format!("{f:#?}") == *e));
}
diff --git a/sgx_tstd/src/collections/hash/benches/map.rs b/sgx_tstd/src/collections/hash/benches/map.rs
index 79fe4e31..932c3686 100644
--- a/sgx_tstd/src/collections/hash/benches/map.rs
+++ b/sgx_tstd/src/collections/hash/benches/map.rs
@@ -60,12 +60,10 @@ fn find_existing(b: &mut Bencher) {
m.insert(i, i);
}
- let mut k = 1;
b.iter(|| {
for i in 1..1001 {
m.contains_key(&i);
}
- k += 1;
});
}
diff --git a/sgx_tstd/src/collections/hash/map.rs b/sgx_tstd/src/collections/hash/map.rs
index 3eb7f883..3f7580f9 100644
--- a/sgx_tstd/src/collections/hash/map.rs
+++ b/sgx_tstd/src/collections/hash/map.rs
@@ -26,10 +26,11 @@ use crate::borrow::Borrow;
use crate::cell::Cell;
use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind;
+use crate::error::Error;
use crate::fmt::{self, Debug};
#[allow(deprecated)]
use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
-use crate::iter::{FromIterator, FusedIterator};
+use crate::iter::FusedIterator;
use crate::ops::Index;
use crate::sys;
@@ -71,7 +72,8 @@ use crate::sys;
/// the [`Eq`] trait, changes while it is in the map. This is normally only
/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
/// The behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect results,
+/// be encapsulated to the `HashMap` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
/// aborts, memory leaks, and non-termination.
///
/// The hash table implementation is a Rust port of Google's [SwissTable].
@@ -126,8 +128,8 @@ use crate::sys;
/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"];
/// for &book in &to_find {
/// match book_reviews.get(book) {
-/// Some(review) => println!("{}: {}", book, review),
-/// None => println!("{} is unreviewed.", book)
+/// Some(review) => println!("{book}: {review}"),
+/// None => println!("{book} is unreviewed.")
/// }
/// }
///
@@ -136,7 +138,7 @@ use crate::sys;
///
/// // Iterate over everything.
/// for (book, review) in &book_reviews {
-/// println!("{}: \"{}\"", book, review);
+/// println!("{book}: \"{review}\"");
/// }
/// ```
///
@@ -153,7 +155,7 @@ use crate::sys;
/// ]);
/// ```
///
-/// `HashMap` implements an [`Entry API`](#method.entry), which allows
+/// `HashMap` implements an [`Entry` API](#method.entry), which allows
/// for complex methods of getting, setting, updating and removing keys and
/// their values:
///
@@ -180,6 +182,9 @@ use crate::sys;
/// // update a key, guarding against the key possibly not being set
/// let stat = player_stats.entry("attack").or_insert(100);
/// *stat += random_stat_buff();
+///
+/// // modify an entry before an insert with in-place mutation
+/// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100);
/// ```
///
/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`].
@@ -216,7 +221,7 @@ use crate::sys;
///
/// // Use derived implementation to print the status of the vikings.
/// for (viking, health) in &vikings {
-/// println!("{:?} has {} hp", viking, health);
+/// println!("{viking:?} has {health} hp");
/// }
/// ```
@@ -244,10 +249,11 @@ impl<K, V> HashMap<K, V, RandomState> {
Default::default()
}
- /// Creates an empty `HashMap` with the specified capacity.
+ /// Creates an empty `HashMap` with at least the specified capacity.
///
/// The hash map will be able to hold at least `capacity` elements without
- /// reallocating. If `capacity` is 0, the hash map will not allocate.
+ /// reallocating. This method is allowed to allocate for more elements than
+ /// `capacity`. If `capacity` is 0, the hash set will not allocate.
///
/// # Examples
///
@@ -287,22 +293,23 @@ impl<K, V, S> HashMap<K, V, S> {
/// map.insert(1, 2);
/// ```
#[inline]
- pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
+ pub const fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
HashMap { base: base::HashMap::with_hasher(hash_builder) }
}
- /// Creates an empty `HashMap` with the specified capacity, using `hash_builder`
- /// to hash the keys.
+ /// Creates an empty `HashMap` with at least the specified capacity, using
+ /// `hasher` to hash the keys.
///
/// The hash map will be able to hold at least `capacity` elements without
- /// reallocating. If `capacity` is 0, the hash map will not allocate.
+ /// reallocating. This method is allowed to allocate for more elements than
+ /// `capacity`. If `capacity` is 0, the hash map will not allocate.
///
- /// Warning: `hash_builder` is normally randomly generated, and
+ /// Warning: `hasher` is normally randomly generated, and
/// is designed to allow HashMaps to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
- /// The `hash_builder` passed should implement the [`BuildHasher`] trait for
+ /// The `hasher` passed should implement the [`BuildHasher`] trait for
/// the HashMap to be useful, see its documentation for details.
///
/// # Examples
@@ -316,8 +323,8 @@ impl<K, V, S> HashMap<K, V, S> {
/// map.insert(1, 2);
/// ```
#[inline]
- pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
- HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) }
+ pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashMap<K, V, S> {
+ HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hasher) }
}
/// Returns the number of elements the map can hold without reallocating.
@@ -352,9 +359,14 @@ impl<K, V, S> HashMap<K, V, S> {
/// ]);
///
/// for key in map.keys() {
- /// println!("{}", key);
+ /// println!("{key}");
/// }
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over keys takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
pub fn keys(&self) -> Keys<'_, K, V> {
Keys { inner: self.iter() }
}
@@ -380,8 +392,13 @@ impl<K, V, S> HashMap<K, V, S> {
/// vec.sort_unstable();
/// assert_eq!(vec, ["a", "b", "c"]);
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over keys takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
}
@@ -401,9 +418,14 @@ impl<K, V, S> HashMap<K, V, S> {
/// ]);
///
/// for val in map.values() {
- /// println!("{}", val);
+ /// println!("{val}");
/// }
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over values takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
pub fn values(&self) -> Values<'_, K, V> {
Values { inner: self.iter() }
}
@@ -427,9 +449,14 @@ impl<K, V, S> HashMap<K, V, S> {
/// }
///
/// for val in map.values() {
- /// println!("{}", val);
+ /// println!("{val}");
/// }
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over values takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
ValuesMut { inner: self.iter_mut() }
}
@@ -455,8 +482,13 @@ impl<K, V, S> HashMap<K, V, S> {
/// vec.sort_unstable();
/// assert_eq!(vec, [1, 2, 3]);
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over values takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
}
@@ -476,10 +508,15 @@ impl<K, V, S> HashMap<K, V, S> {
/// ]);
///
/// for (key, val) in map.iter() {
- /// println!("key: {} val: {}", key, val);
+ /// println!("key: {key} val: {val}");
/// }
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over map takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
+ #[rustc_lint_query_instability]
pub fn iter(&self) -> Iter<'_, K, V> {
Iter { base: self.base.iter() }
}
@@ -505,10 +542,15 @@ impl<K, V, S> HashMap<K, V, S> {
/// }
///
/// for (key, val) in &map {
- /// println!("key: {} val: {}", key, val);
+ /// println!("key: {key} val: {val}");
/// }
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over map takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
+ #[rustc_lint_query_instability]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut { base: self.base.iter_mut() }
}
@@ -551,7 +593,7 @@ impl<K, V, S> HashMap<K, V, S> {
///
/// If the returned iterator is dropped before being fully consumed, it
/// drops the remaining key-value pairs. The returned iterator keeps a
- /// mutable borrow on the vector to optimize its implementation.
+ /// mutable borrow on the map to optimize its implementation.
///
/// # Examples
///
@@ -570,7 +612,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// assert!(a.is_empty());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain { base: self.base.drain() }
}
@@ -611,7 +653,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
where
F: FnMut(&K, &mut V) -> bool,
@@ -621,7 +663,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+ /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`.
/// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
@@ -633,8 +675,13 @@ impl<K, V, S> HashMap<K, V, S> {
/// map.retain(|&k, _| k % 2 == 0);
/// assert_eq!(map.len(), 4);
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, this operation takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&K, &mut V) -> bool,
@@ -684,8 +731,10 @@ where
S: BuildHasher,
{
/// Reserves capacity for at least `additional` more elements to be inserted
- /// in the `HashMap`. The collection may reserve more space to avoid
- /// frequent reallocations.
+ /// in the `HashMap`. The collection may reserve more space to speculatively
+ /// avoid frequent reallocations. After calling `reserve`,
+ /// capacity will be greater than or equal to `self.len() + additional`.
+ /// Does nothing if capacity is already sufficient.
///
/// # Panics
///
@@ -704,8 +753,11 @@ where
}
/// Tries to reserve capacity for at least `additional` more elements to be inserted
- /// in the given `HashMap<K, V>`. The collection may reserve more space to avoid
- /// frequent reallocations.
+ /// in the `HashMap`. The collection may reserve more space to speculatively
+ /// avoid frequent reallocations. After calling `reserve`,
+ /// capacity will be greater than or equal to `self.len() + additional` if
+ /// it returns `Ok(())`.
+ /// Does nothing if capacity is already sufficient.
///
/// # Errors
///
@@ -718,7 +770,7 @@ where
/// use std::collections::HashMap;
///
/// let mut map: HashMap<&str, isize> = HashMap::new();
- /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?");
+ /// map.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?");
/// ```
#[inline]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
@@ -781,8 +833,7 @@ where
/// let mut letters = HashMap::new();
///
/// for ch in "a short treatise on fungi".chars() {
- /// let counter = letters.entry(ch).or_insert(0);
- /// *counter += 1;
+ /// letters.entry(ch).and_modify(|counter| *counter += 1).or_insert(1);
/// }
///
/// assert_eq!(letters[&'s'], 2);
@@ -845,6 +896,117 @@ where
self.base.get_key_value(k)
}
+ /// Attempts to get mutable references to `N` values in the map at once.
+ ///
+ /// Returns an array of length `N` with the results of each query. For soundness, at most one
+ /// mutable reference will be returned to any value. `None` will be returned if any of the
+ /// keys are duplicates or missing.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_many_mut)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut libraries = HashMap::new();
+ /// libraries.insert("Bodleian Library".to_string(), 1602);
+ /// libraries.insert("Athenæum".to_string(), 1807);
+ /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+ /// libraries.insert("Library of Congress".to_string(), 1800);
+ ///
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Library of Congress",
+ /// ]);
+ /// assert_eq!(
+ /// got,
+ /// Some([
+ /// &mut 1807,
+ /// &mut 1800,
+ /// ]),
+ /// );
+ ///
+ /// // Missing keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "New York Public Library",
+ /// ]);
+ /// assert_eq!(got, None);
+ ///
+ /// // Duplicate keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Athenæum",
+ /// ]);
+ /// assert_eq!(got, None);
+ /// ```
+ #[inline]
+ pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]>
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.base.get_many_mut(ks)
+ }
+
+ /// Attempts to get mutable references to `N` values in the map at once, without validating that
+ /// the values are unique.
+ ///
+ /// Returns an array of length `N` with the results of each query. `None` will be returned if
+ /// any of the keys are missing.
+ ///
+ /// For a safe alternative see [`get_many_mut`](Self::get_many_mut).
+ ///
+ /// # Safety
+ ///
+ /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting
+ /// references are not used.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_many_mut)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut libraries = HashMap::new();
+ /// libraries.insert("Bodleian Library".to_string(), 1602);
+ /// libraries.insert("Athenæum".to_string(), 1807);
+ /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691);
+ /// libraries.insert("Library of Congress".to_string(), 1800);
+ ///
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "Library of Congress",
+ /// ]);
+ /// assert_eq!(
+ /// got,
+ /// Some([
+ /// &mut 1807,
+ /// &mut 1800,
+ /// ]),
+ /// );
+ ///
+ /// // Missing keys result in None
+ /// let got = libraries.get_many_mut([
+ /// "Athenæum",
+ /// "New York Public Library",
+ /// ]);
+ /// assert_eq!(got, None);
+ /// ```
+ #[inline]
+ pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>(
+ &mut self,
+ ks: [&Q; N],
+ ) -> Option<[&'_ mut V; N]>
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.base.get_many_unchecked_mut(ks)
+ }
+
/// Returns `true` if the map contains a value for the specified key.
///
/// The key may be any borrowed form of the map's key type, but
@@ -1910,6 +2072,13 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> {
}
}
+impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "key already exists"
+ }
+}
+
impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
@@ -1953,7 +2122,7 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> {
/// let vec: Vec<(&str, i32)> = map.into_iter().collect();
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
fn into_iter(self) -> IntoIter<K, V> {
IntoIter { base: self.base.into_iter() }
}
@@ -2692,6 +2861,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
/// # Examples
///
/// ```
+ /// #![feature(entry_insert)]
/// use std::collections::HashMap;
/// use std::collections::hash_map::Entry;
///
@@ -2849,6 +3019,7 @@ impl DefaultHasher {
/// This hasher is not guaranteed to be the same as all other
/// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
/// instances created through `new` or `default`.
+ #[inline]
#[allow(deprecated)]
#[must_use]
pub fn new() -> DefaultHasher {
@@ -2861,17 +3032,26 @@ impl Default for DefaultHasher {
/// See its documentation for more.
///
/// [`new`]: DefaultHasher::new
+ #[inline]
fn default() -> DefaultHasher {
DefaultHasher::new()
}
}
impl Hasher for DefaultHasher {
+ // The underlying `SipHasher13` doesn't override the other
+ // `write_*` methods, so it's ok not to forward them here.
+
#[inline]
fn write(&mut self, msg: &[u8]) {
self.0.write(msg)
}
+ #[inline]
+ fn write_str(&mut self, s: &str) {
+ self.0.write_str(s);
+ }
+
#[inline]
fn finish(&self) -> u64 {
self.0.finish()
diff --git a/sgx_tstd/src/collections/hash/map/tests.rs b/sgx_tstd/src/collections/hash/map/tests.rs
index 105c3947..f2f0d5e8 100644
--- a/sgx_tstd/src/collections/hash/map/tests.rs
+++ b/sgx_tstd/src/collections/hash/map/tests.rs
@@ -286,10 +286,13 @@ fn test_lots_of_insertions() {
// Try this a few times to make sure we never screw up the hashmap's
// internal state.
- for _ in 0..10 {
+ let loops = 10;
+ for _ in 0..loops {
assert!(m.is_empty());
- for i in 1..1001 {
+ let count = 1001;
+
+ for i in 1..count {
assert!(m.insert(i, i).is_none());
for j in 1..=i {
@@ -297,42 +300,42 @@ fn test_lots_of_insertions() {
assert_eq!(r, Some(&j));
}
- for j in i + 1..1001 {
+ for j in i + 1..count {
let r = m.get(&j);
assert_eq!(r, None);
}
}
- for i in 1001..2001 {
+ for i in count..(2 * count) {
assert!(!m.contains_key(&i));
}
// remove forwards
- for i in 1..1001 {
+ for i in 1..count {
assert!(m.remove(&i).is_some());
for j in 1..=i {
assert!(!m.contains_key(&j));
}
- for j in i + 1..1001 {
+ for j in i + 1..count {
assert!(m.contains_key(&j));
}
}
- for i in 1..1001 {
+ for i in 1..count {
assert!(!m.contains_key(&i));
}
- for i in 1..1001 {
+ for i in 1..count {
assert!(m.insert(i, i).is_none());
}
// remove backwards
- for i in (1..1001).rev() {
+ for i in (1..count).rev() {
assert!(m.remove(&i).is_some());
- for j in i..1001 {
+ for j in i..count {
assert!(!m.contains_key(&j));
}
@@ -534,10 +537,10 @@ fn test_show() {
map.insert(1, 2);
map.insert(3, 4);
- let map_str = format!("{:?}", map);
+ let map_str = format!("{map:?}");
assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}");
- assert_eq!(format!("{:?}", empty), "{}");
+ assert_eq!(format!("{empty:?}"), "{}");
}
#[test_case]
@@ -1098,3 +1101,9 @@ fn from_array() {
// that's a problem!
let _must_not_require_type_annotation = HashMap::from([(1, 2)]);
}
+
+#[test_case]
+fn const_with_hasher() {
+ const X: HashMap<(), (), ()> = HashMap::with_hasher(());
+ assert_eq!(X.len(), 0);
+}
diff --git a/sgx_tstd/src/collections/hash/set.rs b/sgx_tstd/src/collections/hash/set.rs
index f31c6963..05fac8a1 100644
--- a/sgx_tstd/src/collections/hash/set.rs
+++ b/sgx_tstd/src/collections/hash/set.rs
@@ -24,7 +24,7 @@ use crate::borrow::Borrow;
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{BuildHasher, Hash};
-use crate::iter::{Chain, FromIterator, FusedIterator};
+use crate::iter::{Chain, FusedIterator};
use crate::ops::{BitAnd, BitOr, BitXor, Sub};
use super::map::{map_try_reserve_error, RandomState};
@@ -50,13 +50,14 @@ use super::map::{map_try_reserve_error, RandomState};
/// In other words, if two keys are equal, their hashes must be equal.
///
///
-/// It is a logic error for an item to be modified in such a way that the
-/// item's hash, as determined by the [`Hash`] trait, or its equality, as
-/// determined by the [`Eq`] trait, changes while it is in the set. This is
-/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
-/// unsafe code. The behavior resulting from such a logic error is not
-/// specified (it could include panics, incorrect results, aborts, memory
-/// leaks, or non-termination) but will not be undefined behavior.
+/// It is a logic error for a key to be modified in such a way that the key's
+/// hash, as determined by the [`Hash`] trait, or its equality, as determined by
+/// the [`Eq`] trait, changes while it is in the map. This is normally only
+/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+/// The behavior resulting from such a logic error is not specified, but will
+/// be encapsulated to the `HashSet` that observed the logic error and not
+/// result in undefined behavior. This could include panics, incorrect results,
+/// aborts, memory leaks, and non-termination.
///
/// # Examples
///
@@ -83,7 +84,7 @@ use super::map::{map_try_reserve_error, RandomState};
///
/// // Iterate over everything.
/// for book in &books {
-/// println!("{}", book);
+/// println!("{book}");
/// }
/// ```
///
@@ -108,7 +109,7 @@ use super::map::{map_try_reserve_error, RandomState};
///
/// // Use derived implementation to print the vikings.
/// for x in &vikings {
-/// println!("{:?}", x);
+/// println!("{x:?}");
/// }
/// ```
///
@@ -147,10 +148,11 @@ impl<T> HashSet<T, RandomState> {
Default::default()
}
- /// Creates an empty `HashSet` with the specified capacity.
+ /// Creates an empty `HashSet` with at least the specified capacity.
///
/// The hash set will be able to hold at least `capacity` elements without
- /// reallocating. If `capacity` is 0, the hash set will not allocate.
+ /// reallocating. This method is allowed to allocate for more elements than
+ /// `capacity`. If `capacity` is 0, the hash set will not allocate.
///
/// # Examples
///
@@ -194,11 +196,16 @@ impl<T, S> HashSet<T, S> {
///
/// // Will print in an arbitrary order.
/// for x in set.iter() {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, iterating over set takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn iter(&self) -> Iter<'_, T> {
Iter { base: self.base.iter() }
}
@@ -242,7 +249,7 @@ impl<T, S> HashSet<T, S> {
///
/// If the returned iterator is dropped before being fully consumed, it
/// drops the remaining elements. The returned iterator keeps a mutable
- /// borrow on the vector to optimize its implementation.
+ /// borrow on the set to optimize its implementation.
///
/// # Examples
///
@@ -254,13 +261,13 @@ impl<T, S> HashSet<T, S> {
///
/// // print 1, 2, 3 in an arbitrary order
/// for i in set.drain() {
- /// println!("{}", i);
+ /// println!("{i}");
/// }
///
/// assert!(set.is_empty());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn drain(&mut self) -> Drain<'_, T> {
Drain { base: self.base.drain() }
}
@@ -298,7 +305,7 @@ impl<T, S> HashSet<T, S> {
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
where
F: FnMut(&T) -> bool,
@@ -308,7 +315,7 @@ impl<T, S> HashSet<T, S> {
/// Retains only the elements specified by the predicate.
///
- /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+ /// In other words, remove all elements `e` for which `f(&e)` returns `false`.
/// The elements are visited in unsorted (and unspecified) order.
///
/// # Examples
@@ -320,7 +327,12 @@ impl<T, S> HashSet<T, S> {
/// set.retain(|&k| k % 2 == 0);
/// assert_eq!(set.len(), 3);
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ ///
+ /// # Performance
+ ///
+ /// In the current implementation, this operation takes O(capacity) time
+ /// instead of O(len) because it internally visits empty buckets too.
+ #[rustc_lint_query_instability]
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&T) -> bool,
@@ -369,15 +381,16 @@ impl<T, S> HashSet<T, S> {
/// set.insert(2);
/// ```
#[inline]
- pub fn with_hasher(hasher: S) -> HashSet<T, S> {
+ pub const fn with_hasher(hasher: S) -> HashSet<T, S> {
HashSet { base: base::HashSet::with_hasher(hasher) }
}
- /// Creates an empty `HashSet` with the specified capacity, using
+ /// Creates an empty `HashSet` with at least the specified capacity, using
/// `hasher` to hash the keys.
///
/// The hash set will be able to hold at least `capacity` elements without
- /// reallocating. If `capacity` is 0, the hash set will not allocate.
+ /// reallocating. This method is allowed to allocate for more elements than
+ /// `capacity`. If `capacity` is 0, the hash set will not allocate.
///
/// Warning: `hasher` is normally randomly generated, and
/// is designed to allow `HashSet`s to be resistant to attacks that
@@ -426,8 +439,10 @@ where
S: BuildHasher,
{
/// Reserves capacity for at least `additional` more elements to be inserted
- /// in the `HashSet`. The collection may reserve more space to avoid
- /// frequent reallocations.
+ /// in the `HashSet`. The collection may reserve more space to speculatively
+ /// avoid frequent reallocations. After calling `reserve`,
+ /// capacity will be greater than or equal to `self.len() + additional`.
+ /// Does nothing if capacity is already sufficient.
///
/// # Panics
///
@@ -447,8 +462,11 @@ where
}
/// Tries to reserve capacity for at least `additional` more elements to be inserted
- /// in the given `HashSet<K, V>`. The collection may reserve more space to avoid
- /// frequent reallocations.
+ /// in the `HashSet`. The collection may reserve more space to speculatively
+ /// avoid frequent reallocations. After calling `reserve`,
+ /// capacity will be greater than or equal to `self.len() + additional` if
+ /// it returns `Ok(())`.
+ /// Does nothing if capacity is already sufficient.
///
/// # Errors
///
@@ -460,7 +478,7 @@ where
/// ```
/// use std::collections::HashSet;
/// let mut set: HashSet<i32> = HashSet::new();
- /// set.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?");
+ /// set.try_reserve(10).expect("why is the test harness OOMing on a handful of bytes?");
/// ```
#[inline]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
@@ -524,7 +542,7 @@ where
///
/// // Can be seen as `a - b`.
/// for x in a.difference(&b) {
- /// println!("{}", x); // Print 1
+ /// println!("{x}"); // Print 1
/// }
///
/// let diff: HashSet<_> = a.difference(&b).collect();
@@ -536,7 +554,7 @@ where
/// assert_eq!(diff, [4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
Difference { iter: self.iter(), other }
}
@@ -553,7 +571,7 @@ where
///
/// // Print 1, 4 in arbitrary order.
/// for x in a.symmetric_difference(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let diff1: HashSet<_> = a.symmetric_difference(&b).collect();
@@ -563,7 +581,7 @@ where
/// assert_eq!(diff1, [1, 4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn symmetric_difference<'a>(
&'a self,
other: &'a HashSet<T, S>,
@@ -574,6 +592,12 @@ where
/// Visits the values representing the intersection,
/// i.e., the values that are both in `self` and `other`.
///
+ /// When an equal element is present in `self` and `other`
+ /// then the resulting `Intersection` may yield references to
+ /// one or the other. This can be relevant if `T` contains fields which
+ /// are not compared by its `Eq` implementation, and may hold different
+ /// value between the two equal copies of `T` in the two sets.
+ ///
/// # Examples
///
/// ```
@@ -583,14 +607,14 @@ where
///
/// // Print 2, 3 in arbitrary order.
/// for x in a.intersection(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let intersection: HashSet<_> = a.intersection(&b).collect();
/// assert_eq!(intersection, [2, 3].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
if self.len() <= other.len() {
Intersection { iter: self.iter(), other }
@@ -611,14 +635,14 @@ where
///
/// // Print 1, 2, 3, 4 in arbitrary order.
/// for x in a.union(&b) {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
///
/// let union: HashSet<_> = a.union(&b).collect();
/// assert_eq!(union, [1, 2, 3, 4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
if self.len() >= other.len() {
Union { iter: self.iter().chain(other.difference(self)) }
@@ -834,9 +858,10 @@ where
/// Adds a value to the set.
///
- /// If the set did not have this value present, `true` is returned.
+ /// Returns whether the value was newly inserted. That is:
///
- /// If the set did have this value present, `false` is returned.
+ /// - If the set did not previously contain this value, `true` is returned.
+ /// - If the set already contained this value, `false` is returned.
///
/// # Examples
///
@@ -1384,7 +1409,7 @@ impl<'a, T, S> IntoIterator for &'a HashSet<T, S> {
type IntoIter = Iter<'a, T>;
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
@@ -1411,11 +1436,11 @@ impl<T, S> IntoIterator for HashSet<T, S> {
///
/// // Will print in an arbitrary order.
/// for x in &v {
- /// println!("{}", x);
+ /// println!("{x}");
/// }
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
+ #[rustc_lint_query_instability]
fn into_iter(self) -> IntoIter<T> {
IntoIter { base: self.base.into_iter() }
}
diff --git a/sgx_tstd/src/collections/hash/set/tests.rs b/sgx_tstd/src/collections/hash/set/tests.rs
index 89dad83a..352143fa 100644
--- a/sgx_tstd/src/collections/hash/set/tests.rs
+++ b/sgx_tstd/src/collections/hash/set/tests.rs
@@ -320,10 +320,10 @@ fn test_show() {
set.insert(1);
set.insert(2);
- let set_str = format!("{:?}", set);
+ let set_str = format!("{set:?}");
assert!(set_str == "{1, 2}" || set_str == "{2, 1}");
- assert_eq!(format!("{:?}", empty), "{}");
+ assert_eq!(format!("{empty:?}"), "{}");
}
#[test_case]
@@ -516,3 +516,9 @@ fn from_array() {
// that's a problem!
let _must_not_require_type_annotation = HashSet::from([1, 2]);
}
+
+#[test_case]
+fn const_with_hasher() {
+ const X: HashSet<(), ()> = HashSet::with_hasher(());
+ assert_eq!(X.len(), 0);
+}
diff --git a/sgx_tstd/src/collections/mod.rs b/sgx_tstd/src/collections/mod.rs
index 5b2dcbd1..4b8c5a14 100644
--- a/sgx_tstd/src/collections/mod.rs
+++ b/sgx_tstd/src/collections/mod.rs
@@ -216,7 +216,7 @@
//! ```
//! let vec = vec![1, 2, 3, 4];
//! for x in vec.iter() {
-//! println!("vec contained {}", x);
+//! println!("vec contained {x:?}");
//! }
//! ```
//!
@@ -263,7 +263,7 @@
//! ```
//! let vec = vec![1, 2, 3, 4];
//! for x in vec.iter().rev() {
-//! println!("vec contained {}", x);
+//! println!("vec contained {x:?}");
//! }
//! ```
//!
@@ -323,7 +323,7 @@
//!
//! println!("Number of occurrences of each character");
//! for (char, count) in &count {
-//! println!("{}: {}", char, count);
+//! println!("{char}: {count}");
//! }
//! ```
//!
@@ -356,7 +356,7 @@
//! // Check if they're sober enough to have another beer.
//! if person.blood_alcohol > 0.3 {
//! // Too drunk... for now.
-//! println!("Sorry {}, I have to cut you off", id);
+//! println!("Sorry {id}, I have to cut you off");
//! } else {
//! // Have another!
//! person.blood_alcohol += 0.1;
@@ -415,6 +415,7 @@
//!
//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator"
+#[doc(hidden)]
pub use crate::ops::Bound;
pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
pub use alloc_crate::collections::{linked_list, vec_deque};
diff --git a/sgx_tstd/src/env.rs b/sgx_tstd/src/env.rs
index 9a4b3da0..46de970c 100644
--- a/sgx_tstd/src/env.rs
+++ b/sgx_tstd/src/env.rs
@@ -45,9 +45,11 @@ use crate::sys::os as os_imp;
///
/// # Platform-specific behavior
///
-/// This function currently corresponds to the `getcwd` function on Unix
+/// This function [currently] corresponds to the `getcwd` function on Unix
/// and the `GetCurrentDirectoryW` function on Windows.
///
+/// [currently]: crate::io#platform-specific-behavior
+///
/// # Errors
///
/// Returns an [`Err`] if the current working directory value is invalid.
@@ -76,11 +78,13 @@ pub fn current_dir() -> io::Result<PathBuf> {
///
/// # Platform-specific behavior
///
-/// This function currently corresponds to the `chdir` function on Unix
+/// This function [currently] corresponds to the `chdir` function on Unix
/// and the `SetCurrentDirectoryW` function on Windows.
///
/// Returns an [`Err`] if the operation fails.
///
+/// [currently]: crate::io#platform-specific-behavior
+///
/// # Examples
///
/// ```
@@ -135,7 +139,7 @@ pub struct VarsOs {
/// // We will iterate through the references to the element returned by
/// // env::vars();
/// for (key, value) in env::vars() {
-/// println!("{}: {}", key, value);
+/// println!("{key}: {value}");
/// }
/// ```
///
@@ -164,7 +168,7 @@ pub fn vars() -> Vars {
/// // We will iterate through the references to the element returned by
/// // env::vars_os();
/// for (key, value) in env::vars_os() {
-/// println!("{:?}: {:?}", key, value);
+/// println!("{key:?}: {value:?}");
/// }
/// ```
#[must_use]
@@ -223,8 +227,8 @@ impl fmt::Debug for VarsOs {
///
/// let key = "HOME";
/// match env::var(key) {
-/// Ok(val) => println!("{}: {:?}", key, val),
-/// Err(e) => println!("couldn't interpret {}: {}", key, e),
+/// Ok(val) => println!("{key}: {val:?}"),
+/// Err(e) => println!("couldn't interpret {key}: {e}"),
/// }
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> Result<String, VarError> {
@@ -262,8 +266,8 @@ fn _var(key: &OsStr) -> Result<String, VarError> {
///
/// let key = "HOME";
/// match env::var_os(key) {
-/// Some(val) => println!("{}: {:?}", key, val),
-/// None => println!("{} is not defined in the environment.", key)
+/// Some(val) => println!("{key}: {val:?}"),
+/// None => println!("{key} is not defined in the environment.")
/// }
/// ```
#[must_use]
@@ -273,7 +277,7 @@ pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
fn _var_os(key: &OsStr) -> Option<OsString> {
os_imp::getenv(key)
- .unwrap_or_else(|e| panic!("failed to get environment variable `{:?}`: {}", key, e))
+ .unwrap_or_else(|e| panic!("failed to get environment variable `{key:?}`: {e}"))
}
/// The error type for operations interacting with environment variables.
@@ -347,7 +351,7 @@ pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
fn _set_var(key: &OsStr, value: &OsStr) {
os_imp::setenv(key, value).unwrap_or_else(|e| {
- panic!("failed to set environment variable `{:?}` to `{:?}`: {}", key, value, e)
+ panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}")
})
}
@@ -388,7 +392,7 @@ pub fn remove_var<K: AsRef<OsStr>>(key: K) {
fn _remove_var(key: &OsStr) {
os_imp::unsetenv(key)
- .unwrap_or_else(|e| panic!("failed to remove environment variable `{:?}`: {}", key, e))
+ .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}"))
}
/// An iterator that splits an environment variable into paths according to
@@ -423,7 +427,7 @@ pub struct SplitPaths<'a> {
/// println!("'{}'", path.display());
/// }
/// }
-/// None => println!("{} is not defined in the environment.", key)
+/// None => println!("{key} is not defined in the environment.")
/// }
/// ```
pub fn split_paths<T: AsRef<OsStr> + ?Sized>(unparsed: &T) -> SplitPaths<'_> {
@@ -585,7 +589,7 @@ pub fn home_dir() -> Option<PathBuf> {
/// # Platform-specific behavior
///
/// On Unix, returns the value of the `TMPDIR` environment variable if it is
-/// set, otherwise for non-Android it returns `/tmp`. If Android, since there
+/// set, otherwise for non-Android it returns `/tmp`. On Android, since there
/// is no global temporary folder (it is usually allocated per-app), it returns
/// `/data/local/tmp`.
/// On Windows, the behavior is equivalent to that of [`GetTempPath2`][GetTempPath2] /
@@ -628,36 +632,23 @@ pub fn temp_dir() -> PathBuf {
///
/// # Security
///
-/// The output of this function should not be used in anything that might have
-/// security implications. For example:
+/// The output of this function should not be trusted for anything
+/// that might have security implications. Basically, if users can run
+/// the executable, they can change the output arbitrarily.
///
-/// ```
-/// fn main() {
-/// println!("{:?}", std::env::current_exe());
-/// }
-/// ```
+/// As an example, you can easily introduce a race condition. It goes
+/// like this:
///
-/// On Linux systems, if this is compiled as `foo`:
+/// 1. You get the path to the current executable using `current_exe()`, and
+/// store it in a variable.
+/// 2. Time passes. A malicious actor removes the current executable, and
+/// replaces it with a malicious one.
+/// 3. You then use the stored path to re-execute the current
+/// executable.
///
-/// ```bash
-/// $ rustc foo.rs
-/// $ ./foo
-/// Ok("/home/alex/foo")
-/// ```
-///
-/// And you make a hard link of the program:
-///
-/// ```bash
-/// $ ln foo bar
-/// ```
-///
-/// When you run it, you won’t get the path of the original executable, you’ll
-/// get the path of the hard link:
-///
-/// ```bash
-/// $ ./bar
-/// Ok("/home/alex/bar")
-/// ```
+/// You expected to safely execute the current executable, but you're
+/// instead executing something completely different. The code you
+/// just executed run with your privileges.
///
/// This sort of behavior has been known to [lead to privilege escalation] when
/// used incorrectly.
@@ -672,7 +663,7 @@ pub fn temp_dir() -> PathBuf {
/// match env::current_exe() {
/// Ok(exe_path) => println!("Path of this executable is: {}",
/// exe_path.display()),
-/// Err(e) => println!("failed to get current exe path: {}", e),
+/// Err(e) => println!("failed to get current exe path: {e}"),
/// };
/// ```
#[cfg(feature = "env")]
@@ -741,7 +732,7 @@ pub struct ArgsOs {
///
/// // Prints each argument on a separate line
/// for argument in env::args() {
-/// println!("{}", argument);
+/// println!("{argument}");
/// }
/// ```
pub fn args() -> Args {
@@ -775,7 +766,7 @@ pub fn args() -> Args {
///
/// // Prints each argument on a separate line
/// for argument in env::args_os() {
-/// println!("{:?}", argument);
+/// println!("{argument:?}");
/// }
/// ```
pub fn args_os() -> ArgsOs {
diff --git a/sgx_tstd/src/error.rs b/sgx_tstd/src/error.rs
index da666a8f..ec182b39 100644
--- a/sgx_tstd/src/error.rs
+++ b/sgx_tstd/src/error.rs
@@ -20,152 +20,11 @@
#[cfg(feature = "unit_test")]
mod tests;
-// A note about crates and the facade:
-//
-// Originally, the `Error` trait was defined in libcore, and the impls
-// were scattered about. However, coherence objected to this
-// arrangement, because to create the blanket impls for `Box` required
-// knowing that `&str: !Error`, and we have no means to deal with that
-// sort of conflict just now. Therefore, for the time being, we have
-// moved the `Error` trait into libstd. As we evolve a sol'n to the
-// coherence challenge (e.g., specialization, neg impls, etc) we can
-// reconsider what crate these items belong in.
-
-use core::array;
-use core::convert::Infallible;
-
-use crate::alloc::{AllocError, LayoutError};
-use crate::any::TypeId;
#[cfg(feature = "backtrace")]
use crate::backtrace::Backtrace;
-use crate::borrow::Cow;
-use crate::cell;
-use crate::char;
-use crate::fmt::{self, Debug, Display};
-#[cfg(feature = "backtrace")]
-use crate::fmt::Write;
-use crate::mem::transmute;
-use crate::num;
-use crate::str;
-use crate::string;
-use crate::sync::Arc;
-use crate::sys;
-use crate::time;
-
-use sgx_oc::ocall::{self, OCallError};
-use sgx_types::error::SgxStatus;
-
-/// `Error` is a trait representing the basic expectations for error values,
-/// i.e., values of type `E` in [`Result<T, E>`].
-///
-/// Errors must describe themselves through the [`Display`] and [`Debug`]
-/// traits. Error messages are typically concise lowercase sentences without
-/// trailing punctuation:
-///
-/// ```
-/// let err = "NaN".parse::<u32>().unwrap_err();
-/// assert_eq!(err.to_string(), "invalid digit found in string");
-/// ```
-///
-/// Errors may provide cause chain information. [`Error::source()`] is generally
-/// used when errors cross "abstraction boundaries". If one module must report
-/// an error that is caused by an error from a lower-level module, it can allow
-/// accessing that error via [`Error::source()`]. This makes it possible for the
-/// high-level module to provide its own errors while also revealing some of the
-/// implementation for debugging via `source` chains.
-pub trait Error: Debug + Display {
- /// The lower-level source of this error, if any.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::fmt;
- ///
- /// #[derive(Debug)]
- /// struct SuperError {
- /// source: SuperErrorSideKick,
- /// }
- ///
- /// impl fmt::Display for SuperError {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "SuperError is here!")
- /// }
- /// }
- ///
- /// impl Error for SuperError {
- /// fn source(&self) -> Option<&(dyn Error + 'static)> {
- /// Some(&self.source)
- /// }
- /// }
- ///
- /// #[derive(Debug)]
- /// struct SuperErrorSideKick;
- ///
- /// impl fmt::Display for SuperErrorSideKick {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "SuperErrorSideKick is here!")
- /// }
- /// }
- ///
- /// impl Error for SuperErrorSideKick {}
- ///
- /// fn get_super_error() -> Result<(), SuperError> {
- /// Err(SuperError { source: SuperErrorSideKick })
- /// }
- ///
- /// fn main() {
- /// match get_super_error() {
- /// Err(e) => {
- /// println!("Error: {}", e);
- /// println!("Caused by: {}", e.source().unwrap());
- /// }
- /// _ => println!("No error"),
- /// }
- /// }
- /// ```
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- None
- }
+use crate::fmt::{self, Write};
- /// Gets the `TypeId` of `self`.
- #[doc(hidden)]
- fn type_id(&self, _: private::Internal) -> TypeId
- where
- Self: 'static,
- {
- TypeId::of::<Self>()
- }
-
- /// Returns a stack backtrace, if available, of where this error occurred.
- ///
- /// This function allows inspecting the location, in code, of where an error
- /// happened. The returned `Backtrace` contains information about the stack
- /// trace of the OS thread of execution of where the error originated from.
- ///
- /// Note that not all errors contain a `Backtrace`. Also note that a
- /// `Backtrace` may actually be empty. For more information consult the
- /// `Backtrace` type itself.
- #[cfg(feature = "backtrace")]
- fn backtrace(&self) -> Option<&Backtrace> {
- None
- }
-
- /// ```
- /// if let Err(e) = "xc".parse::<u32>() {
- /// // Print `e` itself, no need for description().
- /// eprintln!("Error: {}", e);
- /// }
- /// ```
- fn description(&self) -> &str {
- "description() is deprecated; use Display"
- }
-
- #[allow(missing_docs)]
- fn cause(&self) -> Option<&dyn Error> {
- self.source()
- }
-}
+pub use core::error::Error;
mod private {
// This is a hack to prevent `type_id` from being overridden by `Error`
@@ -174,634 +33,12 @@ mod private {
pub struct Internal;
}
-impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
- /// Converts a type of [`Error`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::fmt;
- /// use std::mem;
- ///
- /// #[derive(Debug)]
- /// struct AnError;
- ///
- /// impl fmt::Display for AnError {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "An error")
- /// }
- /// }
- ///
- /// impl Error for AnError {}
- ///
- /// let an_error = AnError;
- /// assert!(0 == mem::size_of_val(&an_error));
- /// let a_boxed_error = Box::<dyn Error>::from(an_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: E) -> Box<dyn Error + 'a> {
- Box::new(err)
- }
-}
-
-impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
- /// dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::fmt;
- /// use std::mem;
- ///
- /// #[derive(Debug)]
- /// struct AnError;
- ///
- /// impl fmt::Display for AnError {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "An error")
- /// }
- /// }
- ///
- /// impl Error for AnError {}
- ///
- /// unsafe impl Send for AnError {}
- ///
- /// unsafe impl Sync for AnError {}
- ///
- /// let an_error = AnError;
- /// assert!(0 == mem::size_of_val(&an_error));
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
- Box::new(err)
- }
-}
-
-impl From<String> for Box<dyn Error + Send + Sync> {
- /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_string_error = "a string error".to_string();
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- #[inline]
- fn from(err: String) -> Box<dyn Error + Send + Sync> {
- struct StringError(String);
-
- impl Error for StringError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- &self.0
- }
- }
-
- impl Display for StringError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Display::fmt(&self.0, f)
- }
- }
-
- // Purposefully skip printing "StringError(..)"
- impl Debug for StringError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Debug::fmt(&self.0, f)
- }
- }
-
- Box::new(StringError(err))
- }
-}
-
-impl From<String> for Box<dyn Error> {
- /// Converts a [`String`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_string_error = "a string error".to_string();
- /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(str_err: String) -> Box<dyn Error> {
- let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
- let err2: Box<dyn Error> = err1;
- err2
- }
-}
-
-impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// [`str`]: prim@str
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_str_error = "a str error";
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- #[inline]
- fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
- From::from(String::from(err))
- }
-}
-
-impl From<&str> for Box<dyn Error> {
- /// Converts a [`str`] into a box of dyn [`Error`].
- ///
- /// [`str`]: prim@str
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- ///
- /// let a_str_error = "a str error";
- /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: &str) -> Box<dyn Error> {
- From::from(String::from(err))
- }
-}
-
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
- /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- /// use std::borrow::Cow;
- ///
- /// let a_cow_str_error = Cow::from("a str error");
- /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
- /// assert!(
- /// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
- From::from(String::from(err))
- }
-}
-
-impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
- /// Converts a [`Cow`] into a box of dyn [`Error`].
- ///
- /// # Examples
- ///
- /// ```
- /// use std::error::Error;
- /// use std::mem;
- /// use std::borrow::Cow;
- ///
- /// let a_cow_str_error = Cow::from("a str error");
- /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
- /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
- /// ```
- fn from(err: Cow<'a, str>) -> Box<dyn Error> {
- From::from(String::from(err))
- }
-}
-
-impl Error for ! {}
-
-impl Error for AllocError {}
-
-impl Error for LayoutError {}
-
-impl Error for str::ParseBoolError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "failed to parse bool"
- }
-}
-
-impl Error for str::Utf8Error {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "invalid utf-8: corrupt contents"
- }
-}
-
-impl Error for num::ParseIntError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for num::TryFromIntError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for array::TryFromSliceError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for num::ParseFloatError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for string::FromUtf8Error {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "invalid utf-8"
- }
-}
-
-impl Error for string::FromUtf16Error {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "invalid utf-16"
- }
-}
-
-impl Error for Infallible {
- fn description(&self) -> &str {
- match *self {}
- }
-}
-
-impl Error for char::DecodeUtf16Error {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "unpaired surrogate found"
- }
-}
-
-impl Error for char::TryFromCharError {}
-
-impl<'a, K: Debug + Ord, V: Debug> Error
- for crate::collections::btree_map::OccupiedError<'a, K, V>
-{
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "key already exists"
- }
-}
-
-impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "key already exists"
- }
-}
-
-impl Error for SgxStatus {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for OCallError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- match self {
- OCallError::SgxError(s) => s.description(),
- OCallError::OsError(code) => sys::decode_error_kind(*code).as_str(),
- OCallError::GaiError(code) => ocall::gai_error_str(*code),
- OCallError::CustomError(s) => s,
- }
- }
-
- #[allow(deprecated)]
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- match self {
- OCallError::SgxError(ref s) => Some(s),
- OCallError::OsError(..) => None,
- OCallError::GaiError(..) => None,
- OCallError::CustomError(..) => None,
- }
- }
-}
-
-impl<T: Error> Error for Box<T> {
- #[allow(deprecated, deprecated_in_future)]
- fn description(&self) -> &str {
- Error::description(&**self)
- }
-
- #[allow(deprecated)]
- fn cause(&self) -> Option<&dyn Error> {
- Error::cause(&**self)
- }
-
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- Error::source(&**self)
- }
-}
-
-impl<'a, T: Error + ?Sized> Error for &'a T {
- #[allow(deprecated, deprecated_in_future)]
- fn description(&self) -> &str {
- Error::description(&**self)
- }
-
- #[allow(deprecated)]
- fn cause(&self) -> Option<&dyn Error> {
- Error::cause(&**self)
- }
-
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- Error::source(&**self)
- }
-
- #[cfg(feature = "backtrace")]
- fn backtrace(&self) -> Option<&Backtrace> {
- Error::backtrace(&**self)
- }
-}
-
-impl<T: Error + ?Sized> Error for Arc<T> {
- #[allow(deprecated, deprecated_in_future)]
- fn description(&self) -> &str {
- Error::description(&**self)
- }
-
- #[allow(deprecated)]
- fn cause(&self) -> Option<&dyn Error> {
- Error::cause(&**self)
- }
-
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- Error::source(&**self)
- }
-
- #[cfg(feature = "backtrace")]
- fn backtrace(&self) -> Option<&Backtrace> {
- Error::backtrace(&**self)
- }
-}
-
-impl Error for fmt::Error {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "an error occurred when formatting an argument"
- }
-}
-
-impl Error for cell::BorrowError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "already mutably borrowed"
- }
-}
-
-impl Error for cell::BorrowMutError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "already borrowed"
- }
-}
-
-impl Error for char::CharTryFromError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "converted integer out of range for `char`"
- }
-}
-
-impl Error for char::ParseCharError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for alloc_crate::collections::TryReserveError {}
-
-impl Error for time::FromFloatSecsError {}
-
-// Copied from `any.rs`.
-impl dyn Error + 'static {
- /// Returns `true` if the inner type is the same as `T`.
- #[inline]
- pub fn is<T: Error + 'static>(&self) -> bool {
- // Get `TypeId` of the type this function is instantiated with.
- let t = TypeId::of::<T>();
-
- // Get `TypeId` of the type in the trait object (`self`).
- let concrete = self.type_id(private::Internal);
-
- // Compare both `TypeId`s on equality.
- t == concrete
- }
-
- /// Returns some reference to the inner value if it is of type `T`, or
- /// `None` if it isn't.
- #[inline]
- pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
- if self.is::<T>() {
- unsafe { Some(&*(self as *const dyn Error as *const T)) }
- } else {
- None
- }
- }
-
- /// Returns some mutable reference to the inner value if it is of type `T`, or
- /// `None` if it isn't.
- #[inline]
- pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
- if self.is::<T>() {
- unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) }
- } else {
- None
- }
- }
-}
-
-impl dyn Error + 'static + Send {
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn is<T: Error + 'static>(&self) -> bool {
- <dyn Error + 'static>::is::<T>(self)
- }
-
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
- <dyn Error + 'static>::downcast_ref::<T>(self)
- }
-
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
- <dyn Error + 'static>::downcast_mut::<T>(self)
- }
-}
-
-impl dyn Error + 'static + Send + Sync {
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn is<T: Error + 'static>(&self) -> bool {
- <dyn Error + 'static>::is::<T>(self)
- }
-
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
- <dyn Error + 'static>::downcast_ref::<T>(self)
- }
-
- /// Forwards to the method defined on the type `dyn Error`.
- #[inline]
- pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
- <dyn Error + 'static>::downcast_mut::<T>(self)
- }
-}
-
-impl dyn Error {
- #[inline]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
- if self.is::<T>() {
- unsafe {
- let raw: *mut dyn Error = Box::into_raw(self);
- Ok(Box::from_raw(raw as *mut T))
- }
- } else {
- Err(self)
- }
- }
-
- /// Returns an iterator starting with the current error and continuing with
- /// recursively calling [`Error::source`].
- ///
- /// If you want to omit the current error and only use its sources,
- /// use `skip(1)`.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(error_iter)]
- /// use std::error::Error;
- /// use std::fmt;
- ///
- /// #[derive(Debug)]
- /// struct A;
- ///
- /// #[derive(Debug)]
- /// struct B(Option<Box<dyn Error + 'static>>);
- ///
- /// impl fmt::Display for A {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "A")
- /// }
- /// }
- ///
- /// impl fmt::Display for B {
- /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- /// write!(f, "B")
- /// }
- /// }
- ///
- /// impl Error for A {}
- ///
- /// impl Error for B {
- /// fn source(&self) -> Option<&(dyn Error + 'static)> {
- /// self.0.as_ref().map(|e| e.as_ref())
- /// }
- /// }
- ///
- /// let b = B(Some(Box::new(A)));
- ///
- /// // let err : Box<Error> = b.into(); // or
- /// let err = &b as &(dyn Error);
- ///
- /// let mut iter = err.chain();
- ///
- /// assert_eq!("B".to_string(), iter.next().unwrap().to_string());
- /// assert_eq!("A".to_string(), iter.next().unwrap().to_string());
- /// assert!(iter.next().is_none());
- /// assert!(iter.next().is_none());
- /// ```
- #[inline]
- pub fn chain(&self) -> Chain<'_> {
- Chain { current: Some(self) }
- }
-}
-
-/// An iterator over an [`Error`] and its sources.
+/// An error reporter that prints an error and its sources.
///
-/// If you want to omit the initial error and only process
-/// its sources, use `skip(1)`.
-#[derive(Clone, Debug)]
-pub struct Chain<'a> {
- current: Option<&'a (dyn Error + 'static)>,
-}
-
-impl<'a> Iterator for Chain<'a> {
- type Item = &'a (dyn Error + 'static);
-
- fn next(&mut self) -> Option<Self::Item> {
- let current = self.current;
- self.current = self.current.and_then(Error::source);
- current
- }
-}
-
-impl dyn Error + Send {
- #[inline]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
- let err: Box<dyn Error> = self;
- <dyn Error>::downcast(err).map_err(|s| unsafe {
- // Reapply the `Send` marker.
- transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
- })
- }
-}
-
-impl dyn Error + Send + Sync {
- #[inline]
- /// Attempts to downcast the box to a concrete type.
- pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
- let err: Box<dyn Error> = self;
- <dyn Error>::downcast(err).map_err(|s| unsafe {
- // Reapply the `Send + Sync` marker.
- transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
- })
- }
-}
-
-/// An error reporter that print's an error and its sources.
-///
-/// Report also exposes configuration options for formatting the error chain, either entirely on a
-/// single line, or in multi-line format with each cause in the error chain on a new line.
+/// Report also exposes configuration options for formatting the error sources, either entirely on a
+/// single line, or in multi-line format with each source on a new line.
///
-/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
+/// `Report` only requires that the wrapped error implement `Error`. It doesn't require that the
/// wrapped error be `Send`, `Sync`, or `'static`.
///
/// # Examples
@@ -905,7 +142,7 @@ impl dyn Error + Send + Sync {
///
/// ## Return from `main`
///
-/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
+/// `Report` also implements `From` for all types that implement [`Error`]; this when combined with
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
/// from `main`.
///
@@ -940,7 +177,7 @@ impl dyn Error + Send + Sync {
/// # Err(SuperError { source: SuperErrorSideKick })
/// # }
///
-/// fn main() -> Result<(), Report> {
+/// fn main() -> Result<(), Report<SuperError>> {
/// get_super_error()?;
/// Ok(())
/// }
@@ -953,7 +190,7 @@ impl dyn Error + Send + Sync {
/// ```
///
/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
-/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
+/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace
/// you will need to manually convert and enable those flags.
///
/// ```should_panic
@@ -987,7 +224,7 @@ impl dyn Error + Send + Sync {
/// # Err(SuperError { source: SuperErrorSideKick })
/// # }
///
-/// fn main() -> Result<(), Report> {
+/// fn main() -> Result<(), Report<SuperError>> {
/// get_super_error()
/// .map_err(Report::from)
/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
@@ -1003,7 +240,6 @@ impl dyn Error + Send + Sync {
/// Caused by:
/// SuperErrorSideKick is here!
/// ```
-#[cfg(feature = "backtrace")]
pub struct Report<E = Box<dyn Error>> {
/// The error being reported.
error: E,
@@ -1013,7 +249,6 @@ pub struct Report<E = Box<dyn Error>> {
pretty: bool,
}
-#[cfg(feature = "backtrace")]
impl<E> Report<E>
where
Report<E>: From<E>,
@@ -1024,7 +259,6 @@ where
}
}
-#[cfg(feature = "backtrace")]
impl<E> Report<E> {
/// Enable pretty-printing the report across multiple lines.
///
@@ -1060,7 +294,7 @@ impl<E> Report<E> {
///
/// let error = SuperError { source: SuperErrorSideKick };
/// let report = Report::new(error).pretty(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces the following output:
@@ -1121,7 +355,7 @@ impl<E> Report<E> {
/// let source = SuperErrorSideKick { source };
/// let error = SuperError { source };
/// let report = Report::new(error).pretty(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces the following output:
@@ -1144,13 +378,15 @@ impl<E> Report<E> {
///
/// **Note**: Report will search for the first `Backtrace` it can find starting from the
/// outermost error. In this example it will display the backtrace from the second error in the
- /// chain, `SuperErrorSideKick`.
+ /// sources, `SuperErrorSideKick`.
///
/// ```rust
/// #![feature(error_reporter)]
- /// #![feature(backtrace)]
+ /// #![feature(provide_any)]
+ /// #![feature(error_generic_member_access)]
/// # use std::error::Error;
/// # use std::fmt;
+ /// use std::any::Demand;
/// use std::error::Report;
/// use std::backtrace::Backtrace;
///
@@ -1180,8 +416,8 @@ impl<E> Report<E> {
/// }
///
/// impl Error for SuperErrorSideKick {
- /// fn backtrace(&self) -> Option<&Backtrace> {
- /// Some(&self.backtrace)
+ /// fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
+ /// demand.provide_ref::<Backtrace>(&self.backtrace);
/// }
/// }
///
@@ -1195,7 +431,7 @@ impl<E> Report<E> {
/// let source = SuperErrorSideKick::new();
/// let error = SuperError { source };
/// let report = Report::new(error).pretty(true).show_backtrace(true);
- /// eprintln!("Error: {:?}", report);
+ /// eprintln!("Error: {report:?}");
/// ```
///
/// This example produces something similar to the following output:
@@ -1226,82 +462,21 @@ impl<E> Report<E> {
}
}
-#[cfg(feature = "backtrace")]
impl<E> Report<E>
where
E: Error,
{
+ #[cfg(feature = "backtrace")]
+ #[allow(clippy::map_flatten)]
fn backtrace(&self) -> Option<&Backtrace> {
// have to grab the backtrace on the first error directly since that error may not be
// 'static
- let backtrace = self.error.backtrace();
- backtrace.or_else(|| {
- self.error
- .source()
- .and_then(|source| source.chain().find_map(|source| source.backtrace()))
- })
- }
-
- /// Format the report as a single line.
- fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", self.error)?;
-
- let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
-
- for cause in sources {
- write!(f, ": {}", cause)?;
- }
-
- Ok(())
- }
-
- /// Format the report as multiple lines, with each error cause on its own line.
- fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let error = &self.error;
-
- write!(f, "{}", error)?;
-
- if let Some(cause) = error.source() {
- write!(f, "\n\nCaused by:")?;
-
- let multiple = cause.source().is_some();
-
- for (ind, error) in cause.chain().enumerate() {
- writeln!(f)?;
- let mut indented = Indented { inner: f };
- if multiple {
- write!(indented, "{: >4}: {}", ind, error)?;
- } else {
- write!(indented, " {}", error)?;
- }
- }
- }
-
- if self.show_backtrace {
- let backtrace = self.backtrace();
-
- if let Some(backtrace) = backtrace {
- let backtrace = backtrace.to_string();
-
- f.write_str("\n\nStack backtrace:\n")?;
- f.write_str(backtrace.trim_end())?;
- }
- }
-
- Ok(())
- }
-}
-
-#[cfg(feature = "backtrace")]
-impl Report<Box<dyn Error>> {
- fn backtrace(&self) -> Option<&Backtrace> {
- // have to grab the backtrace on the first error directly since that error may not be
- // 'static
- let backtrace = self.error.backtrace();
+ let backtrace = (&self.error as &dyn Error).request_ref();
backtrace.or_else(|| {
self.error
.source()
- .and_then(|source| source.chain().find_map(|source| source.backtrace()))
+ .map(|source| source.sources().find_map(|source| source.request_ref()))
+ .flatten()
})
}
@@ -1309,10 +484,10 @@ impl Report<Box<dyn Error>> {
fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.error)?;
- let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+ let sources = self.error.source().into_iter().flat_map(<dyn Error>::sources);
for cause in sources {
- write!(f, ": {}", cause)?;
+ write!(f, ": {cause}")?;
}
Ok(())
@@ -1322,24 +497,25 @@ impl Report<Box<dyn Error>> {
fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let error = &self.error;
- write!(f, "{}", error)?;
+ write!(f, "{error}")?;
if let Some(cause) = error.source() {
write!(f, "\n\nCaused by:")?;
let multiple = cause.source().is_some();
- for (ind, error) in cause.chain().enumerate() {
+ for (ind, error) in cause.sources().enumerate() {
writeln!(f)?;
let mut indented = Indented { inner: f };
if multiple {
- write!(indented, "{: >4}: {}", ind, error)?;
+ write!(indented, "{ind: >4}: {error}")?;
} else {
- write!(indented, " {}", error)?;
+ write!(indented, " {error}")?;
}
}
}
+ #[cfg(feature = "backtrace")]
if self.show_backtrace {
let backtrace = self.backtrace();
@@ -1355,7 +531,6 @@ impl Report<Box<dyn Error>> {
}
}
-#[cfg(feature = "backtrace")]
impl<E> From<E> for Report<E>
where
E: Error,
@@ -1365,18 +540,6 @@ where
}
}
-#[cfg(feature = "backtrace")]
-impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
-where
- E: Error + 'a,
-{
- fn from(error: E) -> Self {
- let error = box error;
- Report { error, show_backtrace: false, pretty: false }
- }
-}
-
-#[cfg(feature = "backtrace")]
impl<E> fmt::Display for Report<E>
where
E: Error,
@@ -1386,16 +549,8 @@ where
}
}
-#[cfg(feature = "backtrace")]
-impl fmt::Display for Report<Box<dyn Error>> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
- }
-}
-
// This type intentionally outputs the same format for `Display` and `Debug`for
// situations where you unwrap a `Report` or return it from main.
-#[cfg(feature = "backtrace")]
impl<E> fmt::Debug for Report<E>
where
Report<E>: fmt::Display,
@@ -1406,12 +561,10 @@ where
}
/// Wrapper type for indenting the inner source.
-#[cfg(feature = "backtrace")]
struct Indented<'a, D> {
inner: &'a mut D,
}
-#[cfg(feature = "backtrace")]
impl<T> Write for Indented<'_, T>
where
T: Write,
diff --git a/sgx_tstd/src/error/tests.rs b/sgx_tstd/src/error/tests.rs
index 2f5c49a2..b9f99138 100644
--- a/sgx_tstd/src/error/tests.rs
+++ b/sgx_tstd/src/error/tests.rs
@@ -17,6 +17,7 @@
use super::Error;
use crate::fmt;
+use core::any::Demand;
use sgx_test_utils::test_case;
@@ -149,7 +150,7 @@ Stack backtrace:
error.backtrace = Some(trace);
let report = Report::new(error).pretty(true).show_backtrace(true);
- println!("Error: {}", report);
+ println!("Error: {report}");
assert_eq!(expected.trim_end(), report.to_string());
}
@@ -174,7 +175,7 @@ Stack backtrace:
let error = GenericError::new_with_source("Error with two sources", error);
let report = Report::new(error).pretty(true).show_backtrace(true);
- println!("Error: {}", report);
+ println!("Error: {report}");
assert_eq!(expected.trim_end(), report.to_string());
}
@@ -217,8 +218,8 @@ where
self.source.as_deref()
}
- fn backtrace(&self) -> Option<&Backtrace> {
- self.backtrace.as_ref()
+ fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+ self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt));
}
}
@@ -374,7 +375,7 @@ Caused by:
1: The message goes on and on.";
let actual = report.to_string();
- println!("{}", actual);
+ println!("{actual}");
assert_eq!(expected, actual);
}
diff --git a/sgx_tstd/src/f32.rs b/sgx_tstd/src/f32.rs
index 6906080e..0f116a06 100644
--- a/sgx_tstd/src/f32.rs
+++ b/sgx_tstd/src/f32.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License..
-//! Constants specific to the `f32` single-precision floating point type.
+//! Constants for the `f32` single-precision floating point type.
//!
//! *[See also the `f32` primitive type](primitive@f32).*
//!
@@ -40,9 +40,8 @@ pub use core::f32::{
MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
};
-#[lang = "f32_runtime"]
impl f32 {
- /// Returns the largest integer less than or equal to a number.
+ /// Returns the largest integer less than or equal to `self`.
///
/// # Examples
///
@@ -55,13 +54,14 @@ impl f32 {
/// assert_eq!(g.floor(), 3.0);
/// assert_eq!(h.floor(), -4.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn floor(self) -> f32 {
unsafe { intrinsics::floorf32(self) }
}
- /// Returns the smallest integer greater than or equal to a number.
+ /// Returns the smallest integer greater than or equal to `self`.
///
/// # Examples
///
@@ -72,13 +72,14 @@ impl f32 {
/// assert_eq!(f.ceil(), 4.0);
/// assert_eq!(g.ceil(), 4.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ceil(self) -> f32 {
unsafe { intrinsics::ceilf32(self) }
}
- /// Returns the nearest integer to a number. Round half-way cases away from
+ /// Returns the nearest integer to `self`. Round half-way cases away from
/// `0.0`.
///
/// # Examples
@@ -90,13 +91,15 @@ impl f32 {
/// assert_eq!(f.round(), 3.0);
/// assert_eq!(g.round(), -3.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn round(self) -> f32 {
unsafe { intrinsics::roundf32(self) }
}
- /// Returns the integer part of a number.
+ /// Returns the integer part of `self`.
+ /// This means that non-integer numbers are always truncated towards zero.
///
/// # Examples
///
@@ -109,13 +112,14 @@ impl f32 {
/// assert_eq!(g.trunc(), 3.0);
/// assert_eq!(h.trunc(), -3.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn trunc(self) -> f32 {
unsafe { intrinsics::truncf32(self) }
}
- /// Returns the fractional part of a number.
+ /// Returns the fractional part of `self`.
///
/// # Examples
///
@@ -128,14 +132,14 @@ impl f32 {
/// assert!(abs_difference_x <= f32::EPSILON);
/// assert!(abs_difference_y <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn fract(self) -> f32 {
self - self.trunc()
}
- /// Computes the absolute value of `self`. Returns `NAN` if the
- /// number is `NAN`.
+ /// Computes the absolute value of `self`.
///
/// # Examples
///
@@ -151,6 +155,7 @@ impl f32 {
///
/// assert!(f32::NAN.abs().is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn abs(self) -> f32 {
@@ -161,7 +166,7 @@ impl f32 {
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
- /// - `NAN` if the number is `NAN`
+ /// - NaN if the number is NaN
///
/// # Examples
///
@@ -173,6 +178,7 @@ impl f32 {
///
/// assert!(f32::NAN.signum().is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn signum(self) -> f32 {
@@ -183,8 +189,10 @@ impl f32 {
/// `sign`.
///
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
- /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
- /// `sign` is returned.
+ /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+ /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+ /// across arithmetical operations is not generally guaranteed.
+ /// See [explanation of NaN as a special value](primitive@f32) for more info.
///
/// # Examples
///
@@ -198,6 +206,7 @@ impl f32 {
///
/// assert!(f32::NAN.copysign(1.0).is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn copysign(self, sign: f32) -> f32 {
@@ -224,6 +233,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn mul_add(self, a: f32, b: f32) -> f32 {
@@ -247,6 +257,7 @@ impl f32 {
/// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
/// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn div_euclid(self, rhs: f32) -> f32 {
@@ -280,6 +291,7 @@ impl f32 {
/// // limitation due to round-off error
/// assert!((-f32::EPSILON).rem_euclid(3.0) != 0.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn rem_euclid(self, rhs: f32) -> f32 {
@@ -289,7 +301,9 @@ impl f32 {
/// Raises a number to an integer power.
///
- /// Using this function is generally faster than using `powf`
+ /// Using this function is generally faster than using `powf`.
+ /// It might have a different sequence of rounding operations than `powf`,
+ /// so the results are not guaranteed to agree.
///
/// # Examples
///
@@ -299,6 +313,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn powi(self, n: i32) -> f32 {
@@ -315,6 +330,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn powf(self, n: f32) -> f32 {
@@ -338,6 +354,7 @@ impl f32 {
/// assert!(negative.sqrt().is_nan());
/// assert!(negative_zero.sqrt() == negative_zero);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sqrt(self) -> f32 {
@@ -358,6 +375,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp(self) -> f32 {
@@ -376,6 +394,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp2(self) -> f32 {
@@ -396,6 +415,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ln(self) -> f32 {
@@ -418,6 +438,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log(self, base: f32) -> f32 {
@@ -436,6 +457,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log2(self) -> f32 {
@@ -457,6 +479,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log10(self) -> f32 {
@@ -480,6 +503,7 @@ impl f32 {
/// assert!(abs_difference_x <= f32::EPSILON);
/// assert!(abs_difference_y <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn abs_sub(self, other: f32) -> f32 {
@@ -498,6 +522,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cbrt(self) -> f32 {
@@ -518,6 +543,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn hypot(self, other: f32) -> f32 {
@@ -535,6 +561,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sin(self) -> f32 {
@@ -552,6 +579,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cos(self) -> f32 {
@@ -568,6 +596,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn tan(self) -> f32 {
@@ -588,6 +617,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn asin(self) -> f32 {
@@ -608,6 +638,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn acos(self) -> f32 {
@@ -627,6 +658,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atan(self) -> f32 {
@@ -659,6 +691,7 @@ impl f32 {
/// assert!(abs_difference_1 <= f32::EPSILON);
/// assert!(abs_difference_2 <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atan2(self, other: f32) -> f32 {
@@ -680,6 +713,7 @@ impl f32 {
/// assert!(abs_difference_0 <= f32::EPSILON);
/// assert!(abs_difference_1 <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[inline]
pub fn sin_cos(self) -> (f32, f32) {
(self.sin(), self.cos())
@@ -699,6 +733,7 @@ impl f32 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp_m1(self) -> f32 {
@@ -719,6 +754,7 @@ impl f32 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ln_1p(self) -> f32 {
@@ -740,6 +776,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sinh(self) -> f32 {
@@ -761,6 +798,7 @@ impl f32 {
/// // Same result
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cosh(self) -> f32 {
@@ -782,6 +820,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn tanh(self) -> f32 {
@@ -800,6 +839,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn asinh(self) -> f32 {
@@ -818,6 +858,7 @@ impl f32 {
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn acosh(self) -> f32 {
@@ -836,6 +877,7 @@ impl f32 {
///
/// assert!(abs_difference <= 1e-5);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atanh(self) -> f32 {
diff --git a/sgx_tstd/src/f64.rs b/sgx_tstd/src/f64.rs
index 68b772eb..d80a295a 100644
--- a/sgx_tstd/src/f64.rs
+++ b/sgx_tstd/src/f64.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License..
-//! Constants specific to the `f64` double-precision floating point type.
+//! Constants for the `f64` double-precision floating point type.
//!
//! *[See also the `f64` primitive type](primitive@f64).*
//!
@@ -40,9 +40,8 @@ pub use core::f64::{
MIN_EXP, MIN_POSITIVE, NAN, NEG_INFINITY, RADIX,
};
-#[lang = "f64_runtime"]
impl f64 {
- /// Returns the largest integer less than or equal to a number.
+ /// Returns the largest integer less than or equal to `self`.
///
/// # Examples
///
@@ -55,13 +54,14 @@ impl f64 {
/// assert_eq!(g.floor(), 3.0);
/// assert_eq!(h.floor(), -4.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn floor(self) -> f64 {
unsafe { intrinsics::floorf64(self) }
}
- /// Returns the smallest integer greater than or equal to a number.
+ /// Returns the smallest integer greater than or equal to `self`.
///
/// # Examples
///
@@ -72,13 +72,14 @@ impl f64 {
/// assert_eq!(f.ceil(), 4.0);
/// assert_eq!(g.ceil(), 4.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ceil(self) -> f64 {
unsafe { intrinsics::ceilf64(self) }
}
- /// Returns the nearest integer to a number. Round half-way cases away from
+ /// Returns the nearest integer to `self`. Round half-way cases away from
/// `0.0`.
///
/// # Examples
@@ -90,13 +91,15 @@ impl f64 {
/// assert_eq!(f.round(), 3.0);
/// assert_eq!(g.round(), -3.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn round(self) -> f64 {
unsafe { intrinsics::roundf64(self) }
}
- /// Returns the integer part of a number.
+ /// Returns the integer part of `self`.
+ /// This means that non-integer numbers are always truncated towards zero.
///
/// # Examples
///
@@ -109,13 +112,14 @@ impl f64 {
/// assert_eq!(g.trunc(), 3.0);
/// assert_eq!(h.trunc(), -3.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn trunc(self) -> f64 {
unsafe { intrinsics::truncf64(self) }
}
- /// Returns the fractional part of a number.
+ /// Returns the fractional part of `self`.
///
/// # Examples
///
@@ -128,14 +132,14 @@ impl f64 {
/// assert!(abs_difference_x < 1e-10);
/// assert!(abs_difference_y < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn fract(self) -> f64 {
self - self.trunc()
}
- /// Computes the absolute value of `self`. Returns `NAN` if the
- /// number is `NAN`.
+ /// Computes the absolute value of `self`.
///
/// # Examples
///
@@ -151,6 +155,7 @@ impl f64 {
///
/// assert!(f64::NAN.abs().is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn abs(self) -> f64 {
@@ -161,7 +166,7 @@ impl f64 {
///
/// - `1.0` if the number is positive, `+0.0` or `INFINITY`
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
- /// - `NAN` if the number is `NAN`
+ /// - NaN if the number is NaN
///
/// # Examples
///
@@ -173,6 +178,7 @@ impl f64 {
///
/// assert!(f64::NAN.signum().is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn signum(self) -> f64 {
@@ -183,8 +189,10 @@ impl f64 {
/// `sign`.
///
/// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
- /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
- /// `sign` is returned.
+ /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of
+ /// `sign` is returned. Note, however, that conserving the sign bit on NaN
+ /// across arithmetical operations is not generally guaranteed.
+ /// See [explanation of NaN as a special value](primitive@f32) for more info.
///
/// # Examples
///
@@ -198,6 +206,7 @@ impl f64 {
///
/// assert!(f64::NAN.copysign(1.0).is_nan());
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn copysign(self, sign: f64) -> f64 {
@@ -224,6 +233,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn mul_add(self, a: f64, b: f64) -> f64 {
@@ -247,6 +257,7 @@ impl f64 {
/// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0
/// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn div_euclid(self, rhs: f64) -> f64 {
@@ -280,6 +291,7 @@ impl f64 {
/// // limitation due to round-off error
/// assert!((-f64::EPSILON).rem_euclid(3.0) != 0.0);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn rem_euclid(self, rhs: f64) -> f64 {
@@ -289,7 +301,9 @@ impl f64 {
/// Raises a number to an integer power.
///
- /// Using this function is generally faster than using `powf`
+ /// Using this function is generally faster than using `powf`.
+ /// It might have a different sequence of rounding operations than `powf`,
+ /// so the results are not guaranteed to agree.
///
/// # Examples
///
@@ -299,6 +313,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn powi(self, n: i32) -> f64 {
@@ -315,6 +330,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn powf(self, n: f64) -> f64 {
@@ -338,6 +354,7 @@ impl f64 {
/// assert!(negative.sqrt().is_nan());
/// assert!(negative_zero.sqrt() == negative_zero);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sqrt(self) -> f64 {
@@ -358,6 +375,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp(self) -> f64 {
@@ -376,6 +394,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp2(self) -> f64 {
@@ -396,6 +415,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ln(self) -> f64 {
@@ -418,6 +438,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log(self, base: f64) -> f64 {
@@ -436,6 +457,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log2(self) -> f64 {
@@ -459,6 +481,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn log10(self) -> f64 {
@@ -482,6 +505,7 @@ impl f64 {
/// assert!(abs_difference_x < 1e-10);
/// assert!(abs_difference_y < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn abs_sub(self, other: f64) -> f64 {
@@ -500,6 +524,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cbrt(self) -> f64 {
@@ -520,6 +545,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn hypot(self, other: f64) -> f64 {
@@ -537,6 +563,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sin(self) -> f64 {
@@ -554,6 +581,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cos(self) -> f64 {
@@ -570,6 +598,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-14);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn tan(self) -> f64 {
@@ -590,6 +619,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn asin(self) -> f64 {
@@ -610,6 +640,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn acos(self) -> f64 {
@@ -629,6 +660,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atan(self) -> f64 {
@@ -661,6 +693,7 @@ impl f64 {
/// assert!(abs_difference_1 < 1e-10);
/// assert!(abs_difference_2 < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atan2(self, other: f64) -> f64 {
@@ -682,6 +715,7 @@ impl f64 {
/// assert!(abs_difference_0 < 1e-10);
/// assert!(abs_difference_1 < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[inline]
pub fn sin_cos(self) -> (f64, f64) {
(self.sin(), self.cos())
@@ -701,6 +735,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-20);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn exp_m1(self) -> f64 {
@@ -721,6 +756,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-20);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn ln_1p(self) -> f64 {
@@ -742,6 +778,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn sinh(self) -> f64 {
@@ -763,6 +800,7 @@ impl f64 {
/// // Same result
/// assert!(abs_difference < 1.0e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn cosh(self) -> f64 {
@@ -784,6 +822,7 @@ impl f64 {
///
/// assert!(abs_difference < 1.0e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn tanh(self) -> f64 {
@@ -802,6 +841,7 @@ impl f64 {
///
/// assert!(abs_difference < 1.0e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn asinh(self) -> f64 {
@@ -820,6 +860,7 @@ impl f64 {
///
/// assert!(abs_difference < 1.0e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn acosh(self) -> f64 {
@@ -838,6 +879,7 @@ impl f64 {
///
/// assert!(abs_difference < 1.0e-10);
/// ```
+ #[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[inline]
pub fn atanh(self) -> f64 {
@@ -848,6 +890,7 @@ impl f64 {
// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
// of expected NaN).
#[allow(clippy::if_same_then_else)]
+ #[rustc_allow_incoherent_impl]
fn log_wrapper<F: Fn(f64) -> f64>(self, log_fn: F) -> f64 {
if !cfg!(any(target_os = "solaris", target_os = "illumos")) {
log_fn(self)
diff --git a/sgx_tstd/src/ffi/c_str.rs b/sgx_tstd/src/ffi/c_str.rs
deleted file mode 100644
index b31e2fff..00000000
--- a/sgx_tstd/src/ffi/c_str.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License..
-
-#[cfg(feature = "unit_test")]
-mod tests;
-
-pub use sgx_ffi::c_str::*;
-
-use crate::error::Error;
-use crate::io;
-
-impl Error for NulError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- "nul byte found in data"
- }
-}
-
-impl From<NulError> for io::Error {
- /// Converts a [`NulError`] into a [`io::Error`].
- fn from(_: NulError) -> io::Error {
- io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
- }
-}
-
-impl Error for FromBytesWithNulError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-impl Error for FromVecWithNulError {}
-
-impl Error for IntoStringError {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-
- fn source(&self) -> Option<&(dyn Error + 'static)> {
- Some(self.__source())
- }
-}
diff --git a/sgx_tstd/src/ffi/mod.rs b/sgx_tstd/src/ffi/mod.rs
index 1c6152af..7e72f121 100644
--- a/sgx_tstd/src/ffi/mod.rs
+++ b/sgx_tstd/src/ffi/mod.rs
@@ -121,7 +121,7 @@
//! On Unix, [`OsStr`] implements the
//! <code>std::os::unix::ffi::[OsStrExt][unix.OsStrExt]</code> trait, which
//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
-//! These do inexpensive conversions from and to UTF-8 byte slices.
+//! These do inexpensive conversions from and to byte slices.
//!
//! Additionally, on Unix [`OsString`] implements the
//! <code>std::os::unix::ffi::[OsStringExt][unix.OsStringExt]</code> trait,
@@ -161,13 +161,18 @@
//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt"
//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide"
-pub use self::c_str::FromBytesWithNulError;
-pub use self::c_str::FromVecWithNulError;
-pub use self::c_str::{CStr, CString, IntoStringError, NulError};
+pub use alloc_crate::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
+pub use core::ffi::{CStr, FromBytesWithNulError};
+
pub use self::os_str::{OsStr, OsString};
+pub use core::ffi::{
+ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint,
+ c_ulong, c_ulonglong, c_ushort,
+};
+
pub use core::ffi::c_void;
+
pub use core::ffi::{VaList, VaListImpl};
-mod c_str;
mod os_str;
diff --git a/sgx_tstd/src/ffi/os_str.rs b/sgx_tstd/src/ffi/os_str.rs
index eb9b8bbe..8a2d359f 100644
--- a/sgx_tstd/src/ffi/os_str.rs
+++ b/sgx_tstd/src/ffi/os_str.rs
@@ -25,7 +25,7 @@ use crate::cmp;
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{Hash, Hasher};
-use crate::iter::{Extend, FromIterator};
+use crate::iter::Extend;
use crate::ops;
use crate::rc::Rc;
use crate::str::FromStr;
@@ -64,6 +64,22 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
/// values, encoded in a less-strict variant of UTF-8. This is useful to
/// understand when handling capacity and length values.
///
+/// # Capacity of `OsString`
+///
+/// Capacity uses units of UTF-8 bytes for OS strings which were created from valid unicode, and
+/// uses units of bytes in an unspecified encoding for other contents. On a given target, all
+/// `OsString` and `OsStr` values use the same units for capacity, so the following will work:
+/// ```
+/// use std::ffi::{OsStr, OsString};
+///
+/// fn concat_os_strings(a: &OsStr, b: &OsStr) -> OsString {
+/// let mut ret = OsString::with_capacity(a.len() + b.len()); // This will allocate
+/// ret.push(a); // This will not allocate further
+/// ret.push(b); // This will not allocate further
+/// ret
+/// }
+/// ```
+///
/// # Creating an `OsString`
///
/// **From a Rust string**: `OsString` implements
@@ -191,13 +207,14 @@ impl OsString {
self.inner.push_slice(&s.as_ref().inner)
}
- /// Creates a new `OsString` with the given capacity.
+ /// Creates a new `OsString` with at least the given capacity.
///
- /// The string will be able to hold exactly `capacity` length units of other
- /// OS strings without reallocating. If `capacity` is 0, the string will not
+ /// The string will be able to hold at least `capacity` length units of other
+ /// OS strings without reallocating. This method is allowed to allocate for
+ /// more units than `capacity`. If `capacity` is 0, the string will not
/// allocate.
///
- /// See main `OsString` documentation information about encoding.
+ /// See the main `OsString` documentation information about encoding and capacity units.
///
/// # Examples
///
@@ -238,7 +255,7 @@ impl OsString {
/// Returns the capacity this `OsString` can hold without reallocating.
///
- /// See `OsString` introduction for information about encoding.
+ /// See the main `OsString` documentation information about encoding and capacity units.
///
/// # Examples
///
@@ -255,9 +272,12 @@ impl OsString {
}
/// Reserves capacity for at least `additional` more capacity to be inserted
- /// in the given `OsString`.
+ /// in the given `OsString`. Does nothing if the capacity is
+ /// already sufficient.
+ ///
+ /// The collection may reserve more space to speculatively avoid frequent reallocations.
///
- /// The collection may reserve more space to avoid frequent reallocations.
+ /// See the main `OsString` documentation information about encoding and capacity units.
///
/// # Examples
///
@@ -274,10 +294,13 @@ impl OsString {
}
/// Tries to reserve capacity for at least `additional` more length units
- /// in the given `OsString`. The string may reserve more space to avoid
+ /// in the given `OsString`. The string may reserve more space to speculatively avoid
/// frequent reallocations. After calling `try_reserve`, capacity will be
- /// greater than or equal to `self.len() + additional`. Does nothing if
- /// capacity is already sufficient.
+ /// greater than or equal to `self.len() + additional` if it returns `Ok(())`.
+ /// Does nothing if capacity is already sufficient. This method preserves
+ /// the contents even if an error occurs.
+ ///
+ /// See the main `OsString` documentation information about encoding and capacity units.
///
/// # Errors
///
@@ -287,7 +310,6 @@ impl OsString {
/// # Examples
///
/// ```
- /// #![feature(try_reserve_2)]
/// use std::ffi::{OsStr, OsString};
/// use std::collections::TryReserveError;
///
@@ -309,7 +331,7 @@ impl OsString {
self.inner.try_reserve(additional)
}
- /// Reserves the minimum capacity for exactly `additional` more capacity to
+ /// Reserves the minimum capacity for at least `additional` more capacity to
/// be inserted in the given `OsString`. Does nothing if the capacity is
/// already sufficient.
///
@@ -319,6 +341,8 @@ impl OsString {
///
/// [`reserve`]: OsString::reserve
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Examples
///
/// ```
@@ -333,7 +357,7 @@ impl OsString {
self.inner.reserve_exact(additional)
}
- /// Tries to reserve the minimum capacity for exactly `additional`
+ /// Tries to reserve the minimum capacity for at least `additional`
/// more length units in the given `OsString`. After calling
/// `try_reserve_exact`, capacity will be greater than or equal to
/// `self.len() + additional` if it returns `Ok(())`.
@@ -345,6 +369,8 @@ impl OsString {
///
/// [`try_reserve`]: OsString::try_reserve
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Errors
///
/// If the capacity overflows, or the allocator reports a failure, then an error
@@ -353,7 +379,6 @@ impl OsString {
/// # Examples
///
/// ```
- /// #![feature(try_reserve_2)]
/// use std::ffi::{OsStr, OsString};
/// use std::collections::TryReserveError;
///
@@ -377,6 +402,8 @@ impl OsString {
/// Shrinks the capacity of the `OsString` to match its length.
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Examples
///
/// ```
@@ -402,6 +429,8 @@ impl OsString {
///
/// If the current capacity is less than the lower limit, this is a no-op.
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Examples
///
/// ```
@@ -597,6 +626,13 @@ impl Hash for OsString {
}
}
+impl fmt::Write for OsString {
+ fn write_str(&mut self, s: &str) -> fmt::Result {
+ self.push(s);
+ Ok(())
+ }
+}
+
impl OsStr {
/// Coerces into an `OsStr` slice.
///
@@ -750,6 +786,8 @@ impl OsStr {
/// This number is simply useful for passing to other methods, like
/// [`OsString::with_capacity`] to avoid reallocations.
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Examples
///
/// ```
@@ -1163,6 +1201,22 @@ impl OsStr {
}
}
+impl<S: Borrow<OsStr>> alloc_crate::slice::Join<&OsStr> for [S] {
+ type Output = OsString;
+
+ fn join(slice: &Self, sep: &OsStr) -> OsString {
+ let Some((first, suffix)) = slice.split_first() else {
+ return OsString::new();
+ };
+ let first_owned = first.borrow().to_owned();
+ suffix.iter().fold(first_owned, |mut a, b| {
+ a.push(sep);
+ a.push(b.borrow());
+ a
+ })
+ }
+}
+
impl Borrow<OsStr> for OsString {
#[inline]
fn borrow(&self) -> &OsStr {
diff --git a/sgx_tstd/src/ffi/os_str/tests.rs b/sgx_tstd/src/ffi/os_str/tests.rs
index 376be81f..33fbb40f 100644
--- a/sgx_tstd/src/ffi/os_str/tests.rs
+++ b/sgx_tstd/src/ffi/os_str/tests.rs
@@ -103,6 +103,20 @@ fn test_os_string_reserve_exact() {
assert!(os_string.capacity() >= 33)
}
+#[test_case]
+fn test_os_string_join() {
+ let strings = [OsStr::new("hello"), OsStr::new("dear"), OsStr::new("world")];
+ assert_eq!("hello", strings[..1].join(OsStr::new(" ")));
+ assert_eq!("hello dear world", strings.join(OsStr::new(" ")));
+ assert_eq!("hellodearworld", strings.join(OsStr::new("")));
+ assert_eq!("hello.\n dear.\n world", strings.join(OsStr::new(".\n ")));
+
+ assert_eq!("dear world", strings[1..].join(&OsString::from(" ")));
+
+ let strings_abc = [OsString::from("a"), OsString::from("b"), OsString::from("c")];
+ assert_eq!("a b c", strings_abc.join(OsStr::new(" ")));
+}
+
#[test_case]
fn test_os_string_default() {
let os_string: OsString = Default::default();
diff --git a/sgx_tstd/src/fs.rs b/sgx_tstd/src/fs.rs
index 8de50199..6a9afafd 100644
--- a/sgx_tstd/src/fs.rs
+++ b/sgx_tstd/src/fs.rs
@@ -24,7 +24,7 @@ mod tests;
use crate::ffi::OsString;
use crate::fmt;
-use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use crate::path::{Path, PathBuf};
use crate::sys::fs as fs_imp;
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -32,7 +32,7 @@ use crate::time::SystemTime;
#[cfg(not(feature = "untrusted_fs"))]
use crate::untrusted::path::PathEx;
-/// A reference to an open file on the filesystem.
+/// An object providing access to an open file on the filesystem.
///
/// An instance of a `File` can be read and/or written depending on what options
/// it was opened with. Files also implement [`Seek`] to alter the logical cursor
@@ -98,6 +98,12 @@ use crate::untrusted::path::PathEx;
/// by different processes. Avoid assuming that holding a `&File` means that the
/// file will not change.
///
+/// # Platform-specific behavior
+///
+/// On Windows, the implementation of [`Read`] and [`Write`] traits for `File`
+/// perform synchronous I/O operations. Therefore the underlying file must not
+/// have been opened for asynchronous I/O (e.g. by using `FILE_FLAG_OVERLAPPED`).
+///
/// [`BufReader<R>`]: io::BufReader
/// [`sync_all`]: File::sync_all
#[cfg_attr(not(test), rustc_diagnostic_item = "File")]
@@ -136,6 +142,16 @@ pub struct ReadDir(fs_imp::ReadDir);
/// An instance of `DirEntry` represents an entry inside of a directory on the
/// filesystem. Each entry can be inspected via methods to learn about the full
/// path or possibly other metadata through per-platform extension traits.
+///
+/// # Platform-specific behavior
+///
+/// On Unix, the `DirEntry` struct contains an internal reference to the open
+/// directory. Holding `DirEntry` objects will consume a file handle even
+/// after the `ReadDir` iterator is dropped.
+///
+/// Note that this [may change in the future][changes].
+///
+/// [changes]: io#platform-specific-behavior
... 18252 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org