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 17:33:59 UTC
[incubator-teaclave-sgx-sdk] 01/01: Support rust-nightly-2022-10-22 and Bump version to 1.1.6
This is an automated email from the ASF dual-hosted git repository.
rduan pushed a commit to branch v1.1.6-testing
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave-sgx-sdk.git
commit 500ff2aefda31cee65509ee61ba057e2bf7314a4
Author: volcano <vo...@163.com>
AuthorDate: Sun Oct 23 00:48:29 2022 +0800
Support rust-nightly-2022-10-22 and Bump version to 1.1.6
---
edl/sgx_fd.edl | 10 +
rust-toolchain | 2 +-
samplecode/mio/client-go/ca.cert | 77 +-
samplecode/mio/client-java/ca.cert | 77 +-
samplecode/mio/client/bin/ca.cert | 77 +-
samplecode/mio/server/bin/end.fullchain | 172 +--
samplecode/mio/server/bin/end.rsa | 50 +-
samplecode/project_template/app/rust-toolchain | 2 +-
samplecode/project_template/enclave/rust-toolchain | 2 +-
samplecode/tls/tlsclient/bin/ca.cert | 77 +-
samplecode/tls/tlsserver/bin/end.fullchain | 172 +--
samplecode/tls/tlsserver/bin/end.rsa | 50 +-
sgx_align_struct_attribute/Cargo.toml | 2 +-
sgx_align_struct_attribute/src/layout.rs | 2 +-
sgx_alloc/Cargo.toml | 2 +-
sgx_alloc/src/alignalloc.rs | 2 +-
sgx_alloc/src/alignbox.rs | 8 +-
sgx_backtrace/Cargo.toml | 2 +-
sgx_backtrace_sys/Cargo.toml | 2 +-
sgx_build_helper/Cargo.toml | 2 +-
sgx_cov/Cargo.toml | 2 +-
sgx_crypto_helper/Cargo.toml | 2 +-
sgx_demangle/Cargo.toml | 2 +-
sgx_edl/Cargo.toml | 2 +-
sgx_edl/edl/sgx_fd.edl | 10 +
sgx_libc/Cargo.toml | 2 +-
sgx_libc/src/lib.rs | 1 +
sgx_libc/src/linux/x86_64/mod.rs | 21 +-
sgx_libc/src/linux/x86_64/ocall.rs | 209 ++-
sgx_no_tstd/Cargo.toml | 2 +-
sgx_panic_abort/src/lib.rs | 15 +-
sgx_panic_unwind/src/gcc.rs | 78 -
sgx_panic_unwind/src/lib.rs | 16 +-
sgx_rand/Cargo.toml | 2 +-
sgx_rand_derive/Cargo.toml | 2 +-
sgx_serialize/Cargo.toml | 2 +-
sgx_serialize_derive/Cargo.toml | 2 +-
sgx_serialize_derive_internals/Cargo.toml | 2 +-
sgx_signal/Cargo.toml | 2 +-
sgx_signal/src/exception.rs | 28 +-
sgx_signal/src/manager.rs | 31 +-
sgx_tcrypto/Cargo.toml | 2 +-
sgx_tcrypto_helper/Cargo.toml | 2 +-
sgx_tdh/Cargo.toml | 2 +-
sgx_tkey_exchange/Cargo.toml | 2 +-
sgx_tprotected_fs/Cargo.toml | 2 +-
sgx_trts/Cargo.toml | 2 +-
sgx_trts/src/c_str.rs | 1533 +-------------------
sgx_trts/src/lib.rs | 1 -
sgx_tse/Cargo.toml | 2 +-
sgx_tseal/Cargo.toml | 2 +-
sgx_tstd/Cargo.toml | 2 +-
sgx_tstd/src/alloc.rs | 29 +-
sgx_tstd/src/backtrace.rs | 15 +-
sgx_tstd/src/collections/hash/map.rs | 258 +++-
sgx_tstd/src/collections/hash/set.rs | 107 +-
sgx_tstd/src/collections/mod.rs | 9 +-
sgx_tstd/src/enclave.rs | 2 +-
sgx_tstd/src/env.rs | 73 +-
sgx_tstd/src/error.rs | 886 +----------
sgx_tstd/src/f32.rs | 68 +-
sgx_tstd/src/f64.rs | 70 +-
sgx_tstd/src/ffi/c_str.rs | 55 -
sgx_tstd/src/ffi/mod.rs | 15 +-
sgx_tstd/src/ffi/os_str.rs | 84 +-
sgx_tstd/src/fs.rs | 169 ++-
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/copy.rs | 46 +-
sgx_tstd/src/io/cursor.rs | 182 ++-
sgx_tstd/src/io/error.rs | 108 +-
sgx_tstd/src/io/error/repr_unpacked.rs | 6 +-
sgx_tstd/src/io/impls.rs | 62 +-
sgx_tstd/src/io/mod.rs | 194 ++-
sgx_tstd/src/io/readbuf.rs | 316 ++--
sgx_tstd/src/io/stdio.rs | 478 +++---
sgx_tstd/src/io/util.rs | 14 +-
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} | 413 +++---
sgx_tstd/src/net/mod.rs | 22 +-
sgx_tstd/src/net/parser.rs | 158 +-
sgx_tstd/src/net/{addr.rs => socket_addr.rs} | 236 ++-
sgx_tstd/src/net/tcp.rs | 15 +-
sgx_tstd/src/net/udp.rs | 14 +-
sgx_tstd/src/os/fd/mod.rs | 12 +-
sgx_tstd/src/os/fd/owned.rs | 130 +-
sgx_tstd/src/os/fd/raw.rs | 87 +-
sgx_tstd/src/os/linux/fs.rs | 26 +-
sgx_tstd/src/os/linux/mod.rs | 2 +
sgx_tstd/src/os/{unix/io/fd.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/raw.rs => net/mod.rs} | 5 +-
sgx_tstd/src/os/net/tcp.rs | 82 ++
sgx_tstd/src/os/raw/mod.rs | 89 +-
sgx_tstd/src/os/unix/fs.rs | 4 +-
sgx_tstd/src/os/unix/io/mod.rs | 70 +-
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 | 40 +-
sgx_tstd/src/os/unix/net/listener.rs | 10 +-
sgx_tstd/src/os/unix/net/stream.rs | 34 +-
sgx_tstd/src/panicking.rs | 184 ++-
sgx_tstd/src/path.rs | 76 +-
sgx_tstd/src/{os/fd/mod.rs => personality.rs} | 25 +-
.../src => sgx_tstd/src/personality}/dwarf/eh.rs | 32 +-
.../src => sgx_tstd/src/personality}/dwarf/mod.rs | 19 +-
.../src => sgx_tstd/src/personality}/gcc.rs | 89 +-
sgx_tstd/src/prelude/mod.rs | 11 +
sgx_tstd/src/rt.rs | 17 +-
sgx_tstd/src/sync/condvar.rs | 53 +-
sgx_tstd/src/sync/lazy_lock.rs | 129 ++
sgx_tstd/src/sync/mod.rs | 15 +-
sgx_tstd/src/sync/mpsc/blocking.rs | 13 +-
sgx_tstd/src/sync/mpsc/mod.rs | 20 +-
sgx_tstd/src/sync/mpsc/oneshot.rs | 24 +-
sgx_tstd/src/sync/mpsc/shared.rs | 33 +-
sgx_tstd/src/sync/mpsc/stream.rs | 31 +-
sgx_tstd/src/sync/mpsc/sync.rs | 1 +
sgx_tstd/src/sync/mutex.rs | 91 +-
sgx_tstd/src/sync/once.rs | 301 +---
sgx_tstd/src/{lazy.rs => sync/once_lock.rs} | 374 ++---
sgx_tstd/src/sync/poison.rs | 17 +-
sgx_tstd/src/sync/rwlock.rs | 198 ++-
sgx_tstd/src/sys/backtrace/mod.rs | 3 +-
.../src/{os/unix/io/fd.rs => sys/common/mod.rs} | 4 +-
sgx_tstd/src/sys/common/small_c_string.rs | 70 +
sgx_tstd/src/sys/fd.rs | 17 +-
sgx_tstd/src/sys/fs.rs | 288 ++--
sgx_tstd/src/sys/io.rs | 18 +-
sgx_tstd/src/sys/kernel_copy.rs | 669 +++++++++
sgx_tstd/src/sys/{ => locks}/condvar.rs | 143 +-
sgx_tstd/src/{os => sys/locks}/mod.rs | 13 +-
sgx_tstd/src/sys/{ => locks}/mutex.rs | 490 ++++---
sgx_tstd/src/sys/{ => locks}/rwlock.rs | 233 +--
sgx_tstd/src/sys/mod.rs | 10 +-
sgx_tstd/src/sys/net.rs | 22 +-
sgx_tstd/src/sys/os.rs | 74 +-
sgx_tstd/src/sys/os_str.rs | 40 +-
sgx_tstd/src/sys/path.rs | 3 +-
sgx_tstd/src/sys/sgxfs.rs | 4 +-
sgx_tstd/src/sys/stdio.rs | 46 +-
sgx_tstd/src/sys/thread_local_dtor.rs | 10 +-
sgx_tstd/src/sys/thread_local_key.rs | 5 -
sgx_tstd/src/sys/time.rs | 206 +--
sgx_tstd/src/sys_common/at_exit_imp.rs | 21 +-
sgx_tstd/src/sys_common/backtrace.rs | 21 +-
sgx_tstd/src/sys_common/condvar.rs | 107 +-
sgx_tstd/src/sys_common/condvar/check.rs | 48 +-
sgx_tstd/src/sys_common/lazy_box.rs | 107 ++
sgx_tstd/src/sys_common/mod.rs | 2 +
sgx_tstd/src/sys_common/mutex.rs | 251 +---
sgx_tstd/src/sys_common/net.rs | 143 +-
sgx_tstd/src/sys_common/once/generic.rs | 298 ++++
sgx_tstd/src/sys_common/once/mod.rs | 46 +
sgx_tstd/src/sys_common/remutex.rs | 79 +-
sgx_tstd/src/sys_common/rwlock.rs | 149 +-
sgx_tstd/src/sys_common/thread_info.rs | 2 +-
sgx_tstd/src/sys_common/thread_local_dtor.rs | 14 +-
sgx_tstd/src/sys_common/thread_local_key.rs | 27 +-
sgx_tstd/src/sys_common/thread_parker/generic.rs | 27 +-
sgx_tstd/src/sys_common/wtf8.rs | 101 +-
sgx_tstd/src/thread/local.rs | 495 ++++++-
sgx_tstd/src/thread/mod.rs | 264 +++-
sgx_tstd/src/thread/scoped.rs | 94 +-
sgx_tstd/src/time.rs | 29 +-
sgx_tstd/src/untrusted/time.rs | 10 +-
sgx_tunittest/Cargo.toml | 2 +-
sgx_types/Cargo.toml | 2 +-
sgx_types/src/error.rs | 8 +
sgx_types/src/lib.rs | 1 +
sgx_types/src/macros.rs | 75 +-
sgx_types/src/types.rs | 5 +-
sgx_ucrypto/Cargo.toml | 2 +-
sgx_unwind/Cargo.toml | 2 +-
sgx_unwind/src/lib.rs | 1 -
sgx_urts/Cargo.toml | 2 +-
sgx_urts/src/fd.rs | 139 +-
sgx_ustdc/fd.c | 72 +-
183 files changed, 7848 insertions(+), 6969 deletions(-)
diff --git a/edl/sgx_fd.edl b/edl/sgx_fd.edl
index 8cfc822e..cd668b71 100644
--- a/edl/sgx_fd.edl
+++ b/edl/sgx_fd.edl
@@ -19,6 +19,7 @@ enclave {
include "inc/stat.h"
include "sys/uio.h"
+ include "time.h"
from "sgx_mem.edl" import *;
@@ -37,11 +38,20 @@ enclave {
size_t u_writev_ocall([out] int *error, int fd, [in, count=iovcnt] const struct iovec *iov, int iovcnt);
size_t u_pwritev64_ocall([out] int *error, int fd, [in, count=iovcnt] const struct iovec *iov, int iovcnt, int64_t offset);
+ size_t u_sendfile_ocall([out] int *error, int out_fd, int in_fd, [in, out] int64_t *offset, size_t count);
+ size_t u_copy_file_range_ocall([out] int *error, int fd_in, [in, out] int64_t *off_in, int fd_out, [in, out] int64_t *off_out, size_t len, unsigned int flags);
+ size_t u_splice_ocall([out] int *error, int fd_in, [in, out] int64_t *off_in, int fd_out, [in, out] int64_t *off_out, size_t len, unsigned int flags);
+
int u_fcntl_arg0_ocall([out] int *error, int fd, int cmd);
int u_fcntl_arg1_ocall([out] int *error, int fd, int cmd, int arg);
int u_ioctl_arg0_ocall([out] int *error, int fd, int request);
int u_ioctl_arg1_ocall([out] int *error, int fd, int request, [in, out] int *arg);
int u_close_ocall([out] int *error, int fd);
+ 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/rust-toolchain b/rust-toolchain
index 4e7e21b0..ea0f16e1 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2022-02-23
\ No newline at end of file
+nightly-2022-10-17
\ No newline at end of file
diff --git a/samplecode/mio/client-go/ca.cert b/samplecode/mio/client-go/ca.cert
index a18fb02c..3a84cbe6 100644
--- a/samplecode/mio/client-go/ca.cert
+++ b/samplecode/mio/client-go/ca.cert
@@ -1,51 +1,30 @@
-----BEGIN CERTIFICATE-----
-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
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/mio/client-java/ca.cert b/samplecode/mio/client-java/ca.cert
index a18fb02c..3a84cbe6 100644
--- a/samplecode/mio/client-java/ca.cert
+++ b/samplecode/mio/client-java/ca.cert
@@ -1,51 +1,30 @@
-----BEGIN CERTIFICATE-----
-MIIJCjCCBPKgAwIBAgIJAI+QZnVEkxq/MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV
-BAMMD3Bvbnl0b3duIFJTQSBDQTAeFw0xNzA0MTAyMDU2MjdaFw0yNzA0MDgyMDU2
-MjdaMBoxGDAWBgNVBAMMD3Bvbnl0b3duIFJTQSBDQTCCBCIwDQYJKoZIhvcNAQEB
-BQADggQPADCCBAoCggQBAMD0iyFqRCNhvD5T9WXO8caNGb5ecrlnqSUvfcc+6Xh9
-sShtK6DX2DZ+6YT2WWOZTk0I9T+XG2kujjyfdCbEDMWcT9so7/gPeIG/qFlhONCu
-HC+zntuZrGgMEYpF3Xc41CyF3saredTJEo1J64TPEke8mohezIGZYM1vTtRnqW+1
-RstSNTu8a/B0VaG0iA5P5RuSGVmxczi4EWJtuXFhcbgqICaUt0vJdrU0Fmrmq0Iq
-ZEIpgZKYirx5QW8b6Q5tv0YsnXNasXvHZQve4GgF449ewk9wWfYevD8UttHUEe2a
-QeEKb2l7NxqyY6trGyVtTRlm4SnoOH/9VodTKUEmS6pds6XFtjRflxgom0TL7CXb
-uJ9b6fkXQlnf01FqAbv5HC1sjgGlSZc7Yk8k09nWOR8mZMoHC+U4KEq+oM+m87q4
-U/GsEk8UsPslGIIHHK6W/sdU6zA9bR3QYmkD40Z7FbVfKVvDmKPlwI7NONqysD8V
-UTPoB8aE7FeulZhlTxdK2EcW14AsjbFiPQ4zAVxj4bRj39RLgJYL+BvAF6PfRHb1
-Xb7ykbuTvT7VhNYXLlQagR9EyixT3Wu9WCWUc0xJKSATn1s2YBLNM7LO4MkYO9WG
-YrejhNHG+54a7rtnnlG04Gs7OhM32baMH/DxT+EEAX4j0Dfww4RaCZcfq1gDPsVe
-+RzqsjjqF8+IzE25SK38xgwT/o3n9r5Ele3/zadwy695KCfbkhVFSDAPvhiv8um5
-6NNP+dDymFRXGzV85xSK75ue3Dpj+MoSScmIdGLEcU5EqYcBFLCXGLYPDIW8Lb89
-mG1z7TkZOLIs+6v7kp4rrvyijsyLFZ+EKUmabAK42qdzASZ1o6ETDDfFBETMxjWA
-oMmGmRkhsyfBTuCr1ESlTBQHj4vvxBrgXgHtHwUinBw/sofLbkFRZ4wz/cBOtwqW
-HIu88/o33l6ywMowcjaoToIbK2a4rD/KFJiwLliGKZG2veiESRhnNUQyjxT/PIef
-0gqx3i1eBGWvfQs/wUC8qI5UadTRhjMFCwMCDVycevZE8lcQ+7zi9tVu6mXife5J
-yP/jxRNDLzpdM6C6puqk0XieZey782XZ7sPpDpS2tphwakINF/5X3t1qZsssZPqq
-F1S2VIsL8qm6Z7HDHXex3o2tDUhc226YSp/T7D+IWP3UCs0NjJrldakhnAd7ykxT
-b2cDh09GDYSbji4Y6WmgIbSAurqk6kt4MWrfx4yfEAlp8ujH6788lRDAiXN1RgzC
-k8r21IOJONDG7Qk1rS0YUV4XyGz4SEpBdPTI7RM1fl5bDn4e+OslBcfWh5XplZrz
-4D4Z9YWVZ8X6d7CiPYZIg35oo/45KGel3Z8algziVkMCAwEAAaNTMFEwHQYDVR0O
-BBYEFOWXlO0crUtBejJo87v9lwg8PlE6MB8GA1UdIwQYMBaAFOWXlO0crUtBejJo
-87v9lwg8PlE6MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggQBADUQ
-YqVmS9o3/5Qp7Tr+JL5ZNRP1fRmV5kAqaKDC5I9ONKRYahHvoI0ojE/j+pmwI4gf
-mp5mW8EgsNfooovrzVSHxJgBO9r1ogMlL9AvwlvVxLbexvLXpM/1QjD/7FID/TaK
-1q5mhSBKaEYXqQ+8DN25aVsI/bwHx4eP11Ft6YjhPqaX/WutE/IIAMbgASRFtBlO
-foTm++fpdn8rCg5LiLLpWrRLC3zUSUtFd7if3wQ4vcDdck09v9PjD5Lk34aYkowJ
-oARbVmBMpAxwkMXaThP1fT7xlYPDhAA26UXksT5xUNzFPbmOVReuFT0drhJlF6e6
-SLTjy2BcrYuz5ieBmmY6QboBYH3SzUFKuamvnHLSic3i3u9Ly68XUjOtDKgYB7Y5
-oZtfZT+YFmz/R6eLUcGRRfcmLJ+i/OXjgyKVkYBMDafW3RI9fRp46Yr/lvOv5gFW
-Vrn3Tfc9cSbYQgE4vuKXcs4aVVeX8uAyjcucMV3eLdxaBLUAezTpJseRfqtH2kCk
-3JIV6m2y6Tm5EhhaSiHKbe6FtPFKhpu7m9AlquUzhBU9Aq59mbKp6jtV0mWhYwKB
-K6REmWQqqAOtHIs7UIXDeN1ZByJ7q+et57RvMgMHc5My0d6a+gQAUssH4i73sVTz
-Uej57DW9L7hK0GQpzGzGIO/9lYTzWMVa8EZG1Fa5nUgMh3N3Oy6qUQIqr8E8xT2O
-IbKKV6Acx6lBiwii4JkruEMgVVEdsDWDVdP8Ov5lJvvIPLWLqnXsZ2sKCyZrVkgc
-PTXVtYBLmn7Tuwody2MSaBONSqleJ1oPQJ9lsAKyqX4xpX05ZJu2kNhST2oq2127
-378GS85DqKDM3P187mjU2G8moqWaGKr6byiIr7ea5TkqIzpC3tKW5QRHvX9aanz0
-akQx6F+l3l4L8J0cXaKasUJTaCk3cWPbbVzo8tQwwdxd0/MdJWrmitK85o+4gLqG
-Cvn9VA4mnhjRR0XccxEtzmhSxBRWXoCF1+FnfDmXhPji+AmAhVqRwPkqX9T9H+54
-YG2ZA9Trxssme+QFSFCPZrHuw66ZI6GmKo6h+Hr2qew7LytASN+x2QyvRf7tSNmf
-oUgmiD+CFpaH6exjrCC0/hcJ53Kv3E5GBvQskvOqgsUkW+nmsrm95YOosn+9MoQc
-PIM6zQCmZ0N/6jHrEHnOnSnz03tGHsvPs6tMB6DKhQz9FNqlrLG7UHhlqhFWj9nv
-H+Zh0oOwbcgcoxkk+W6LHLDpA3UpC1tlOzTlD2ektACvQQr/2A/fecpJN/7iWlX9
-BimWwRTS24bO5dX92Kb8V1TNO6ARd9TqOkPXRatysyh7it/MXpc5I2+t49hqlXoV
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/mio/client/bin/ca.cert b/samplecode/mio/client/bin/ca.cert
index a18fb02c..3a84cbe6 100644
--- a/samplecode/mio/client/bin/ca.cert
+++ b/samplecode/mio/client/bin/ca.cert
@@ -1,51 +1,30 @@
-----BEGIN CERTIFICATE-----
-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
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/mio/server/bin/end.fullchain b/samplecode/mio/server/bin/end.fullchain
index 2ea11e48..380ec768 100644
--- a/samplecode/mio/server/bin/end.fullchain
+++ b/samplecode/mio/server/bin/end.fullchain
@@ -1,113 +1,81 @@
-----BEGIN CERTIFICATE-----
MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u
-eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE3MDQxMDIwNTYyN1oX
-DTIyMTAwMTIwNTYyN1owGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCa4nonCxArES+kBBf9mZoaQ2GBMg74
-Pj2ve4RKJSIBt9A7EgJ4hFznFQ11O11Xvb3dVQGOK+pFRxh2xg0DJvV3lJytpvKe
-mviyT5KSGvp6Hybqmx66B2V3iDfrXhhySqG5tKEeczFBIq+62dAp0+r0oSdpZKGT
-1YDtXonjcbnDb93K7g8arEadFKYN3MAjBGQ3m5fsWJJuq4hLU1+dpmAfxmYH1dlc
-n89LyPhYh0I7R5v17VrGlNCWIWD1emLtM8vTS94eMtp8R6MuMIZTOKgBTrIpU4G5
-GPcR3flDzzLsCxEttjjMa41zStKXzieUIwirRAzPv48V4JlkCCUPv97pAgMBAAGj
-gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFNn77YZg
-4AGguHBKVggK00dtRvhCMEIGA1UdIwQ7MDmAFGuwcG2Zfyr92yAiXU9HP9rBYC6/
+eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDYwOTE3MTUxMloX
+DTI0MTEyOTE3MTUxMlowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdwbEc6ZKih4mQA916JwctBZgnRmzO
+KERrzlHjfzy8ZfsUJLENQBN8s3RVRwPThReHdp8bpiVRrNmMRxyXoa5oqxWDjXOu
+5W4hoISIMbOAq4Kj8G+eS0UKwypKHwJ1aUzEjWQGKxNpIYvcGqwYpN1Yi1+qTgLg
+2qw1ENtBhrWHhmQruGqDtQTQLe2tbcOuGhIL0cyWIRtEWHWL/wb1Akzhm31WQF+m
+URtYvYonA/Ta7ErONXCxsEXndTR4iT/XognnOhTJ+uIinNwn52y9Te7MYix6SDBE
+VeKZx9v3iOYU81zXf+WaxNqZvTfbPjkLsXiymOgVfGQcO4hiQeLoJIHXAgMBAAGj
+gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFEweXJqS
+BzVcf/00QeOC29OwBQszMEIGA1UdIwQ7MDmAFEKPy8hHZVazpvIsxFcGo4YrkEkw
oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO
dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0
-MA0GCSqGSIb3DQEBCwUAA4IBgQB4xB9IPNxkJIA8QtngQZCCSPH5SjfAibcLfwi2
-NLHe4hO4HvoIVv0ru7CODfq45qNfH7sUj8a/JBU8BwcJ3xPewWFdavtCP8+dapmd
-pr831+Xx6p9tNIdW16WrCXEV8i9bHy43Y4pWbNdXQy5meI0qvSM/ExedZqqVeJJT
-oXL/aCtMsBixlwlKvrsG9ZvIAl1ics0wA5kqQWVufe95loI+HUcPc9s9689H+/ON
-lH8rTLPwyufk9h2dTb9Wzw3qewlDIqgoyX7k9cOwrJqA4D6typCvb5dWfQlK9c72
-4rGbqHSx7mrlaZ4typfAMdEbynRlDSgIIZGXb7RaoV3NT2XuVFd8+lcXgBiJMvPk
-STejz77EPR2+uKvQ1gMJXpEHCBUvMMyDqhpcNzb0DaXgf4eYI9RqfxU1pkgYnfxe
-DGDGI2SdmO43NwSDyEQVSlRpCIBj4ZDay3IP7mbdi8MLxR9H1BCHnN7D04UrTnuA
-c/cl0RMWL+iHtKU2cCxltEQQ9qQ=
+MA0GCSqGSIb3DQEBCwUAA4IBgQCViHp2pLcIMzl/wN+sULznLYZvrlynU4AHnL8/
+ba6iSAM6EMlrcu11+UBQglHIN2BEn+Jjas+HT1sQOIOixMgjrMBgirLez8n5DN66
+o5aK5bu23GjQvzq5JEh0skQDHtSFX0YRwqXIhi1spGtObsnoupxJNBQbdAcDv50/
+m6/8WXcPbXBnR+wRywFmjb6+OSVNgCRtBFTbR5XRVHMPEwvSk4hVj4jimlnPHZYL
+3VatCPtZr6iaLZl9E64BbS+J4vPQ0Z/2JMUjtXCuj19k8LO2TTTBz54QVoMF5jrZ
+xotneq+wmPH3lmozEOmyj4+4CmoyNz+RDhrlok84x3g4YEKUQyK1V4ROi9DtL1CV
+VoLfHSwS9SiDdD/Qn2n7RICn6DP2lHozICyHX0Op4W+vETHho7Flsw21bMisAGrl
+wwQ7UYU4XfPOC9hQoCvU60uVe7z+uZvlBY8RwmcW4iFIbfCcPT6Hrom5F1X4Z/dm
+zDW8ZhLDsjUY/D4lUeWjbO1RCHI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIGnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255
-dG93biBSU0EgQ0EwHhcNMTcwNDEwMjA1NjI3WhcNMjcwNDA4MjA1NjI3WjAsMSow
+MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255
+dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow
KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G
-CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDCX7V0gKGQBS64QKntjDlBslbQJaxq
-EL8Yyq+qjF6nkOoqENKWSzeNyQ76kPVlzeV03UCaIgTF4+FeQrUr7wauEz0FGmDh
-yx/B4xy9ZXdBIftPB8iz8Q/KrKO6YM6tkj7ijvL8hP3MfssBkA+VoAxamPSIikfM
-9kyttemjYizgM0ywebzKmQGJbEINZ80Kp63ayR/Uo/cORjlH3xbmtTsL3pd+k6Ro
-xOMZKm1RIwOwGgxDW4ea294A4lXHwfwHGMsP0/xmqTZ0R/EpxLKeqJAQffTiVsBK
-YEFzANn3nol1IYrdcZcgcs16KTnc5+XyL87KSdIgDgG3wmQvRCdLX5G6GChyP03Z
-qQSYMkwGSNgCD1v4m14Z5XT2su7iilHfjsucvT4OukCe63nqeXIZ+w63YqbjTp/a
-HMgrXVg1wMlSncl0OIKcjLOgJ5vbPOGk9DvF93JbRFp/9sAZmK89Ur4gBmgpq2Zn
-bknK0LVt+aerP7rf8CPYE89olPVUW0owwrkCAwEAAaNeMFwwHQYDVR0OBBYEFGuw
-cG2Zfyr92yAiXU9HP9rBYC6/MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF
+CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw
+zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C
+G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9
+HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ
+ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1
+fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25
+stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop
+Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+
+9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP
+y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC
-BAEARD9wwIHsAFWlzrRLw3JcAUDB906Ks7KZzdqe3n6FkbyHHP1N5JG25wXwgADS
-qux6sZU7h6+q209IEqXWbw+nbxJs/3D1hLN6X2tVgsfkSflGsd3DfNPZI8qKUyOD
-VYlql/EPEMBixXOeVpwxXc48rX/yVjxqCvhY/A7eIiAc+bzQtwozLppChyVitQGI
-MViXRdGdFiybwTKoJMYXl6ztamk9TWhdvJ9znirol12b06Z3J0Kz0c/kqY7VVZqL
-ba76+IAJjvWQE7PYEOqpFHOLpilv9j5d/0kBR4AgJaooFwcYnr6aJKfNUgGWEmdn
-ELYmfa0qORllAM/yGoewRfWGLZBNgT0QFYg2IFjnp0W0wIXFRd7xVqldN+cTmMqk
-szpVV7bqGvuk6SQNFjIZ8VIVc/mXua4WlwBODDRzKqU3bIgBTODgVq1edwqp6UjN
-ECLAOe1p03GGMr4WSPDoFjlQlHy+NLUwZg3RI+HsAkow9WfP7KqGN4vFDC4ru9Pg
-2uD28oTrOgYQpzKjQJSH3kC5feOUdrsET7zic75XO1J33CAlgbIZ2TSQDqnH2cY5
-bQsWSNA2Lle3wBbeHlCy7ACiaoeJS23TJV9n8PcsRwSmHA9NgT4WSavXwtZ0lBhI
-60GY80VXo9ziQjvVTMZNymZ4FEqCvULHGhFI08Jqd1jOXjnPLY4WEARqkicBJvI1
-3t4sBLDU+PEqH7m8k3lCZd6D7XVDcc8bJock+DjXZIMbZY79UMuzyHocXNJpRfRT
-cqS0qneltFe6Pea7y0PN2IDttGBLb1CVQpXhRkpFU8jtyXh3ulSZSJEeqLVRFgdv
-PVwHWAhLPewVGDkgTrlWVNfiXxp1LWVTFzQFas9xWiY4byQk/DNQaaFwHpGoZgVc
-qAzUVk20Msm2u9xvSbPcBGk0dL4fdlnOkyeq/k/fnNrGdRHJWuJe7QR73/N0u6fy
-7H76xUXvcwwrxL8ma8nV9K+A7oM7YUiR1wagD9cnoDDBgQmH9Izvfw0PxJgqnLOe
-lQGPVGRhmXNtLLG57dqgjrvERGy9u5NMxBlkH0giZTFyQXPQ+N75ouM4S3RL75PM
-UaTOBtnyCj++5ysnDFlGqEXgy08rrtkCbbNfd9dnO568juXS6ExC6TEL/pUMhy+Z
-ooIJ69Tt7R5dOLaKRrkX/nKHfCfLfXXnjyDmdRHRYrXvTWusF038OsqY89tb0F0u
-S4Szv4/Bl1bhzx/XYMZv/y7XL0va8FQLiRTuvqJ9hTsE/Xkd4ZFrP1LaP6HzVR1g
-tsFs2Gc8j7H299U3WLjNon0TL2uPXa77Vu+9h7QCi1W9Uzsv0xMvZ/KMEnXyaEBd
-W1lqo85ih1nnfxcW+lmAz8QNGQ==
+AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V
+a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI
+7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5
+wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M
+IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y
+2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl
+E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH
+9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y
+H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6
+68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li
+WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIJCjCCBPKgAwIBAgIJAI+QZnVEkxq/MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV
-BAMMD3Bvbnl0b3duIFJTQSBDQTAeFw0xNzA0MTAyMDU2MjdaFw0yNzA0MDgyMDU2
-MjdaMBoxGDAWBgNVBAMMD3Bvbnl0b3duIFJTQSBDQTCCBCIwDQYJKoZIhvcNAQEB
-BQADggQPADCCBAoCggQBAMD0iyFqRCNhvD5T9WXO8caNGb5ecrlnqSUvfcc+6Xh9
-sShtK6DX2DZ+6YT2WWOZTk0I9T+XG2kujjyfdCbEDMWcT9so7/gPeIG/qFlhONCu
-HC+zntuZrGgMEYpF3Xc41CyF3saredTJEo1J64TPEke8mohezIGZYM1vTtRnqW+1
-RstSNTu8a/B0VaG0iA5P5RuSGVmxczi4EWJtuXFhcbgqICaUt0vJdrU0Fmrmq0Iq
-ZEIpgZKYirx5QW8b6Q5tv0YsnXNasXvHZQve4GgF449ewk9wWfYevD8UttHUEe2a
-QeEKb2l7NxqyY6trGyVtTRlm4SnoOH/9VodTKUEmS6pds6XFtjRflxgom0TL7CXb
-uJ9b6fkXQlnf01FqAbv5HC1sjgGlSZc7Yk8k09nWOR8mZMoHC+U4KEq+oM+m87q4
-U/GsEk8UsPslGIIHHK6W/sdU6zA9bR3QYmkD40Z7FbVfKVvDmKPlwI7NONqysD8V
-UTPoB8aE7FeulZhlTxdK2EcW14AsjbFiPQ4zAVxj4bRj39RLgJYL+BvAF6PfRHb1
-Xb7ykbuTvT7VhNYXLlQagR9EyixT3Wu9WCWUc0xJKSATn1s2YBLNM7LO4MkYO9WG
-YrejhNHG+54a7rtnnlG04Gs7OhM32baMH/DxT+EEAX4j0Dfww4RaCZcfq1gDPsVe
-+RzqsjjqF8+IzE25SK38xgwT/o3n9r5Ele3/zadwy695KCfbkhVFSDAPvhiv8um5
-6NNP+dDymFRXGzV85xSK75ue3Dpj+MoSScmIdGLEcU5EqYcBFLCXGLYPDIW8Lb89
-mG1z7TkZOLIs+6v7kp4rrvyijsyLFZ+EKUmabAK42qdzASZ1o6ETDDfFBETMxjWA
-oMmGmRkhsyfBTuCr1ESlTBQHj4vvxBrgXgHtHwUinBw/sofLbkFRZ4wz/cBOtwqW
-HIu88/o33l6ywMowcjaoToIbK2a4rD/KFJiwLliGKZG2veiESRhnNUQyjxT/PIef
-0gqx3i1eBGWvfQs/wUC8qI5UadTRhjMFCwMCDVycevZE8lcQ+7zi9tVu6mXife5J
-yP/jxRNDLzpdM6C6puqk0XieZey782XZ7sPpDpS2tphwakINF/5X3t1qZsssZPqq
-F1S2VIsL8qm6Z7HDHXex3o2tDUhc226YSp/T7D+IWP3UCs0NjJrldakhnAd7ykxT
-b2cDh09GDYSbji4Y6WmgIbSAurqk6kt4MWrfx4yfEAlp8ujH6788lRDAiXN1RgzC
-k8r21IOJONDG7Qk1rS0YUV4XyGz4SEpBdPTI7RM1fl5bDn4e+OslBcfWh5XplZrz
-4D4Z9YWVZ8X6d7CiPYZIg35oo/45KGel3Z8algziVkMCAwEAAaNTMFEwHQYDVR0O
-BBYEFOWXlO0crUtBejJo87v9lwg8PlE6MB8GA1UdIwQYMBaAFOWXlO0crUtBejJo
-87v9lwg8PlE6MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggQBADUQ
-YqVmS9o3/5Qp7Tr+JL5ZNRP1fRmV5kAqaKDC5I9ONKRYahHvoI0ojE/j+pmwI4gf
-mp5mW8EgsNfooovrzVSHxJgBO9r1ogMlL9AvwlvVxLbexvLXpM/1QjD/7FID/TaK
-1q5mhSBKaEYXqQ+8DN25aVsI/bwHx4eP11Ft6YjhPqaX/WutE/IIAMbgASRFtBlO
-foTm++fpdn8rCg5LiLLpWrRLC3zUSUtFd7if3wQ4vcDdck09v9PjD5Lk34aYkowJ
-oARbVmBMpAxwkMXaThP1fT7xlYPDhAA26UXksT5xUNzFPbmOVReuFT0drhJlF6e6
-SLTjy2BcrYuz5ieBmmY6QboBYH3SzUFKuamvnHLSic3i3u9Ly68XUjOtDKgYB7Y5
-oZtfZT+YFmz/R6eLUcGRRfcmLJ+i/OXjgyKVkYBMDafW3RI9fRp46Yr/lvOv5gFW
-Vrn3Tfc9cSbYQgE4vuKXcs4aVVeX8uAyjcucMV3eLdxaBLUAezTpJseRfqtH2kCk
-3JIV6m2y6Tm5EhhaSiHKbe6FtPFKhpu7m9AlquUzhBU9Aq59mbKp6jtV0mWhYwKB
-K6REmWQqqAOtHIs7UIXDeN1ZByJ7q+et57RvMgMHc5My0d6a+gQAUssH4i73sVTz
-Uej57DW9L7hK0GQpzGzGIO/9lYTzWMVa8EZG1Fa5nUgMh3N3Oy6qUQIqr8E8xT2O
-IbKKV6Acx6lBiwii4JkruEMgVVEdsDWDVdP8Ov5lJvvIPLWLqnXsZ2sKCyZrVkgc
-PTXVtYBLmn7Tuwody2MSaBONSqleJ1oPQJ9lsAKyqX4xpX05ZJu2kNhST2oq2127
-378GS85DqKDM3P187mjU2G8moqWaGKr6byiIr7ea5TkqIzpC3tKW5QRHvX9aanz0
-akQx6F+l3l4L8J0cXaKasUJTaCk3cWPbbVzo8tQwwdxd0/MdJWrmitK85o+4gLqG
-Cvn9VA4mnhjRR0XccxEtzmhSxBRWXoCF1+FnfDmXhPji+AmAhVqRwPkqX9T9H+54
-YG2ZA9Trxssme+QFSFCPZrHuw66ZI6GmKo6h+Hr2qew7LytASN+x2QyvRf7tSNmf
-oUgmiD+CFpaH6exjrCC0/hcJ53Kv3E5GBvQskvOqgsUkW+nmsrm95YOosn+9MoQc
-PIM6zQCmZ0N/6jHrEHnOnSnz03tGHsvPs6tMB6DKhQz9FNqlrLG7UHhlqhFWj9nv
-H+Zh0oOwbcgcoxkk+W6LHLDpA3UpC1tlOzTlD2ektACvQQr/2A/fecpJN/7iWlX9
-BimWwRTS24bO5dX92Kb8V1TNO6ARd9TqOkPXRatysyh7it/MXpc5I2+t49hqlXoV
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/mio/server/bin/end.rsa b/samplecode/mio/server/bin/end.rsa
index 47deca38..4ba9c7a9 100644
--- a/samplecode/mio/server/bin/end.rsa
+++ b/samplecode/mio/server/bin/end.rsa
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/samplecode/project_template/app/rust-toolchain b/samplecode/project_template/app/rust-toolchain
index 4e7e21b0..0f99c85c 100644
--- a/samplecode/project_template/app/rust-toolchain
+++ b/samplecode/project_template/app/rust-toolchain
@@ -1 +1 @@
-nightly-2022-02-23
\ No newline at end of file
+nightly-2022-10-22
\ No newline at end of file
diff --git a/samplecode/project_template/enclave/rust-toolchain b/samplecode/project_template/enclave/rust-toolchain
index 4e7e21b0..0f99c85c 100644
--- a/samplecode/project_template/enclave/rust-toolchain
+++ b/samplecode/project_template/enclave/rust-toolchain
@@ -1 +1 @@
-nightly-2022-02-23
\ No newline at end of file
+nightly-2022-10-22
\ No newline at end of file
diff --git a/samplecode/tls/tlsclient/bin/ca.cert b/samplecode/tls/tlsclient/bin/ca.cert
index a18fb02c..3a84cbe6 100644
--- a/samplecode/tls/tlsclient/bin/ca.cert
+++ b/samplecode/tls/tlsclient/bin/ca.cert
@@ -1,51 +1,30 @@
-----BEGIN CERTIFICATE-----
-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
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/tls/tlsserver/bin/end.fullchain b/samplecode/tls/tlsserver/bin/end.fullchain
index 2ea11e48..380ec768 100644
--- a/samplecode/tls/tlsserver/bin/end.fullchain
+++ b/samplecode/tls/tlsserver/bin/end.fullchain
@@ -1,113 +1,81 @@
-----BEGIN CERTIFICATE-----
MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u
-eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE3MDQxMDIwNTYyN1oX
-DTIyMTAwMTIwNTYyN1owGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCa4nonCxArES+kBBf9mZoaQ2GBMg74
-Pj2ve4RKJSIBt9A7EgJ4hFznFQ11O11Xvb3dVQGOK+pFRxh2xg0DJvV3lJytpvKe
-mviyT5KSGvp6Hybqmx66B2V3iDfrXhhySqG5tKEeczFBIq+62dAp0+r0oSdpZKGT
-1YDtXonjcbnDb93K7g8arEadFKYN3MAjBGQ3m5fsWJJuq4hLU1+dpmAfxmYH1dlc
-n89LyPhYh0I7R5v17VrGlNCWIWD1emLtM8vTS94eMtp8R6MuMIZTOKgBTrIpU4G5
-GPcR3flDzzLsCxEttjjMa41zStKXzieUIwirRAzPv48V4JlkCCUPv97pAgMBAAGj
-gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFNn77YZg
-4AGguHBKVggK00dtRvhCMEIGA1UdIwQ7MDmAFGuwcG2Zfyr92yAiXU9HP9rBYC6/
+eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTE5MDYwOTE3MTUxMloX
+DTI0MTEyOTE3MTUxMlowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdwbEc6ZKih4mQA916JwctBZgnRmzO
+KERrzlHjfzy8ZfsUJLENQBN8s3RVRwPThReHdp8bpiVRrNmMRxyXoa5oqxWDjXOu
+5W4hoISIMbOAq4Kj8G+eS0UKwypKHwJ1aUzEjWQGKxNpIYvcGqwYpN1Yi1+qTgLg
+2qw1ENtBhrWHhmQruGqDtQTQLe2tbcOuGhIL0cyWIRtEWHWL/wb1Akzhm31WQF+m
+URtYvYonA/Ta7ErONXCxsEXndTR4iT/XognnOhTJ+uIinNwn52y9Te7MYix6SDBE
+VeKZx9v3iOYU81zXf+WaxNqZvTfbPjkLsXiymOgVfGQcO4hiQeLoJIHXAgMBAAGj
+gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFEweXJqS
+BzVcf/00QeOC29OwBQszMEIGA1UdIwQ7MDmAFEKPy8hHZVazpvIsxFcGo4YrkEkw
oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO
dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0
-MA0GCSqGSIb3DQEBCwUAA4IBgQB4xB9IPNxkJIA8QtngQZCCSPH5SjfAibcLfwi2
-NLHe4hO4HvoIVv0ru7CODfq45qNfH7sUj8a/JBU8BwcJ3xPewWFdavtCP8+dapmd
-pr831+Xx6p9tNIdW16WrCXEV8i9bHy43Y4pWbNdXQy5meI0qvSM/ExedZqqVeJJT
-oXL/aCtMsBixlwlKvrsG9ZvIAl1ics0wA5kqQWVufe95loI+HUcPc9s9689H+/ON
-lH8rTLPwyufk9h2dTb9Wzw3qewlDIqgoyX7k9cOwrJqA4D6typCvb5dWfQlK9c72
-4rGbqHSx7mrlaZ4typfAMdEbynRlDSgIIZGXb7RaoV3NT2XuVFd8+lcXgBiJMvPk
-STejz77EPR2+uKvQ1gMJXpEHCBUvMMyDqhpcNzb0DaXgf4eYI9RqfxU1pkgYnfxe
-DGDGI2SdmO43NwSDyEQVSlRpCIBj4ZDay3IP7mbdi8MLxR9H1BCHnN7D04UrTnuA
-c/cl0RMWL+iHtKU2cCxltEQQ9qQ=
+MA0GCSqGSIb3DQEBCwUAA4IBgQCViHp2pLcIMzl/wN+sULznLYZvrlynU4AHnL8/
+ba6iSAM6EMlrcu11+UBQglHIN2BEn+Jjas+HT1sQOIOixMgjrMBgirLez8n5DN66
+o5aK5bu23GjQvzq5JEh0skQDHtSFX0YRwqXIhi1spGtObsnoupxJNBQbdAcDv50/
+m6/8WXcPbXBnR+wRywFmjb6+OSVNgCRtBFTbR5XRVHMPEwvSk4hVj4jimlnPHZYL
+3VatCPtZr6iaLZl9E64BbS+J4vPQ0Z/2JMUjtXCuj19k8LO2TTTBz54QVoMF5jrZ
+xotneq+wmPH3lmozEOmyj4+4CmoyNz+RDhrlok84x3g4YEKUQyK1V4ROi9DtL1CV
+VoLfHSwS9SiDdD/Qn2n7RICn6DP2lHozICyHX0Op4W+vETHho7Flsw21bMisAGrl
+wwQ7UYU4XfPOC9hQoCvU60uVe7z+uZvlBY8RwmcW4iFIbfCcPT6Hrom5F1X4Z/dm
+zDW8ZhLDsjUY/D4lUeWjbO1RCHI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIGnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255
-dG93biBSU0EgQ0EwHhcNMTcwNDEwMjA1NjI3WhcNMjcwNDA4MjA1NjI3WjAsMSow
+MIIEnzCCAoegAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255
+dG93biBSU0EgQ0EwHhcNMTkwNjA5MTcxNTEyWhcNMjkwNjA2MTcxNTEyWjAsMSow
KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G
-CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDCX7V0gKGQBS64QKntjDlBslbQJaxq
-EL8Yyq+qjF6nkOoqENKWSzeNyQ76kPVlzeV03UCaIgTF4+FeQrUr7wauEz0FGmDh
-yx/B4xy9ZXdBIftPB8iz8Q/KrKO6YM6tkj7ijvL8hP3MfssBkA+VoAxamPSIikfM
-9kyttemjYizgM0ywebzKmQGJbEINZ80Kp63ayR/Uo/cORjlH3xbmtTsL3pd+k6Ro
-xOMZKm1RIwOwGgxDW4ea294A4lXHwfwHGMsP0/xmqTZ0R/EpxLKeqJAQffTiVsBK
-YEFzANn3nol1IYrdcZcgcs16KTnc5+XyL87KSdIgDgG3wmQvRCdLX5G6GChyP03Z
-qQSYMkwGSNgCD1v4m14Z5XT2su7iilHfjsucvT4OukCe63nqeXIZ+w63YqbjTp/a
-HMgrXVg1wMlSncl0OIKcjLOgJ5vbPOGk9DvF93JbRFp/9sAZmK89Ur4gBmgpq2Zn
-bknK0LVt+aerP7rf8CPYE89olPVUW0owwrkCAwEAAaNeMFwwHQYDVR0OBBYEFGuw
-cG2Zfyr92yAiXU9HP9rBYC6/MCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF
+CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCj/tOFeSW3WB+TtuLCR1L/84lZytFw
+zbpzOTGB1kPEKNbrMsv3lHXm5bHa8Bl3k113k7Hi7OAt/nkMm05s8LcUoovhaG5C
+G7tjzL+ld1nO74gNS3IQHCzxRdRwIgaDZHyICfBQBfB9/m+9z3yRtOKWJl6i/MT9
+HRN6yADW/8gHFlMzRkCKBjIKXehKsu8cbtB+5MukwtXI4rKf9aYXZQOEUn1kEwQJ
+ZIKBXR0eyloQiZervUE7meRCTBvzXT9VoSEX49/mempp4hnfdHlRNzre4/tphBf1
+fRUdpVXZ3DvmzoHdXRVzxx3X5LvDpf7Eb3ViGkXDFwkSfHEhkRnAl4lIzTH/1F25
+stmT8a0PA/lCNMrzJBzkLcuem1G1uMHoQZo1f3OpslJ8gHbE9ZlIbIKmpmJS9oop
+Vh1BH+aOy5doCrF8uOLTQ3d5CqA/EZMGahDHy7IkeNYmG/RXUKNltv+r95gwuRP+
+9UIJ9FTa4REQbIpGWP5XibI6x4LqLTJj+VsCAwEAAaNeMFwwHQYDVR0OBBYEFEKP
+y8hHZVazpvIsxFcGo4YrkEkwMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF
BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jANBgkqhkiG9w0BAQsFAAOC
-BAEARD9wwIHsAFWlzrRLw3JcAUDB906Ks7KZzdqe3n6FkbyHHP1N5JG25wXwgADS
-qux6sZU7h6+q209IEqXWbw+nbxJs/3D1hLN6X2tVgsfkSflGsd3DfNPZI8qKUyOD
-VYlql/EPEMBixXOeVpwxXc48rX/yVjxqCvhY/A7eIiAc+bzQtwozLppChyVitQGI
-MViXRdGdFiybwTKoJMYXl6ztamk9TWhdvJ9znirol12b06Z3J0Kz0c/kqY7VVZqL
-ba76+IAJjvWQE7PYEOqpFHOLpilv9j5d/0kBR4AgJaooFwcYnr6aJKfNUgGWEmdn
-ELYmfa0qORllAM/yGoewRfWGLZBNgT0QFYg2IFjnp0W0wIXFRd7xVqldN+cTmMqk
-szpVV7bqGvuk6SQNFjIZ8VIVc/mXua4WlwBODDRzKqU3bIgBTODgVq1edwqp6UjN
-ECLAOe1p03GGMr4WSPDoFjlQlHy+NLUwZg3RI+HsAkow9WfP7KqGN4vFDC4ru9Pg
-2uD28oTrOgYQpzKjQJSH3kC5feOUdrsET7zic75XO1J33CAlgbIZ2TSQDqnH2cY5
-bQsWSNA2Lle3wBbeHlCy7ACiaoeJS23TJV9n8PcsRwSmHA9NgT4WSavXwtZ0lBhI
-60GY80VXo9ziQjvVTMZNymZ4FEqCvULHGhFI08Jqd1jOXjnPLY4WEARqkicBJvI1
-3t4sBLDU+PEqH7m8k3lCZd6D7XVDcc8bJock+DjXZIMbZY79UMuzyHocXNJpRfRT
-cqS0qneltFe6Pea7y0PN2IDttGBLb1CVQpXhRkpFU8jtyXh3ulSZSJEeqLVRFgdv
-PVwHWAhLPewVGDkgTrlWVNfiXxp1LWVTFzQFas9xWiY4byQk/DNQaaFwHpGoZgVc
-qAzUVk20Msm2u9xvSbPcBGk0dL4fdlnOkyeq/k/fnNrGdRHJWuJe7QR73/N0u6fy
-7H76xUXvcwwrxL8ma8nV9K+A7oM7YUiR1wagD9cnoDDBgQmH9Izvfw0PxJgqnLOe
-lQGPVGRhmXNtLLG57dqgjrvERGy9u5NMxBlkH0giZTFyQXPQ+N75ouM4S3RL75PM
-UaTOBtnyCj++5ysnDFlGqEXgy08rrtkCbbNfd9dnO568juXS6ExC6TEL/pUMhy+Z
-ooIJ69Tt7R5dOLaKRrkX/nKHfCfLfXXnjyDmdRHRYrXvTWusF038OsqY89tb0F0u
-S4Szv4/Bl1bhzx/XYMZv/y7XL0va8FQLiRTuvqJ9hTsE/Xkd4ZFrP1LaP6HzVR1g
-tsFs2Gc8j7H299U3WLjNon0TL2uPXa77Vu+9h7QCi1W9Uzsv0xMvZ/KMEnXyaEBd
-W1lqo85ih1nnfxcW+lmAz8QNGQ==
+AgEAMzTRDLBExVFlw98AuX+pM+/R2Gjw5KFHvSYLKLbMRfuuZK1yNYYaYtNrtF+V
+a53OFgaZj56o7tXc2PB8kw4MELD0ViR8Do2bvZieFcEe4DwhdjGCjuLehVLT29qI
+7T3N/JkJ5daemKZcRB6Ne0F4+6QlVVNck28HUKbQThl88RdwLUImmSAfgKSt6uJ5
+wlH7wiYQR2vPXwSuEYzwot+L/91eBwuQr4Lovx9+TCKTbwQOKYjX4KfcOOQ1rx0M
+IMrvwWqnabc6m1F0O6//ibL0kuFkJYEgOH2uJA12FBHO+/q2tcytejkOWKWMJj6Y
+2etwIHcpzXaEP7fZ75cFGqcE3s7XGsweBIPLjMP1bKxEcFKzygURm/auUuXBCFBl
+E16PB6JEAeCKe/8VFeyucvjPuQDWB49aq+r2SbpbI4IeZdz/QgEIOb0MpwStrvhH
+9f/DtGMbjvuAEkRoOorK4m5k4GY3LsWTR2bey27AXk8N7pKarpu2N7ChBPm+EV0Y
+H+tAI/OfdZuNUCES00F5UAFdU8zBUZo19ao2ZqfEADimE7Epk2s0bUe4GSqEXJp6
+68oVSMhZmMf/RCSNlr97f34sNiUA1YJ0JbCRZmw8KWNm9H1PARLbrgeRBZ/k31Li
+WLDr3fiEVk7SGxj3zo94cS6AT55DyXLiSD/bFmL1QXgZweA=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-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
-9Xpi4ds6s2cT8zZGDKI=
+MIIFFTCCAv2gAwIBAgIUGXgsGl4sGhiPwUPOme5w5jJscVQwDQYJKoZIhvcNAQEL
+BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTE5MDYwOTE3MTUxMVoX
+DTI5MDYwNjE3MTUxMVowGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArpW4WHfSmTCMvnDJaCRL5BR2knDc
+C+T4/wv7i//zsBL3q0YVdBpllWCZx8TSfuXT/1o/Zxdt+H1ZjnH8yuwuHOToE3W0
++Y/912hAPiD+d79A+MtqVX1gayjHDy9HybznTN2Onh1ZhWyks0FLL5SB0vVCLwXP
+W7tcyY0w6wn3RTw4nBu7co5a280cHgHv5V3XeNgteQrnkXE9TfuqqUZwVt0v1jr1
+bk1KaDDD+36wfeO70Q6CeLwKPhN0mPDHdj/lecj4efl0l1B0ehHxLkLuztqtkCF6
++yMoBrEyzJjO6TGMSTMsnw4F9bA15jkIIEQs5FhwVHFOTmu5BG+j37umoy27k5As
+5cV0/djr3r8WhBZ6w2+XjvbAdJPgqc+Xobnx1i5GI4noRC4G4Cl0Vx+iRru1/nsE
+xPazz9UVkiUsDlN9n49f1pik9z74Box6CD6IZVb8h4vV7um+0R4/eErVf/Cyf1Xe
+axVaOgA/CD0ucLdSfDz61O/2PG3P7YjWY1R9zr35e8pakgyFPXnWMbsfniuGkM0X
+6lG743Q7yVt38/HuAqi1AGq+r/AKisrezt97UNm0CryuEk02y4SVLbhuG/V6mBCh
+4Va3KD1ZOgfJcTZbuxebIz6W+5jL80hE0YwBBs8vSv8Fo5N7dYNSNvyMxkoPh8Gw
+CAFyqt5zBLGCEvkCAwEAAaNTMFEwHQYDVR0OBBYEFDjj6hEpDZdjAIdvd9Moe3un
+RvJWMB8GA1UdIwQYMBaAFDjj6hEpDZdjAIdvd9Moe3unRvJWMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggIBACu+Ct6J+Dh3EXFOgjW3gN3CaD0UK0kW
+03u7znNAJBAYhi+MXSTPBdrxYGOPkHF1Jl15qb2fc58+0nakf8bvah8kgxi2ujX8
+vrPBjsAv/ixPvUrcol9ZGrseP5DdFS8pw1FoDR/JdgNCdSM4xC3GSk2SLYs+QSJx
+YG3nQLOAZEvnbiZ4zBZ0wVct4w9jrxtqdq2eS8cLoRVx715MzKPBCGEccYu/py5a
+gkyclr16s0mb+wN49of34AQ+xXguHZGNZzCy6PTbx0IC+sRVe82+RZkj21JG+AFM
+9s+vLgRdtWIEZW1AIYbUUbhuvsne+sidZW5XQuFp1V4LlQbO49oEhrPMBn+oHKg5
+MWIe68bjkqDSnDzG+TEBTWiAhyyGyZcebfCs72DGbYrfKt1uTyi+groumPnvQfJB
+y3kqy2pUFeEkNJkx4BfYL+N7I07s9WTy8UMoqn/OLuyqoFaYMd9XMaOOx3xTy8aw
+pUJ69c3VI66W/Ii1ypk2EPUImWpG/n89Y/8Mk1NbesaZLk9feTDfbM4VNPkQU+7T
+3DNQxPSswSh4nXGURwC46SOu2s1lRA98ZXkP5XhUvTuvfg/e4suq26OqjORHQ5zI
+57NP+uHRrfHGlrQ196j1Maw7W7vkocbEv8/06v6s54CG8ezzD2nt1QrLJqSpUqHo
+qolvgn/PK+gg
-----END CERTIFICATE-----
diff --git a/samplecode/tls/tlsserver/bin/end.rsa b/samplecode/tls/tlsserver/bin/end.rsa
index 47deca38..4ba9c7a9 100644
--- a/samplecode/tls/tlsserver/bin/end.rsa
+++ b/samplecode/tls/tlsserver/bin/end.rsa
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/sgx_align_struct_attribute/Cargo.toml b/sgx_align_struct_attribute/Cargo.toml
index 5cadf18e..5403d72b 100644
--- a/sgx_align_struct_attribute/Cargo.toml
+++ b/sgx_align_struct_attribute/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_align_struct_attribute"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_align_struct_attribute/src/layout.rs b/sgx_align_struct_attribute/src/layout.rs
index 861f9eee..356885a5 100644
--- a/sgx_align_struct_attribute/src/layout.rs
+++ b/sgx_align_struct_attribute/src/layout.rs
@@ -124,7 +124,7 @@ fn check_align_req(size: usize, align_req: &[AlignReq]) -> bool {
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/Cargo.toml b/sgx_alloc/Cargo.toml
index f0d1f1c2..58ce519f 100644
--- a/sgx_alloc/Cargo.toml
+++ b/sgx_alloc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_alloc"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_alloc/src/alignalloc.rs b/sgx_alloc/src/alignalloc.rs
index b83c130c..ffd292d7 100644
--- a/sgx_alloc/src/alignalloc.rs
+++ b/sgx_alloc/src/alignalloc.rs
@@ -308,7 +308,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 5a888b2d..594f1004 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/Cargo.toml b/sgx_backtrace/Cargo.toml
index cab06623..3aa45670 100644
--- a/sgx_backtrace/Cargo.toml
+++ b/sgx_backtrace/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "sgx_backtrace"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_backtrace_sys/Cargo.toml b/sgx_backtrace_sys/Cargo.toml
index e7669112..cc3425a5 100644
--- a/sgx_backtrace_sys/Cargo.toml
+++ b/sgx_backtrace_sys/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_backtrace_sys"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_build_helper/Cargo.toml b/sgx_build_helper/Cargo.toml
index dc23478c..49649ef6 100644
--- a/sgx_build_helper/Cargo.toml
+++ b/sgx_build_helper/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_build_helper"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_cov/Cargo.toml b/sgx_cov/Cargo.toml
index e53df42f..78ec10a0 100644
--- a/sgx_cov/Cargo.toml
+++ b/sgx_cov/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_cov"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_crypto_helper/Cargo.toml b/sgx_crypto_helper/Cargo.toml
index c4967401..1f37036b 100644
--- a/sgx_crypto_helper/Cargo.toml
+++ b/sgx_crypto_helper/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_crypto_helper"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_demangle/Cargo.toml b/sgx_demangle/Cargo.toml
index f2578e1e..e836f4ea 100644
--- a/sgx_demangle/Cargo.toml
+++ b/sgx_demangle/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "sgx_demangle"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_edl/Cargo.toml b/sgx_edl/Cargo.toml
index e0adf67f..8956085b 100644
--- a/sgx_edl/Cargo.toml
+++ b/sgx_edl/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_edl"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_edl/edl/sgx_fd.edl b/sgx_edl/edl/sgx_fd.edl
index 8cfc822e..cd668b71 100644
--- a/sgx_edl/edl/sgx_fd.edl
+++ b/sgx_edl/edl/sgx_fd.edl
@@ -19,6 +19,7 @@ enclave {
include "inc/stat.h"
include "sys/uio.h"
+ include "time.h"
from "sgx_mem.edl" import *;
@@ -37,11 +38,20 @@ enclave {
size_t u_writev_ocall([out] int *error, int fd, [in, count=iovcnt] const struct iovec *iov, int iovcnt);
size_t u_pwritev64_ocall([out] int *error, int fd, [in, count=iovcnt] const struct iovec *iov, int iovcnt, int64_t offset);
+ size_t u_sendfile_ocall([out] int *error, int out_fd, int in_fd, [in, out] int64_t *offset, size_t count);
+ size_t u_copy_file_range_ocall([out] int *error, int fd_in, [in, out] int64_t *off_in, int fd_out, [in, out] int64_t *off_out, size_t len, unsigned int flags);
+ size_t u_splice_ocall([out] int *error, int fd_in, [in, out] int64_t *off_in, int fd_out, [in, out] int64_t *off_out, size_t len, unsigned int flags);
+
int u_fcntl_arg0_ocall([out] int *error, int fd, int cmd);
int u_fcntl_arg1_ocall([out] int *error, int fd, int cmd, int arg);
int u_ioctl_arg0_ocall([out] int *error, int fd, int request);
int u_ioctl_arg1_ocall([out] int *error, int fd, int request, [in, out] int *arg);
int u_close_ocall([out] int *error, int fd);
+ 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_libc/Cargo.toml b/sgx_libc/Cargo.toml
index 1a46645a..749f059a 100644
--- a/sgx_libc/Cargo.toml
+++ b/sgx_libc/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_libc"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_libc/src/lib.rs b/sgx_libc/src/lib.rs
index 01d2dd1d..4ec71889 100644
--- a/sgx_libc/src/lib.rs
+++ b/sgx_libc/src/lib.rs
@@ -22,6 +22,7 @@
#![allow(overflowing_literals)]
#![allow(non_snake_case)]
#![allow(unused_macros)]
+#![allow(unused_imports)]
#![allow(clippy::cmp_null)]
#![allow(unused_assignments)]
#![allow(clippy::missing_safety_doc)]
diff --git a/sgx_libc/src/linux/x86_64/mod.rs b/sgx_libc/src/linux/x86_64/mod.rs
index dc55613b..213c2064 100644
--- a/sgx_libc/src/linux/x86_64/mod.rs
+++ b/sgx_libc/src/linux/x86_64/mod.rs
@@ -110,7 +110,7 @@ extern "C" {
/// Get the last error number.
pub fn errno() -> i32 {
- unsafe { (*errno_location()) as i32 }
+ unsafe { *errno_location() }
}
/// Set the last error number.
@@ -121,7 +121,7 @@ pub fn set_errno(e: i32) {
/// Gets a detailed string description for the given error number.
pub unsafe fn error_string(errno: i32, buf: &mut [i8]) -> i32 {
let p = buf.as_mut_ptr();
- strerror_r(errno as c_int, p as *mut c_char, buf.len()) as i32
+ strerror_r(errno as c_int, p as *mut c_char, buf.len())
}
pub unsafe fn memchr(s: *const u8, c: u8, n: usize) -> *const u8 {
@@ -512,6 +512,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;
@@ -1420,7 +1423,7 @@ pub const SA_NOCLDWAIT: c_int = 0x00000002;
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_usize;
pub const SIGTRAP: c_int = 5;
pub const SIGCHLD: c_int = 17;
@@ -1562,7 +1565,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
}
@@ -1617,7 +1620,7 @@ pub const fn CMSG_ALIGN(len: usize) -> usize {
#[inline]
pub unsafe 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 {
ptr::null_mut::<cmsghdr>()
@@ -1641,13 +1644,13 @@ pub unsafe fn CMSG_LEN(length: c_uint) -> c_uint {
#[inline]
pub unsafe 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 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
{
ptr::null_mut::<cmsghdr>()
} else {
diff --git a/sgx_libc/src/linux/x86_64/ocall.rs b/sgx_libc/src/linux/x86_64/ocall.rs
index c6a0c826..422a5f82 100644
--- a/sgx_libc/src/linux/x86_64/ocall.rs
+++ b/sgx_libc/src/linux/x86_64/ocall.rs
@@ -351,6 +351,34 @@ extern "C" {
iovcnt: c_int,
offset: off64_t,
) -> sgx_status_t;
+ pub fn u_sendfile_ocall(
+ result: *mut ssize_t,
+ errno: *mut c_int,
+ out_fd: c_int,
+ in_fd: c_int,
+ offset: *mut off_t,
+ count: size_t,
+ ) -> sgx_status_t;
+ pub fn u_copy_file_range_ocall(
+ result: *mut ssize_t,
+ errno: *mut c_int,
+ fd_in: c_int,
+ off_in: *mut loff_t,
+ fd_out: c_int,
+ off_out: *mut loff_t,
+ len: size_t,
+ flags: c_uint,
+ ) -> sgx_status_t;
+ pub fn u_splice_ocall(
+ result: *mut ssize_t,
+ errno: *mut c_int,
+ fd_in: c_int,
+ off_in: *mut loff_t,
+ fd_out: c_int,
+ off_out: *mut loff_t,
+ len: size_t,
+ flags: c_uint,
+ ) -> sgx_status_t;
pub fn u_fcntl_arg0_ocall(
result: *mut c_int,
errno: *mut c_int,
@@ -378,6 +406,20 @@ extern "C" {
arg: *mut c_int,
) -> sgx_status_t;
pub fn u_close_ocall(result: *mut c_int, errno: *mut c_int, fd: c_int) -> sgx_status_t;
+ pub fn u_isatty_ocall(result: *mut c_int, errno: *mut c_int, fd: c_int) -> sgx_status_t;
+ pub fn u_dup_ocall(result: *mut c_int, errno: *mut c_int, oldfd: c_int) -> sgx_status_t;
+ pub fn u_eventfd_ocall(
+ result: *mut c_int,
+ errno: *mut c_int,
+ 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,
+ ) -> sgx_status_t;
// time
pub fn u_clock_gettime_ocall(
result: *mut c_int,
@@ -2173,7 +2215,7 @@ pub unsafe fn writev(fd: c_int, iov: *const iovec, iovcnt: c_int) -> ssize_t {
ptr::copy_nonoverlapping(
io.iov_base as *const u8,
tmpiov.iov_base as *mut u8,
- io.iov_len as usize,
+ io.iov_len,
);
tmpiovec.push(tmpiov);
ptr = ptr.add(io.iov_len);
@@ -2260,7 +2302,7 @@ pub unsafe fn pwritev64(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off
ptr::copy_nonoverlapping(
io.iov_base as *const u8,
tmpiov.iov_base as *mut u8,
- io.iov_len as usize,
+ io.iov_len,
);
tmpiovec.push(tmpiov);
ptr = ptr.add(io.iov_len);
@@ -2292,6 +2334,95 @@ pub unsafe fn pwritev64(fd: c_int, iov: *const iovec, iovcnt: c_int, offset: off
result
}
+pub unsafe fn sendfile(out_fd: c_int, in_fd: c_int, offset: *mut off_t, count: size_t) -> ssize_t {
+ let mut result: ssize_t = 0;
+ let mut error: c_int = 0;
+ let status = u_sendfile_ocall(
+ &mut result as *mut ssize_t,
+ &mut error as *mut c_int,
+ out_fd,
+ in_fd,
+ offset,
+ count,
+ );
+
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result == -1 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
+pub unsafe fn copy_file_range(
+ fd_in: c_int,
+ off_in: *mut loff_t,
+ fd_out: c_int,
+ off_out: *mut loff_t,
+ len: size_t,
+ flags: c_uint,
+) -> ssize_t {
+ let mut result: ssize_t = 0;
+ let mut error: c_int = 0;
+
+ let status = u_copy_file_range_ocall(
+ &mut result as *mut ssize_t,
+ &mut error as *mut c_int,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ flags,
+ );
+
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result == -1 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
+pub unsafe fn splice(
+ fd_in: c_int,
+ off_in: *mut loff_t,
+ fd_out: c_int,
+ off_out: *mut loff_t,
+ len: size_t,
+ flags: c_uint,
+) -> ssize_t {
+ let mut result: ssize_t = 0;
+ let mut error: c_int = 0;
+
+ let status = u_splice_ocall(
+ &mut result as *mut ssize_t,
+ &mut error as *mut c_int,
+ fd_in,
+ off_in,
+ fd_out,
+ off_out,
+ len,
+ flags,
+ );
+
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result == -1 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
pub unsafe fn fcntl_arg0(fd: c_int, cmd: c_int) -> c_int {
let mut result: c_int = 0;
let mut error: c_int = 0;
@@ -2389,6 +2520,78 @@ pub unsafe fn close(fd: c_int) -> c_int {
result
}
+pub unsafe fn isatty(fd: c_int) -> c_int {
+ let mut result: c_int = 0;
+ let mut error: c_int = 0;
+ let status = u_isatty_ocall(&mut result as *mut c_int, &mut error as *mut c_int, fd);
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result == 0 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = 0;
+ }
+ result
+}
+
+pub unsafe fn dup(oldfd: c_int) -> c_int {
+ let mut result: c_int = 0;
+ let mut error: c_int = 0;
+ let status = u_dup_ocall(&mut result as *mut c_int, &mut error as *mut c_int, oldfd);
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result < 0 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
+pub unsafe fn eventfd(initval: c_uint, flags: c_int) -> c_int {
+ let mut result: c_int = 0;
+ let mut error: c_int = 0;
+ let status = u_eventfd_ocall(
+ &mut result as *mut c_int,
+ &mut error as *mut c_int,
+ initval,
+ flags,
+ );
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result < 0 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
+pub unsafe fn futimens(fd: c_int, times: *const timespec) -> 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,
+ );
+
+ if status == sgx_status_t::SGX_SUCCESS {
+ if result < 0 {
+ set_errno(error);
+ }
+ } else {
+ set_errno(ESGX);
+ result = -1;
+ }
+ result
+}
+
// time
pub unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> c_int {
let mut result: c_int = 0;
@@ -3041,7 +3244,7 @@ pub unsafe fn recvmsg(sockfd: c_int, msg: *mut msghdr, flags: c_int) -> ssize_t
}
}
- mhdr.msg_namelen = msg_namelen_out as u32;
+ mhdr.msg_namelen = msg_namelen_out;
mhdr.msg_controllen = msg_controllen_out;
mhdr.msg_flags = msg_flags;
}
diff --git a/sgx_no_tstd/Cargo.toml b/sgx_no_tstd/Cargo.toml
index d85aab82..e5f116f5 100644
--- a/sgx_no_tstd/Cargo.toml
+++ b/sgx_no_tstd/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_no_tstd"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
build = "build.rs"
repository = "https://github.com/apache/teaclave-sgx-sdk"
diff --git a/sgx_panic_abort/src/lib.rs b/sgx_panic_abort/src/lib.rs
index 86925c36..b4b90016 100644
--- a/sgx_panic_abort/src/lib.rs
+++ b/sgx_panic_abort/src/lib.rs
@@ -8,7 +8,6 @@
#![panic_runtime]
#![allow(unused_features)]
#![feature(core_intrinsics)]
-#![feature(nll)]
#![feature(panic_runtime)]
#![feature(std_internals)]
#![feature(staged_api)]
@@ -18,12 +17,14 @@
use core::any::Any;
use core::panic::BoxMeUp;
+/// # Safety
#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
unreachable!()
}
+/// # Safety
// "Leak" the payload and shim to the relevant abort on the platform in question.
#[rustc_std_internal_symbol]
pub unsafe extern "C-unwind" fn __rust_start_panic(_payload: *mut &mut dyn BoxMeUp) -> u32 {
@@ -66,6 +67,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/sgx_panic_unwind/src/gcc.rs b/sgx_panic_unwind/src/gcc.rs
index 56d95ea3..a539b590 100644
--- a/sgx_panic_unwind/src/gcc.rs
+++ b/sgx_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_libc::{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/sgx_panic_unwind/src/lib.rs b/sgx_panic_unwind/src/lib.rs
index 3e2e111b..6d0ba761 100644
--- a/sgx_panic_unwind/src/lib.rs
+++ b/sgx_panic_unwind/src/lib.rs
@@ -1,7 +1,15 @@
//! 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")]
@@ -12,7 +20,6 @@
#![feature(core_intrinsics)]
#![feature(lang_items)]
-#![feature(nll)]
#![feature(panic_unwind)]
#![feature(staged_api)]
#![feature(std_internals)]
@@ -23,7 +30,6 @@
#![feature(c_unwind)]
extern crate alloc;
-extern crate sgx_libc;
extern crate sgx_unwind;
use alloc::boxed::Box;
@@ -42,8 +48,6 @@ extern "C" {
fn __rust_foreign_exception() -> !;
}
-mod dwarf;
-
/// # Safety
#[rustc_std_internal_symbol]
#[allow(improper_ctypes_definitions)]
@@ -55,7 +59,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/sgx_rand/Cargo.toml b/sgx_rand/Cargo.toml
index bdd11ffb..5eda5362 100644
--- a/sgx_rand/Cargo.toml
+++ b/sgx_rand/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_rand"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_rand_derive/Cargo.toml b/sgx_rand_derive/Cargo.toml
index 442abfeb..c4a04b40 100644
--- a/sgx_rand_derive/Cargo.toml
+++ b/sgx_rand_derive/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_rand_derive"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_serialize/Cargo.toml b/sgx_serialize/Cargo.toml
index 457e0093..ccbf57af 100644
--- a/sgx_serialize/Cargo.toml
+++ b/sgx_serialize/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_serialize"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_serialize_derive/Cargo.toml b/sgx_serialize_derive/Cargo.toml
index a9f40849..c9aff5a7 100644
--- a/sgx_serialize_derive/Cargo.toml
+++ b/sgx_serialize_derive/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_serialize_derive"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_serialize_derive_internals/Cargo.toml b/sgx_serialize_derive_internals/Cargo.toml
index 499039d8..7ef5a874 100644
--- a/sgx_serialize_derive_internals/Cargo.toml
+++ b/sgx_serialize_derive_internals/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_serialize_derive_internals"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_signal/Cargo.toml b/sgx_signal/Cargo.toml
index 2502991e..84b1eef4 100644
--- a/sgx_signal/Cargo.toml
+++ b/sgx_signal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_signal"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_signal/src/exception.rs b/sgx_signal/src/exception.rs
index daa541ed..dfeb0627 100644
--- a/sgx_signal/src/exception.rs
+++ b/sgx_signal/src/exception.rs
@@ -26,7 +26,7 @@ use std::collections::LinkedList;
use std::convert::From;
use std::num::NonZeroU64;
use std::ops::Drop;
-use std::sync::{Arc, Once, SgxRwLock, SgxThreadMutex, ONCE_INIT};
+use std::sync::{Arc, Once, SgxRwLock, SgxMutex, PoisonError, ONCE_INIT};
use std::u64;
#[repr(u32)]
@@ -53,19 +53,21 @@ pub struct HandlerId(NonZeroU64);
impl HandlerId {
fn new() -> HandlerId {
- static GUARD: SgxThreadMutex = SgxThreadMutex::new();
- static mut COUNTER: u64 = 1;
-
- unsafe {
- let _guard = GUARD.lock();
- if COUNTER == u64::MAX {
- panic!("failed to generate unique HandlerId : bitspace exhausted");
- }
- let id = COUNTER;
- COUNTER += 1;
- let _ = GUARD.unlock();
- HandlerId(NonZeroU64::new(id).unwrap())
+ #[cold]
+ fn exhausted() -> ! {
+ panic!("failed to generate unique Handler ID: bitspace exhausted")
}
+ static COUNTER: SgxMutex<u64> = SgxMutex::new(0);
+
+ let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
+ let Some(id) = counter.checked_add(1) else {
+ drop(counter);
+ exhausted();
+ };
+
+ *counter = id;
+ drop(counter);
+ HandlerId(NonZeroU64::new(id).unwrap())
}
}
diff --git a/sgx_signal/src/manager.rs b/sgx_signal/src/manager.rs
index 9484e2db..bbf67991 100644
--- a/sgx_signal/src/manager.rs
+++ b/sgx_signal/src/manager.rs
@@ -25,7 +25,7 @@ use std::mem;
use std::num::NonZeroU64;
use std::sync::Arc;
#[allow(deprecated)]
-use std::sync::{SgxMutex, SgxThreadMutex};
+use std::sync::{SgxMutex, PoisonError};
use std::u64;
thread_local! { static SIGNAL_MASK: Cell<SigSet> = Cell::new(SigSet::new()) }
@@ -145,20 +145,25 @@ pub struct ActionId(NonZeroU64);
impl ActionId {
fn new() -> Self {
- static GUARD: SgxThreadMutex = SgxThreadMutex::new();
- static mut COUNTER: u64 = 1;
-
- unsafe {
- let _guard = GUARD.lock();
- if COUNTER == u64::MAX {
- panic!("failed to generate unique ActionId : bitspace exhausted");
- }
- let id = COUNTER;
- COUNTER += 1;
- let _ = GUARD.unlock();
- ActionId(NonZeroU64::new(id).unwrap())
+ #[cold]
+ fn exhausted() -> ! {
+ panic!("failed to generate unique Action ID: bitspace exhausted")
}
+
+ static COUNTER: SgxMutex<u64> = SgxMutex::new(0);
+
+ let mut counter = COUNTER.lock().unwrap_or_else(PoisonError::into_inner);
+ let Some(id) = counter.checked_add(1) else {
+ drop(counter);
+ exhausted();
+ };
+
+ *counter = id;
+ drop(counter);
+ ActionId(NonZeroU64::new(id).unwrap())
}
+
+
}
pub type Action = dyn Fn(&siginfo_t) + Send + Sync;
diff --git a/sgx_tcrypto/Cargo.toml b/sgx_tcrypto/Cargo.toml
index 24e88205..7aa6a4ad 100644
--- a/sgx_tcrypto/Cargo.toml
+++ b/sgx_tcrypto/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tcrypto"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tcrypto_helper/Cargo.toml b/sgx_tcrypto_helper/Cargo.toml
index 2498690f..6e252fba 100644
--- a/sgx_tcrypto_helper/Cargo.toml
+++ b/sgx_tcrypto_helper/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tcrypto_helper"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tdh/Cargo.toml b/sgx_tdh/Cargo.toml
index 2283440c..c417be8a 100644
--- a/sgx_tdh/Cargo.toml
+++ b/sgx_tdh/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tdh"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tkey_exchange/Cargo.toml b/sgx_tkey_exchange/Cargo.toml
index 9f670260..f3234128 100644
--- a/sgx_tkey_exchange/Cargo.toml
+++ b/sgx_tkey_exchange/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tkey_exchange"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tprotected_fs/Cargo.toml b/sgx_tprotected_fs/Cargo.toml
index 2db16b69..d6b3e0bf 100644
--- a/sgx_tprotected_fs/Cargo.toml
+++ b/sgx_tprotected_fs/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tprotected_fs"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_trts/Cargo.toml b/sgx_trts/Cargo.toml
index 385801a1..a8df5226 100644
--- a/sgx_trts/Cargo.toml
+++ b/sgx_trts/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_trts"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_trts/src/c_str.rs b/sgx_trts/src/c_str.rs
index da052e16..7c9b0f77 100644
--- a/sgx_trts/src/c_str.rs
+++ b/sgx_trts/src/c_str.rs
@@ -15,1534 +15,5 @@
// specific language governing permissions and limitations
// under the License..
-use crate::ascii;
-use crate::libc;
-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::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 = libc::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 = libc::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
- }
-}
+pub use alloc::ffi::{CString, FromVecWithNulError, IntoStringError, NulError};
+pub use core::ffi::{CStr, FromBytesWithNulError};
diff --git a/sgx_trts/src/lib.rs b/sgx_trts/src/lib.rs
index 7659bdc3..ac9606e4 100644
--- a/sgx_trts/src/lib.rs
+++ b/sgx_trts/src/lib.rs
@@ -67,7 +67,6 @@
#![feature(allocator_api)]
#![feature(specialization)]
#![feature(vec_into_raw_parts)]
-#![feature(toowned_clone_into)]
#![feature(rustc_attrs)]
#![allow(incomplete_features)]
#![allow(non_camel_case_types)]
diff --git a/sgx_tse/Cargo.toml b/sgx_tse/Cargo.toml
index 3191167e..d5c72dce 100644
--- a/sgx_tse/Cargo.toml
+++ b/sgx_tse/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tse"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tseal/Cargo.toml b/sgx_tseal/Cargo.toml
index 21e63482..f91fcc19 100644
--- a/sgx_tseal/Cargo.toml
+++ b/sgx_tseal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tseal"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tstd/Cargo.toml b/sgx_tstd/Cargo.toml
index 97ec1b37..957a8d85 100644
--- a/sgx_tstd/Cargo.toml
+++ b/sgx_tstd/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "sgx_tstd"
-version = "1.1.5"
+version = "1.1.6"
authors = ["The Teaclave Authors"]
repository = "https://github.com/apache/teaclave-sgx-sdk"
license-file = "LICENSE"
diff --git a/sgx_tstd/src/alloc.rs b/sgx_tstd/src/alloc.rs
index 1e15ff32..240b2bab 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 a491f5d8..6824ced5 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
@@ -300,7 +294,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 {
@@ -441,8 +435,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 RawFrame::Actual(frame) = &frame.frame;
diff --git a/sgx_tstd/src/collections/hash/map.rs b/sgx_tstd/src/collections/hash/map.rs
index 2c5012a4..0626409f 100644
--- a/sgx_tstd/src/collections/hash/map.rs
+++ b/sgx_tstd/src/collections/hash/map.rs
@@ -23,10 +23,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;
@@ -68,7 +69,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].
@@ -123,8 +125,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.")
/// }
/// }
///
@@ -133,7 +135,7 @@ use crate::sys;
///
/// // Iterate over everything.
/// for (book, review) in &book_reviews {
-/// println!("{}: \"{}\"", book, review);
+/// println!("{book}: \"{review}\"");
/// }
/// ```
///
@@ -150,7 +152,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:
///
@@ -177,6 +179,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`].
@@ -213,7 +218,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");
/// }
/// ```
@@ -241,10 +246,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
///
@@ -284,22 +290,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
@@ -313,8 +320,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.
@@ -349,9 +356,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() }
}
@@ -377,8 +389,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() }
}
@@ -398,9 +415,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() }
}
@@ -424,9 +446,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() }
}
@@ -452,8 +479,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() }
}
@@ -473,10 +505,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() }
}
@@ -502,10 +539,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() }
}
@@ -548,7 +590,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
///
@@ -567,7 +609,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() }
}
@@ -608,7 +650,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,
@@ -618,7 +660,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
@@ -630,8 +672,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,
@@ -681,8 +728,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
///
@@ -701,8 +750,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
///
@@ -715,7 +767,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> {
@@ -778,8 +830,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);
@@ -842,6 +893,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
@@ -1907,6 +2069,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>;
@@ -1950,7 +2119,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() }
}
@@ -2689,6 +2858,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;
///
@@ -2846,6 +3016,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 {
@@ -2858,17 +3029,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/set.rs b/sgx_tstd/src/collections/hash/set.rs
index b6b62b62..4e0baedf 100644
--- a/sgx_tstd/src/collections/hash/set.rs
+++ b/sgx_tstd/src/collections/hash/set.rs
@@ -21,7 +21,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};
@@ -47,13 +47,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
///
@@ -80,7 +81,7 @@ use super::map::{map_try_reserve_error, RandomState};
///
/// // Iterate over everything.
/// for book in &books {
-/// println!("{}", book);
+/// println!("{book}");
/// }
/// ```
///
@@ -105,7 +106,7 @@ use super::map::{map_try_reserve_error, RandomState};
///
/// // Use derived implementation to print the vikings.
/// for x in &vikings {
-/// println!("{:?}", x);
+/// println!("{x:?}");
/// }
/// ```
///
@@ -144,10 +145,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
///
@@ -191,11 +193,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() }
}
@@ -239,7 +246,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
///
@@ -251,13 +258,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() }
}
@@ -295,7 +302,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,
@@ -305,7 +312,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
@@ -317,7 +324,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,
@@ -366,15 +378,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
@@ -423,8 +436,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
///
@@ -444,8 +459,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
///
@@ -457,7 +475,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> {
@@ -521,7 +539,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();
@@ -533,7 +551,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 }
}
@@ -550,7 +568,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();
@@ -560,7 +578,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>,
@@ -571,6 +589,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
///
/// ```
@@ -580,14 +604,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 }
@@ -608,14 +632,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)) }
@@ -831,9 +855,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
///
@@ -1381,7 +1406,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()
}
@@ -1408,11 +1433,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/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/enclave.rs b/sgx_tstd/src/enclave.rs
index 1f26a95e..4b1efe83 100644
--- a/sgx_tstd/src/enclave.rs
+++ b/sgx_tstd/src/enclave.rs
@@ -103,7 +103,7 @@ pub fn get_enclave_id() -> sgx_enclave_id_t {
/// set_enclave_id is to set enclave ID.
///
pub fn set_enclave_id(eid: sgx_enclave_id_t) {
- ENCLAVE_ID.store(eid as u64, Ordering::SeqCst);
+ ENCLAVE_ID.store(eid, Ordering::SeqCst);
}
///
diff --git a/sgx_tstd/src/env.rs b/sgx_tstd/src/env.rs
index cae3405c..fda2b4ac 100644
--- a/sgx_tstd/src/env.rs
+++ b/sgx_tstd/src/env.rs
@@ -37,9 +37,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.
@@ -67,11 +69,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
///
/// ```
@@ -125,7 +129,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}");
/// }
/// ```
///
@@ -154,7 +158,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]
@@ -213,8 +217,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> {
@@ -252,8 +256,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]
@@ -263,7 +267,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.
@@ -337,7 +341,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}")
})
}
@@ -378,7 +382,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
@@ -413,7 +417,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<'_> {
@@ -575,7 +579,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] /
@@ -618,36 +622,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.
@@ -662,7 +653,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}"),
/// };
/// ```
pub fn current_exe() -> io::Result<PathBuf> {
diff --git a/sgx_tstd/src/error.rs b/sgx_tstd/src/error.rs
index d795fc9a..ec182b39 100644
--- a/sgx_tstd/src/error.rs
+++ b/sgx_tstd/src/error.rs
@@ -17,150 +17,14 @@
//! Traits for working with Errors.
-// 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;
+#[cfg(feature = "unit_test")]
+mod tests;
-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::time;
+use crate::fmt::{self, Write};
-use sgx_types::sgx_status_t;
-
-/// `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
- }
-
- /// 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`
@@ -169,612 +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 sgx_status_t {
- #[allow(deprecated)]
- fn description(&self) -> &str {
- self.__description()
- }
-}
-
-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
@@ -878,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`.
///
@@ -913,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(())
/// }
@@ -926,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
@@ -960,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))?;
@@ -976,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,
@@ -986,7 +249,6 @@ pub struct Report<E = Box<dyn Error>> {
pretty: bool,
}
-#[cfg(feature = "backtrace")]
impl<E> Report<E>
where
Report<E>: From<E>,
@@ -997,7 +259,6 @@ where
}
}
-#[cfg(feature = "backtrace")]
impl<E> Report<E> {
/// Enable pretty-printing the report across multiple lines.
///
@@ -1033,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:
@@ -1094,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:
@@ -1117,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;
///
@@ -1153,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);
/// }
/// }
///
@@ -1168,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:
@@ -1199,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()
})
}
@@ -1282,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(())
@@ -1295,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();
@@ -1328,7 +531,6 @@ impl Report<Box<dyn Error>> {
}
}
-#[cfg(feature = "backtrace")]
impl<E> From<E> for Report<E>
where
E: Error,
@@ -1338,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,
@@ -1359,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,
@@ -1379,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/f32.rs b/sgx_tstd/src/f32.rs
index e8b0850f..71fd19a2 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).*
//!
@@ -37,9 +37,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
///
@@ -52,13 +51,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
///
@@ -69,13 +69,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
@@ -87,13 +88,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
///
@@ -106,13 +109,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
///
@@ -125,14 +129,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
///
@@ -148,6 +152,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 {
@@ -158,7 +163,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
///
@@ -170,6 +175,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 {
@@ -180,8 +186,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
///
@@ -195,6 +203,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 {
@@ -221,6 +230,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 {
@@ -244,6 +254,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 {
@@ -277,6 +288,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 {
@@ -286,7 +298,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
///
@@ -296,6 +310,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 {
@@ -312,6 +327,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 {
@@ -335,6 +351,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 {
@@ -355,6 +372,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 {
@@ -373,6 +391,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 {
@@ -393,6 +412,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 {
@@ -415,6 +435,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 {
@@ -433,6 +454,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 {
@@ -454,6 +476,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 {
@@ -477,6 +500,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 {
@@ -495,6 +519,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 {
@@ -515,6 +540,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 {
@@ -532,6 +558,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 {
@@ -549,6 +576,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 {
@@ -565,6 +593,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 {
@@ -585,6 +614,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 {
@@ -605,6 +635,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 {
@@ -624,6 +655,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 {
@@ -656,6 +688,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 {
@@ -677,6 +710,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())
@@ -696,6 +730,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 {
@@ -716,6 +751,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 {
@@ -737,6 +773,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 {
@@ -758,6 +795,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 {
@@ -779,6 +817,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 {
@@ -797,6 +836,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 {
@@ -815,6 +855,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 {
@@ -833,6 +874,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 25a5c498..b9c31894 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).*
//!
@@ -28,6 +28,7 @@
#![allow(missing_docs)]
+
use crate::intrinsics;
use crate::sys::cmath;
@@ -37,9 +38,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
///
@@ -52,13 +52,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
///
@@ -69,13 +70,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
@@ -87,13 +89,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
///
@@ -106,13 +110,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
///
@@ -125,14 +130,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
///
@@ -148,6 +153,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 {
@@ -158,7 +164,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
///
@@ -170,6 +176,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 {
@@ -180,8 +187,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
///
@@ -195,6 +204,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 {
@@ -221,6 +231,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 {
@@ -244,6 +255,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 {
@@ -277,6 +289,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 {
@@ -286,7 +299,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
///
@@ -296,6 +311,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 {
@@ -312,6 +328,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 {
@@ -335,6 +352,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 {
@@ -355,6 +373,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 {
@@ -373,6 +392,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 {
@@ -393,6 +413,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 {
@@ -415,6 +436,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 {
@@ -433,6 +455,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 {
@@ -456,6 +479,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 {
@@ -479,6 +503,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 {
@@ -497,6 +522,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 {
@@ -517,6 +543,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 {
@@ -534,6 +561,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 {
@@ -551,6 +579,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 {
@@ -567,6 +596,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 {
@@ -587,6 +617,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 {
@@ -607,6 +638,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 {
@@ -626,6 +658,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 {
@@ -658,6 +691,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 {
@@ -679,6 +713,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())
@@ -698,6 +733,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 {
@@ -718,6 +754,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 {
@@ -739,6 +776,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 {
@@ -760,6 +798,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 {
@@ -781,6 +820,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 {
@@ -799,6 +839,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 {
@@ -817,6 +858,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 {
@@ -835,6 +877,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 {
@@ -845,6 +888,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 6ecdabd1..00000000
--- a/sgx_tstd/src/ffi/c_str.rs
+++ /dev/null
@@ -1,55 +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..
-
-pub use sgx_trts::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 8dc3d034..0a44c5ba 100644
--- a/sgx_tstd/src/ffi/os_str.rs
+++ b/sgx_tstd/src/ffi/os_str.rs
@@ -22,7 +22,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;
@@ -61,6 +61,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
@@ -188,13 +204,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
///
@@ -235,7 +252,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
///
@@ -252,9 +269,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
///
@@ -271,10 +291,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
///
@@ -284,7 +307,6 @@ impl OsString {
/// # Examples
///
/// ```
- /// #![feature(try_reserve_2)]
/// use std::ffi::{OsStr, OsString};
/// use std::collections::TryReserveError;
///
@@ -306,7 +328,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.
///
@@ -316,6 +338,8 @@ impl OsString {
///
/// [`reserve`]: OsString::reserve
///
+ /// See the main `OsString` documentation information about encoding and capacity units.
+ ///
/// # Examples
///
/// ```
@@ -330,7 +354,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(())`.
@@ -342,6 +366,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
@@ -350,7 +376,6 @@ impl OsString {
/// # Examples
///
/// ```
- /// #![feature(try_reserve_2)]
/// use std::ffi::{OsStr, OsString};
/// use std::collections::TryReserveError;
///
@@ -374,6 +399,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
///
/// ```
@@ -399,6 +426,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
///
/// ```
@@ -594,6 +623,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.
///
@@ -747,6 +783,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
///
/// ```
@@ -1160,6 +1198,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/fs.rs b/sgx_tstd/src/fs.rs
index cbac797c..c7633e25 100644
--- a/sgx_tstd/src/fs.rs
+++ b/sgx_tstd/src/fs.rs
@@ -20,7 +20,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
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};
@@ -28,7 +28,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
@@ -94,6 +94,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")]
@@ -132,6 +138,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
pub struct DirEntry(fs_imp::DirEntry);
/// Options and flags which can be used to configure how a file is opened.
@@ -172,6 +188,10 @@ pub struct DirEntry(fs_imp::DirEntry);
#[derive(Clone, Debug)]
pub struct OpenOptions(fs_imp::OpenOptions);
+/// Representation of the various timestamps on a file.
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes(fs_imp::FileTimes);
+
/// Representation of the various permissions on a file.
///
/// This module only currently provides one bit of information,
@@ -278,6 +298,9 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
/// This function will create a file if it does not exist,
/// and will entirely replace its contents if it does.
///
+/// Depending on the platform, this function may fail if the
+/// full directory path does not exist.
+///
/// This is a convenience function for using [`File::create`] and [`write_all`]
/// with fewer imports.
///
@@ -330,6 +353,9 @@ impl File {
/// This function will create a file if it does not exist,
/// and will truncate it if it does.
///
+ /// Depending on the platform, this function may fail if the
+ /// full directory path does not exist.
+ ///
/// See the [`OpenOptions::open`] function for more details.
///
/// # Examples
@@ -346,6 +372,34 @@ impl File {
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
}
+ /// Creates a new file in read-write mode; error if the file exists.
+ ///
+ /// This function will create a file if it does not exist, or return an error if it does. This
+ /// way, if the call succeeds, the file returned is guaranteed to be new.
+ ///
+ /// This option is useful because it is atomic. Otherwise between checking whether a file
+ /// exists and creating a new one, the file may have been created by another process (a TOCTOU
+ /// race condition / attack).
+ ///
+ /// This can also be written using
+ /// `File::options().read(true).write(true).create_new(true).open(...)`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(file_create_new)]
+ ///
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::create_new("foo.txt")?;
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn create_new<P: AsRef<Path>>(path: P) -> io::Result<File> {
+ OpenOptions::new().read(true).write(true).create_new(true).open(path.as_ref())
+ }
+
/// Returns a new OpenOptions object.
///
/// This function returns a new OpenOptions object that you can use to
@@ -563,6 +617,53 @@ impl File {
pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
self.inner.set_permissions(perm.0)
}
+
+ /// Changes the timestamps of the underlying file.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// This function currently corresponds to the `futimens` function on Unix (falling back to
+ /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this
+ /// [may change in the future][changes].
+ ///
+ /// [changes]: io#platform-specific-behavior
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the user lacks permission to change timestamps on the
+ /// underlying file. It may also return an error in other os-specific unspecified cases.
+ ///
+ /// This function may return an error if the operating system lacks support to change one or
+ /// more of the timestamps set in the `FileTimes` structure.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(file_set_times)]
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// use std::fs::{self, File, FileTimes};
+ ///
+ /// let src = fs::metadata("src")?;
+ /// let dest = File::options().write(true).open("dest")?;
+ /// let times = FileTimes::new()
+ /// .set_accessed(src.accessed()?)
+ /// .set_modified(src.modified()?);
+ /// dest.set_times(times)?;
+ /// Ok(())
+ /// }
+ /// ```
+ pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
+ self.inner.set_times(times.0)
+ }
+
+ /// Changes the modification time of the underlying file.
+ ///
+ /// This is an alias for `set_times(FileTimes::new().set_modified(time))`.
+ #[inline]
+ pub fn set_modified(&self, time: SystemTime) -> io::Result<()> {
+ self.set_times(FileTimes::new().set_modified(time))
+ }
}
// In addition to the `impl`s here, `File` also has `impl`s for
@@ -611,8 +712,8 @@ impl Read for File {
self.inner.read_vectored(bufs)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- self.inner.read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ self.inner.read_buf(cursor)
}
#[inline]
@@ -662,8 +763,8 @@ impl Read for &File {
self.inner.read(buf)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- self.inner.read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ self.inner.read_buf(cursor)
}
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
@@ -1094,7 +1195,7 @@ impl Metadata {
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.modified() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform");
/// }
@@ -1128,7 +1229,7 @@ impl Metadata {
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.accessed() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform");
/// }
@@ -1159,7 +1260,7 @@ impl Metadata {
/// let metadata = fs::metadata("foo.txt")?;
///
/// if let Ok(time) = metadata.created() {
- /// println!("{:?}", time);
+ /// println!("{time:?}");
/// } else {
/// println!("Not supported on this platform or filesystem");
/// }
@@ -1197,6 +1298,27 @@ impl FromInner<fs_imp::FileAttr> for Metadata {
}
}
+impl FileTimes {
+ /// Create a new `FileTimes` with no times set.
+ ///
+ /// Using the resulting `FileTimes` in [`File::set_times`] will not modify any timestamps.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Set the last access time of a file.
+ pub fn set_accessed(mut self, t: SystemTime) -> Self {
+ self.0.set_accessed(t.into_inner());
+ self
+ }
+
+ /// Set the last modified time of a file.
+ pub fn set_modified(mut self, t: SystemTime) -> Self {
+ self.0.set_modified(t.into_inner());
+ self
+ }
+}
+
impl Permissions {
/// Returns `true` if these permissions describe a readonly (unwritable) file.
///
@@ -1559,7 +1681,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
/// # Platform-specific behavior
///
/// This function currently corresponds to the `stat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
@@ -1592,7 +1714,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
/// # Platform-specific behavior
///
/// This function currently corresponds to the `lstat` function on Unix
-/// and the `GetFileAttributesEx` function on Windows.
+/// and the `GetFileInformationByHandle` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
@@ -1681,11 +1803,17 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
/// This function currently corresponds to the `open` function in Unix
/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
/// `O_CLOEXEC` is set for returned file descriptors.
+///
+/// On Linux (including Android), this function attempts to use `copy_file_range(2)`,
+/// and falls back to reading and writing if that is not possible.
+///
/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate
/// NTFS streams are copied but only the size of the main stream is returned by
-/// this function. On MacOS, this function corresponds to `fclonefileat` and
-/// `fcopyfile`.
-/// Note that, this [may change in the future][changes].
+/// this function.
+///
+/// On MacOS, this function corresponds to `fclonefileat` and `fcopyfile`.
+///
+/// Note that platform-specific behavior [may change in the future][changes].
///
/// [changes]: io#platform-specific-behavior
///
@@ -1988,9 +2116,10 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
///
/// [changes]: io#platform-specific-behavior
///
-/// On macOS before version 10.10 and REDOX this function is not protected against time-of-check to
-/// time-of-use (TOCTOU) race conditions, and should not be used in security-sensitive code on
-/// those platforms. All other platforms are protected.
+/// On macOS before version 10.10 and REDOX, as well as when running in Miri for any target, this
+/// function is not protected against time-of-check to time-of-use (TOCTOU) race conditions, and
+/// should not be used in security-sensitive code on those platforms. All other platforms are
+/// protected.
///
/// # Errors
///
@@ -2225,10 +2354,14 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
/// denied on some of the parent directories.)
///
+/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
+/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
+/// where those bugs are not an issue.
+///
/// # Examples
///
/// ```no_run
-/// #![feature(path_try_exists)]
+/// #![feature(fs_try_exists)]
/// use std::fs;
///
/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
diff --git a/sgx_tstd/src/io/buffered/bufreader.rs b/sgx_tstd/src/io/buffered/bufreader.rs
index cd0795fb..5b8c50bb 100644
--- a/sgx_tstd/src/io/buffered/bufreader.rs
+++ b/sgx_tstd/src/io/buffered/bufreader.rs
@@ -15,12 +15,13 @@
// specific language governing permissions and limitations
// under the License..
-use crate::cmp;
+mod buffer;
+
use crate::fmt;
use crate::io::{
- self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
+ self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
};
-use crate::mem::MaybeUninit;
+use buffer::Buffer;
/// The `BufReader<R>` struct adds buffering to any reader.
///
@@ -58,16 +59,13 @@ use crate::mem::MaybeUninit;
///
/// let mut line = String::new();
/// let len = reader.read_line(&mut line)?;
-/// println!("First line is {} bytes long", len);
+/// println!("First line is {len} bytes long");
/// Ok(())
/// }
/// ```
pub struct BufReader<R> {
inner: R,
- buf: Box<[MaybeUninit<u8>]>,
- pos: usize,
- cap: usize,
- init: usize,
+ buf: Buffer,
}
impl<R: Read> BufReader<R> {
@@ -107,8 +105,7 @@ impl<R: Read> BufReader<R> {
/// }
/// ```
pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
- let buf = Box::new_uninit_slice(capacity);
- BufReader { inner, buf, pos: 0, cap: 0, init: 0 }
+ BufReader { inner, buf: Buffer::with_capacity(capacity) }
}
}
@@ -181,8 +178,7 @@ impl<R> BufReader<R> {
/// }
/// ```
pub fn buffer(&self) -> &[u8] {
- // SAFETY: self.cap is always <= self.init, so self.buf[self.pos..self.cap] is always init
- unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[self.pos..self.cap]) }
+ self.buf.buffer()
}
/// Returns the number of bytes the internal buffer can hold at once.
@@ -204,7 +200,7 @@ impl<R> BufReader<R> {
/// }
/// ```
pub fn capacity(&self) -> usize {
- self.buf.len()
+ self.buf.capacity()
}
/// Unwraps this `BufReader<R>`, returning the underlying reader.
@@ -233,8 +229,15 @@ impl<R> BufReader<R> {
/// Invalidates all data in the internal buffer.
#[inline]
fn discard_buffer(&mut self) {
- self.pos = 0;
- self.cap = 0;
+ self.buf.discard_buffer()
+ }
+}
+
+// This is only used by a test which asserts that the initialization-tracking is correct.
+#[cfg(feature = "unit_test")]
+impl<R> BufReader<R> {
+ pub fn initialized(&self) -> usize {
+ self.buf.initialized()
}
}
@@ -243,17 +246,17 @@ impl<R: Seek> BufReader<R> {
/// the buffer will not be flushed, allowing for more efficient seeks.
/// This method does not return the location of the underlying reader, so the caller
/// must track this information themselves if it is required.
- #[allow(clippy::collapsible_else_if)]
+ #[allow(clippy::redundant_pattern_matching)]
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
- let pos = self.pos as u64;
+ let pos = self.buf.pos() as u64;
if offset < 0 {
- if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
- self.pos = new_pos as usize;
+ if let Some(_) = pos.checked_sub((-offset) as u64) {
+ self.buf.unconsume((-offset) as usize);
return Ok(());
}
} else if let Some(new_pos) = pos.checked_add(offset as u64) {
- if new_pos <= self.cap as u64 {
- self.pos = new_pos as usize;
+ if new_pos <= self.buf.filled() as u64 {
+ self.buf.consume(offset as usize);
return Ok(());
}
}
@@ -267,7 +270,7 @@ impl<R: Read> Read for BufReader<R> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
- if self.pos == self.cap && buf.len() >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && buf.len() >= self.capacity() {
self.discard_buffer();
return self.inner.read(buf);
}
@@ -279,21 +282,21 @@ impl<R: Read> Read for BufReader<R> {
Ok(nread)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
// If we don't have any buffered data and we're doing a massive read
// (larger than our internal buffer), bypass our internal buffer
// entirely.
- if self.pos == self.cap && buf.remaining() >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() {
self.discard_buffer();
- return self.inner.read_buf(buf);
+ return self.inner.read_buf(cursor);
}
- let prev = buf.filled_len();
+ let prev = cursor.written();
let mut rem = self.fill_buf()?;
- rem.read_buf(buf)?;
+ rem.read_buf(cursor.reborrow())?;
- self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
+ self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf
Ok(())
}
@@ -303,9 +306,7 @@ impl<R: Read> Read for BufReader<R> {
// generation for the common path where the buffer has enough bytes to fill the passed-in
// buffer.
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
- if self.buffer().len() >= buf.len() {
- buf.copy_from_slice(&self.buffer()[..buf.len()]);
- self.consume(buf.len());
+ if self.buf.consume_with(buf.len(), |claimed| buf.copy_from_slice(claimed)) {
return Ok(());
}
@@ -314,7 +315,7 @@ impl<R: Read> Read for BufReader<R> {
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
- if self.pos == self.cap && total_len >= self.buf.len() {
+ if self.buf.pos() == self.buf.filled() && total_len >= self.capacity() {
self.discard_buffer();
return self.inner.read_vectored(bufs);
}
@@ -333,8 +334,9 @@ impl<R: Read> Read for BufReader<R> {
// The inner reader might have an optimized `read_to_end`. Drain our buffer and then
// delegate to the inner implementation.
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let nread = self.cap - self.pos;
- buf.extend_from_slice(self.buffer());
+ let inner_buf = self.buffer();
+ buf.extend_from_slice(inner_buf);
+ let nread = inner_buf.len();
self.discard_buffer();
Ok(nread + self.inner.read_to_end(buf)?)
}
@@ -378,33 +380,11 @@ impl<R: Read> Read for BufReader<R> {
impl<R: Read> BufRead for BufReader<R> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
- // If we've reached the end of our internal buffer then we need to fetch
- // some more data from the underlying reader.
- // Branch using `>=` instead of the more correct `==`
- // to tell the compiler that the pos..cap slice is always valid.
- if self.pos >= self.cap {
- debug_assert!(self.pos == self.cap);
-
- let mut readbuf = ReadBuf::uninit(&mut self.buf);
-
- // SAFETY: `self.init` is either 0 or set to `readbuf.initialized_len()`
- // from the last time this function was called
- unsafe {
- readbuf.assume_init(self.init);
- }
-
- self.inner.read_buf(&mut readbuf)?;
-
- self.cap = readbuf.filled_len();
- self.init = readbuf.initialized_len();
-
- self.pos = 0;
- }
- Ok(self.buffer())
+ self.buf.fill_buf(&mut self.inner)
}
fn consume(&mut self, amt: usize) {
- self.pos = cmp::min(self.pos + amt, self.cap);
+ self.buf.consume(amt)
}
}
@@ -415,7 +395,10 @@ where
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("BufReader")
.field("reader", &self.inner)
- .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+ .field(
+ "buffer",
+ &format_args!("{}/{}", self.buf.filled() - self.buf.pos(), self.capacity()),
+ )
.finish()
}
}
@@ -446,7 +429,7 @@ impl<R: Seek> Seek for BufReader<R> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
- let remainder = (self.cap - self.pos) as i64;
+ let remainder = (self.buf.filled() - self.buf.pos()) as i64;
// it should be safe to assume that remainder fits within an i64 as the alternative
// means we managed to allocate 8 exbibytes and that's absurd.
// But it's not out of the realm of possibility for some weird underlying reader to
@@ -504,7 +487,7 @@ impl<R: Seek> Seek for BufReader<R> {
/// }
/// ```
fn stream_position(&mut self) -> io::Result<u64> {
- let remainder = (self.cap - self.pos) as u64;
+ let remainder = (self.buf.filled() - self.buf.pos()) as u64;
self.inner.stream_position().map(|pos| {
pos.checked_sub(remainder).expect(
"overflow when subtracting remaining buffer size from inner stream position",
diff --git a/sgx_tstd/src/io/buffered/bufreader/buffer.rs b/sgx_tstd/src/io/buffered/bufreader/buffer.rs
new file mode 100644
index 00000000..d3293bab
--- /dev/null
+++ b/sgx_tstd/src/io/buffered/bufreader/buffer.rs
@@ -0,0 +1,139 @@
+// 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..
+
+///! An encapsulation of `BufReader`'s buffer management logic.
+///
+/// This module factors out the basic functionality of `BufReader` in order to protect two core
+/// invariants:
+/// * `filled` bytes of `buf` are always initialized
+/// * `pos` is always <= `filled`
+/// Since this module encapsulates the buffer management logic, we can ensure that the range
+/// `pos..filled` is always a valid index into the initialized region of the buffer. This means
+/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
+/// without encountering any runtime bounds checks.
+use crate::cmp;
+use crate::io::{self, BorrowedBuf, Read};
+use crate::mem::MaybeUninit;
+
+pub struct Buffer {
+ // The buffer.
+ buf: Box<[MaybeUninit<u8>]>,
+ // The current seek offset into `buf`, must always be <= `filled`.
+ pos: usize,
+ // Each call to `fill_buf` sets `filled` to indicate how many bytes at the start of `buf` are
+ // initialized with bytes from a read.
+ filled: usize,
+ // This is the max number of bytes returned across all `fill_buf` calls. We track this so that we
+ // can accurately tell `read_buf` how many bytes of buf are initialized, to bypass as much of its
+ // defensive initialization as possible. Note that while this often the same as `filled`, it
+ // doesn't need to be. Calls to `fill_buf` are not required to actually fill the buffer, and
+ // omitting this is a huge perf regression for `Read` impls that do not.
+ initialized: usize,
+}
+
+impl Buffer {
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Self {
+ let buf = Box::new_uninit_slice(capacity);
+ Self { buf, pos: 0, filled: 0, initialized: 0 }
+ }
+
+ #[inline]
+ pub fn buffer(&self) -> &[u8] {
+ // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
+ // that region is initialized because those are all invariants of this type.
+ unsafe { MaybeUninit::slice_assume_init_ref(self.buf.get_unchecked(self.pos..self.filled)) }
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.buf.len()
+ }
+
+ #[inline]
+ pub fn filled(&self) -> usize {
+ self.filled
+ }
+
+ #[inline]
+ pub fn pos(&self) -> usize {
+ self.pos
+ }
+
+ // This is only used by a test which asserts that the initialization-tracking is correct.
+ #[cfg(feature = "unit_test")]
+ pub fn initialized(&self) -> usize {
+ self.initialized
+ }
+
+ #[inline]
+ pub fn discard_buffer(&mut self) {
+ self.pos = 0;
+ self.filled = 0;
+ }
+
+ #[inline]
+ pub fn consume(&mut self, amt: usize) {
+ self.pos = cmp::min(self.pos + amt, self.filled);
+ }
+
+ /// If there are `amt` bytes available in the buffer, pass a slice containing those bytes to
+ /// `visitor` and return true. If there are not enough bytes available, return false.
+ #[inline]
+ pub fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
+ where
+ V: FnMut(&[u8]),
+ {
+ if let Some(claimed) = self.buffer().get(..amt) {
+ visitor(claimed);
+ // If the indexing into self.buffer() succeeds, amt must be a valid increment.
+ self.pos += amt;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub fn unconsume(&mut self, amt: usize) {
+ self.pos = self.pos.saturating_sub(amt);
+ }
+
+ #[inline]
+ pub fn fill_buf(&mut self, mut reader: impl Read) -> io::Result<&[u8]> {
+ // If we've reached the end of our internal buffer then we need to fetch
+ // some more data from the reader.
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.filled {
+ debug_assert!(self.pos == self.filled);
+
+ let mut buf = BorrowedBuf::from(&mut *self.buf);
+ // SAFETY: `self.filled` bytes will always have been initialized.
+ unsafe {
+ buf.set_init(self.initialized);
+ }
+
+ reader.read_buf(buf.unfilled())?;
+
+ self.pos = 0;
+ self.filled = buf.len();
+ self.initialized = buf.init_len();
+ }
+ Ok(self.buffer())
+ }
+}
diff --git a/sgx_tstd/src/io/buffered/bufwriter.rs b/sgx_tstd/src/io/buffered/bufwriter.rs
index 3897735e..1c74f29d 100644
--- a/sgx_tstd/src/io/buffered/bufwriter.rs
+++ b/sgx_tstd/src/io/buffered/bufwriter.rs
@@ -112,11 +112,11 @@ impl<W: Write> BufWriter<W> {
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
}
- /// Creates a new `BufWriter<W>` with the specified buffer capacity.
+ /// Creates a new `BufWriter<W>` with at least the specified buffer capacity.
///
/// # Examples
///
- /// Creating a buffer with a buffer of a hundred bytes.
+ /// Creating a buffer with a buffer of at least a hundred bytes.
///
/// ```no_run
/// use std::io::BufWriter;
diff --git a/sgx_tstd/src/io/buffered/linewriter.rs b/sgx_tstd/src/io/buffered/linewriter.rs
index 8fbdad5e..2dcbd3e8 100644
--- a/sgx_tstd/src/io/buffered/linewriter.rs
+++ b/sgx_tstd/src/io/buffered/linewriter.rs
@@ -104,8 +104,8 @@ impl<W: Write> LineWriter<W> {
LineWriter::with_capacity(1024, inner)
}
- /// Creates a new `LineWriter` with a specified capacity for the internal
- /// buffer.
+ /// Creates a new `LineWriter` with at least the specified capacity for the
+ /// internal buffer.
///
/// # Examples
///
diff --git a/sgx_tstd/src/io/copy.rs b/sgx_tstd/src/io/copy.rs
index b5aa5f43..8730bbd4 100644
--- a/sgx_tstd/src/io/copy.rs
+++ b/sgx_tstd/src/io/copy.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License..
-use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::mem::MaybeUninit;
/// Copies the entire contents of a reader into a writer.
@@ -56,12 +56,22 @@ use crate::mem::MaybeUninit;
/// Ok(())
/// }
/// ```
+///
+/// # Platform-specific behavior
+///
+/// On Linux (including Android), this function uses `copy_file_range(2)`,
+/// `sendfile(2)` or `splice(2)` syscalls to move data directly between file
+/// descriptors if possible.
+///
+/// Note that platform-specific behavior [may change in the future][changes].
+///
+/// [changes]: crate::io#platform-specific-behavior
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> Result<u64>
where
R: Read,
W: Write,
{
- generic_copy(reader, writer)
+ crate::sys::kernel_copy::copy_spec(reader, writer)
}
/// The userspace read-write-loop implementation of `io::copy` that is used when
@@ -97,37 +107,39 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
loop {
let buf = writer.buffer_mut();
- let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+ let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
- // SAFETY: init is either 0 or the initialized_len of the previous iteration
unsafe {
- read_buf.assume_init(init);
+ // SAFETY: init is either 0 or the init_len from the previous iteration.
+ read_buf.set_init(init);
}
if read_buf.capacity() >= DEFAULT_BUF_SIZE {
- match reader.read_buf(&mut read_buf) {
+ let mut cursor = read_buf.unfilled();
+ match reader.read_buf(cursor.reborrow()) {
Ok(()) => {
- let bytes_read = read_buf.filled_len();
+ let bytes_read = cursor.written();
if bytes_read == 0 {
return Ok(len);
}
- init = read_buf.initialized_len() - bytes_read;
+ init = read_buf.init_len() - bytes_read;
+ len += bytes_read as u64;
- // SAFETY: ReadBuf guarantees all of its filled bytes are init
+ // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
unsafe { buf.set_len(buf.len() + bytes_read) };
- len += bytes_read as u64;
+
// Read again if the buffer still has enough capacity, as BufWriter itself would do
// This will occur if the reader returns short reads
- continue;
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
+ } else {
+ writer.flush_buf()?;
+ init = 0;
}
-
- writer.flush_buf()?;
}
}
}
@@ -136,13 +148,13 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
) -> Result<u64> {
- let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
- let mut buf = ReadBuf::uninit(&mut buf);
+ let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
+ let mut buf: BorrowedBuf<'_> = buf.into();
let mut len = 0;
loop {
- match reader.read_buf(&mut buf) {
+ match reader.read_buf(buf.unfilled()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
diff --git a/sgx_tstd/src/io/cursor.rs b/sgx_tstd/src/io/cursor.rs
index be40a321..e7ed2597 100644
--- a/sgx_tstd/src/io/cursor.rs
+++ b/sgx_tstd/src/io/cursor.rs
@@ -17,10 +17,9 @@
use crate::io::prelude::*;
+use crate::alloc::Allocator;
use crate::cmp;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
-
-use core::convert::TryInto;
+use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
@@ -323,12 +322,12 @@ where
Ok(n)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- let prev_filled = buf.filled_len();
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let prev_written = cursor.written();
- Read::read_buf(&mut self.fill_buf()?, buf)?;
+ Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
- self.pos += (buf.filled_len() - prev_filled) as u64;
+ self.pos += (cursor.written() - prev_written) as u64;
Ok(())
}
@@ -395,45 +394,127 @@ fn slice_write_vectored(
Ok(nwritten)
}
-// Resizing write implementation
-fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+/// Reserves the required space, and pads the vec with 0s if necessary.
+fn reserve_and_pad<A: Allocator>(
+ pos_mut: &mut u64,
+ vec: &mut Vec<u8, A>,
+ buf_len: usize,
+) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
io::const_io_error!(
ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length",
)
})?;
- // Make sure the internal buffer is as least as big as where we
- // currently are
- let len = vec.len();
- if len < pos {
- // use `resize` so that the zero filling is as efficient as possible
- vec.resize(pos, 0);
- }
- // Figure out what bytes will be used to overwrite what's currently
- // there (left), and what will be appended on the end (right)
- {
- let space = vec.len() - pos;
- let (left, right) = buf.split_at(cmp::min(space, buf.len()));
- vec[pos..pos + left.len()].copy_from_slice(left);
- vec.extend_from_slice(right);
+
+ // For safety reasons, we don't want these numbers to overflow
+ // otherwise our allocation won't be enough
+ let desired_cap = pos.saturating_add(buf_len);
+ if desired_cap > vec.capacity() {
+ // We want our vec's total capacity
+ // to have room for (pos+buf_len) bytes. Reserve allocates
+ // based on additional elements from the length, so we need to
+ // reserve the difference
+ vec.reserve(desired_cap - vec.len());
+ }
+ // Pad if pos is above the current len.
+ if pos > vec.len() {
+ let diff = pos - vec.len();
+ // Unfortunately, `resize()` would suffice but the optimiser does not
+ // realise the `reserve` it does can be eliminated. So we do it manually
+ // to eliminate that extra branch
+ let spare = vec.spare_capacity_mut();
+ debug_assert!(spare.len() >= diff);
+ // Safety: we have allocated enough capacity for this.
+ // And we are only writing, not reading
+ unsafe {
+ spare.get_unchecked_mut(..diff).fill(core::mem::MaybeUninit::new(0));
+ vec.set_len(pos);
+ }
}
+ Ok(pos)
+}
+
+/// Writes the slice to the vec without allocating
+/// # Safety: vec must have buf.len() spare capacity
+unsafe fn vec_write_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
+where
+ A: Allocator,
+{
+ debug_assert!(vec.capacity() >= pos + buf.len());
+ vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len());
+ pos + buf.len()
+}
+
+/// Resizing write implementation for [`Cursor`]
+///
+/// Cursor is allowed to have a pre-allocated and initialised
+/// vector body, but with a position of 0. This means the [`Write`]
+/// will overwrite the contents of the vec.
+///
+/// This also allows for the vec body to be empty, but with a position of N.
+/// This means that [`Write`] will pad the vec with 0 initially,
+/// before writing anything from that point
+fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
+where
+ A: Allocator,
+{
+ let buf_len = buf.len();
+ let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?;
+
+ // Write the buf then progress the vec forward if necessary
+ // Safety: we have ensured that the capacity is available
+ // and that all bytes get written up to pos
+ unsafe {
+ pos = vec_write_unchecked(pos, vec, buf);
+ if pos > vec.len() {
+ vec.set_len(pos);
+ }
+ };
+
// Bump us forward
- *pos_mut = (pos + buf.len()) as u64;
- Ok(buf.len())
+ *pos_mut += buf_len as u64;
+ Ok(buf_len)
}
-fn vec_write_vectored(
+/// Resizing write_vectored implementation for [`Cursor`]
+///
+/// Cursor is allowed to have a pre-allocated and initialised
+/// vector body, but with a position of 0. This means the [`Write`]
+/// will overwrite the contents of the vec.
+///
+/// This also allows for the vec body to be empty, but with a position of N.
+/// This means that [`Write`] will pad the vec with 0 initially,
+/// before writing anything from that point
+fn vec_write_vectored<A>(
pos_mut: &mut u64,
- vec: &mut Vec<u8>,
+ vec: &mut Vec<u8, A>,
bufs: &[IoSlice<'_>],
-) -> io::Result<usize> {
- let mut nwritten = 0;
- for buf in bufs {
- nwritten += vec_write(pos_mut, vec, buf)?;
+) -> io::Result<usize>
+where
+ A: Allocator,
+{
+ // For safety reasons, we don't want this sum to overflow ever.
+ // If this saturates, the reserve should panic to avoid any unsound writing.
+ let buf_len = bufs.iter().fold(0usize, |a, b| a.saturating_add(b.len()));
+ let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?;
+
+ // Write the buf then progress the vec forward if necessary
+ // Safety: we have ensured that the capacity is available
+ // and that all bytes get written up to the last pos
+ unsafe {
+ for buf in bufs {
+ pos = vec_write_unchecked(pos, vec, buf);
+ }
+ if pos > vec.len() {
+ vec.set_len(pos);
+ }
}
- Ok(nwritten)
+
+ // Bump us forward
+ *pos_mut += buf_len as u64;
+ Ok(buf_len)
}
impl Write for Cursor<&mut [u8]> {
@@ -458,7 +539,10 @@ impl Write for Cursor<&mut [u8]> {
}
}
-impl Write for Cursor<&mut Vec<u8>> {
+impl<A> Write for Cursor<&mut Vec<u8, A>>
+where
+ A: Allocator,
+{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
@@ -478,7 +562,10 @@ impl Write for Cursor<&mut Vec<u8>> {
}
}
-impl Write for Cursor<Vec<u8>> {
+impl<A> Write for Cursor<Vec<u8, A>>
+where
+ A: Allocator,
+{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
@@ -498,7 +585,32 @@ impl Write for Cursor<Vec<u8>> {
}
}
-impl Write for Cursor<Box<[u8]>> {
+impl<A> Write for Cursor<Box<[u8], A>>
+where
+ A: Allocator,
+{
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ slice_write(&mut self.pos, &mut self.inner, buf)
+ }
+
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
+ }
+
+ #[inline]
+ fn is_write_vectored(&self) -> bool {
+ true
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl<const N: usize> Write for Cursor<[u8; N]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
diff --git a/sgx_tstd/src/io/error.rs b/sgx_tstd/src/io/error.rs
index 6de63fbb..13acec0c 100644
--- a/sgx_tstd/src/io/error.rs
+++ b/sgx_tstd/src/io/error.rs
@@ -82,6 +82,13 @@ impl fmt::Debug for Error {
}
}
+impl From<alloc_crate::ffi::NulError> for Error {
+ /// Converts a [`alloc::ffi::NulError`] into a [`Error`].
+ fn from(_: alloc_crate::ffi::NulError) -> Error {
+ const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
+ }
+}
+
// Only derive debug in tests, to make sure it
// doesn't accidentally get printed.
#[cfg_attr(feature = "unit_test", derive(Debug))]
@@ -148,6 +155,19 @@ struct Custom {
/// It is used with the [`io::Error`] type.
///
/// [`io::Error`]: Error
+///
+/// # Handling errors and matching on `ErrorKind`
+///
+/// In application code, use `match` for the `ErrorKind` values you are
+/// expecting; use `_` to match "all other errors".
+///
+/// In comprehensive and thorough tests that want to verify that a test doesn't
+/// return any known incorrect error kind, you may want to cut-and-paste the
+/// current full list of errors from here into your test code, and then match
+/// `_` as the correct case. This seems counterintuitive, but it will make your
+/// tests more robust. In particular, if you want to verify that your code does
+/// produce an unrecognized error kind, the robust solution is to check for all
+/// the recognized error kinds and fail in those cases.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[allow(deprecated)]
#[non_exhaustive]
@@ -334,7 +354,7 @@ pub enum ErrorKind {
impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
use ErrorKind::*;
- // Strictly alphabetical, please. (Sadly rustfmt cannot do this yet.)
+ // tidy-alphabetical-start
match *self {
AddrInUse => "address in use",
AddrNotAvailable => "address not available",
@@ -379,6 +399,7 @@ impl ErrorKind {
WriteZero => "write zero",
SgxError => "Sgx error status",
}
+ // tidy-alphabetical-end
}
}
@@ -411,7 +432,7 @@ impl From<ErrorKind> for Error {
///
/// let not_found = ErrorKind::NotFound;
/// let error = Error::from(not_found);
- /// assert_eq!("entity not found", format!("{}", error));
+ /// assert_eq!("entity not found", format!("{error}"));
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
@@ -434,6 +455,7 @@ impl Error {
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this [`Error`].
///
+ /// Note that this function allocates memory on the heap.
/// If no extra payload is required, use the `From` conversion from
/// `ErrorKind`.
///
@@ -448,7 +470,7 @@ impl Error {
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
///
- /// // creating an error without payload
+ /// // creating an error without payload (and without memory allocation)
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
/// ```
pub fn new<E>(kind: ErrorKind, error: E) -> Error
@@ -520,12 +542,13 @@ impl Error {
/// use std::io::Error;
///
/// let os_error = Error::last_os_error();
- /// println!("last OS error: {:?}", os_error);
+ /// println!("last OS error: {os_error:?}");
/// ```
+ #[doc(alias = "errno")]
#[must_use]
#[inline]
pub fn last_os_error() -> Error {
- Error::from_raw_os_error(sys::os::errno() as i32)
+ Error::from_raw_os_error(sys::os::errno())
}
/// Creates a new instance of an [`Error`] from a particular OS error code.
@@ -575,7 +598,7 @@ impl Error {
///
/// fn print_os_error(err: &Error) {
/// if let Some(raw_os_err) = err.raw_os_error() {
- /// println!("raw OS error: {:?}", raw_os_err);
+ /// println!("raw OS error: {raw_os_err:?}");
/// } else {
/// println!("Not an OS error");
/// }
@@ -634,7 +657,7 @@ impl Error {
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
- /// println!("Inner error: {:?}", inner_err);
+ /// println!("Inner error: {inner_err:?}");
/// } else {
/// println!("No inner error");
/// }
@@ -708,7 +731,7 @@ impl Error {
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
- /// println!("Inner error: {}", inner_err);
+ /// println!("Inner error: {inner_err}");
/// } else {
/// println!("No inner error");
/// }
@@ -747,7 +770,7 @@ impl Error {
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
- /// println!("Inner error: {}", inner_err);
+ /// println!("Inner error: {inner_err}");
/// } else {
/// println!("No inner error");
/// }
@@ -772,6 +795,67 @@ impl Error {
}
}
+ /// Attempt to downgrade the inner error to `E` if any.
+ ///
+ /// If this [`Error`] was constructed via [`new`] then this function will
+ /// attempt to perform downgrade on it, otherwise it will return [`Err`].
+ ///
+ /// If downgrade succeeds, it will return [`Ok`], otherwise it will also
+ /// return [`Err`].
+ ///
+ /// [`new`]: Error::new
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(io_error_downcast)]
+ ///
+ /// use std::fmt;
+ /// use std::io;
+ /// use std::error::Error;
+ ///
+ /// #[derive(Debug)]
+ /// enum E {
+ /// Io(io::Error),
+ /// SomeOtherVariant,
+ /// }
+ ///
+ /// impl fmt::Display for E {
+ /// // ...
+ /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ /// # todo!()
+ /// # }
+ /// }
+ /// impl Error for E {}
+ ///
+ /// impl From<io::Error> for E {
+ /// fn from(err: io::Error) -> E {
+ /// err.downcast::<E>()
+ /// .map(|b| *b)
+ /// .unwrap_or_else(E::Io)
+ /// }
+ /// }
+ /// ```
+ pub fn downcast<E>(self) -> result::Result<Box<E>, Self>
+ where
+ E: error::Error + Send + Sync + 'static,
+ {
+ match self.repr.into_data() {
+ ErrorData::Custom(b) if b.error.is::<E>() => {
+ let res = (*b).error.downcast::<E>();
+
+ // downcast is a really trivial and is marked as inline, so
+ // it's likely be inlined here.
+ //
+ // And the compiler should be able to eliminate the branch
+ // that produces `Err` here since b.error.is::<E>()
+ // returns true.
+ Ok(res.unwrap())
+ }
+ repr_data => Err(Self { repr: Repr::new(repr_data) }),
+ }
+ }
+
/// Returns the corresponding [`ErrorKind`] for this error.
///
/// # Examples
@@ -833,14 +917,14 @@ impl fmt::Display for Error {
match self.repr.data() {
ErrorData::Os(code) => {
let detail = sys::os::error_string(code);
- write!(fmt, "{} (os error {})", detail, code)
+ write!(fmt, "{detail} (os error {code})")
}
- ErrorData::Custom(c) => c.error.fmt(fmt),
+ ErrorData::Custom(ref c) => c.error.fmt(fmt),
ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
ErrorData::SgxStatus(status) => {
let detail = status.__description();
- write!(fmt, "{} (sgx error: {})", detail, status)
+ write!(fmt, "{detail} (sgx error: {status})")
}
}
}
diff --git a/sgx_tstd/src/io/error/repr_unpacked.rs b/sgx_tstd/src/io/error/repr_unpacked.rs
index f1713077..00f318a8 100644
--- a/sgx_tstd/src/io/error/repr_unpacked.rs
+++ b/sgx_tstd/src/io/error/repr_unpacked.rs
@@ -12,6 +12,10 @@ type Inner = ErrorData<Box<Custom>>;
pub(super) struct Repr(Inner);
impl Repr {
+ #[inline]
+ pub(super) fn new(dat: ErrorData<Box<Custom>>) -> Self {
+ Self(dat)
+ }
pub(super) fn new_custom(b: Box<Custom>) -> Self {
Self(Inner::Custom(b))
}
@@ -41,7 +45,7 @@ impl Repr {
Inner::Os(c) => ErrorData::Os(*c),
Inner::Simple(k) => ErrorData::Simple(*k),
Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
- Inner::Custom(m) => ErrorData::Custom(&*m),
+ Inner::Custom(m) => ErrorData::Custom(&**m),
Inner::SgxStatus(s) => ErrorData::SgxStatus(*s),
}
}
diff --git a/sgx_tstd/src/io/impls.rs b/sgx_tstd/src/io/impls.rs
index 2a8ebc6d..57b13d8b 100644
--- a/sgx_tstd/src/io/impls.rs
+++ b/sgx_tstd/src/io/impls.rs
@@ -17,9 +17,10 @@
use crate::alloc::Allocator;
use crate::cmp;
+use crate::collections::VecDeque;
use crate::fmt;
use crate::io::{
- self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
+ self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
};
use crate::mem;
@@ -33,8 +34,8 @@ impl<R: Read + ?Sized> Read for &mut R {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- (**self).read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
}
#[inline]
@@ -136,8 +137,8 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- (**self).read_buf(buf)
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
}
#[inline]
@@ -259,11 +260,11 @@ impl Read for &[u8] {
}
#[inline]
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
- let amt = cmp::min(buf.remaining(), self.len());
+ fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let amt = cmp::min(cursor.capacity(), self.len());
let (a, b) = self.split_at(amt);
- buf.append(a);
+ cursor.append(a);
*self = b;
Ok(())
@@ -418,4 +419,47 @@ impl<A: Allocator> Write for Vec<u8, A> {
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
-}
\ No newline at end of file
+}
+
+/// Read is implemented for `VecDeque<u8>` by consuming bytes from the front of the `VecDeque`.
+impl<A: Allocator> Read for VecDeque<u8, A> {
+ /// Fill `buf` with the contents of the "front" slice as returned by
+ /// [`as_slices`][`VecDeque::as_slices`]. If the contained byte slices of the `VecDeque` are
+ /// discontiguous, multiple calls to `read` will be needed to read the entire content.
+ #[inline]
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let (ref mut front, _) = self.as_slices();
+ let n = Read::read(front, buf)?;
+ self.drain(..n);
+ Ok(n)
+ }
+
+ #[inline]
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ let (ref mut front, _) = self.as_slices();
+ let n = cmp::min(cursor.capacity(), front.len());
+ Read::read_buf(front, cursor)?;
+ self.drain(..n);
+ Ok(())
+ }
+}
+
+/// Write is implemented for `VecDeque<u8>` by appending to the `VecDeque`, growing it as needed.
+impl<A: Allocator> Write for VecDeque<u8, A> {
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.extend(buf);
+ Ok(buf.len())
+ }
+
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+ self.extend(buf);
+ Ok(())
+ }
+
+ #[inline]
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
diff --git a/sgx_tstd/src/io/mod.rs b/sgx_tstd/src/io/mod.rs
index 2497f3db..313e0cd2 100644
--- a/sgx_tstd/src/io/mod.rs
+++ b/sgx_tstd/src/io/mod.rs
@@ -108,7 +108,7 @@
//! // read a line into buffer
//! reader.read_line(&mut buffer)?;
//!
-//! println!("{}", buffer);
+//! println!("{buffer}");
//! Ok(())
//! }
//! ```
@@ -264,7 +264,6 @@
//! [`.unwrap()`]: crate::result::Result::unwrap
use crate::cmp;
-use crate::convert::TryInto;
use crate::fmt;
use crate::mem::replace;
use crate::ops::{Deref, DerefMut};
@@ -273,13 +272,14 @@ use crate::str;
use crate::sys;
use crate::sys_common::memchr;
-
pub use self::buffered::WriterPanicked;
-
#[cfg(feature = "stdio")]
-pub use self::stdio::{_eprint, _print};
+#[allow(unused_imports)]
+pub(crate) use self::stdio::attempt_print_to_stderr;
#[cfg(feature = "stdio")]
-pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
+pub use self::stdio::set_output_capture;
+#[cfg(feature = "stdio")]
+pub use self::stdio::{_eprint, _print};
#[cfg(feature = "stdio")]
pub use self::stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock};
pub use self::{
@@ -290,7 +290,7 @@ pub use self::{
util::{empty, repeat, sink, Empty, Repeat, Sink},
};
-pub use self::readbuf::ReadBuf;
+pub use self::readbuf::{BorrowedBuf, BorrowedCursor};
pub(crate) use error::const_io_error;
mod buffered;
@@ -304,6 +304,15 @@ mod readbuf;
mod stdio;
mod util;
+pub trait IsTerminal: crate::sealed::Sealed {
+ /// Returns `true` if the descriptor/handle refers to a terminal/tty.
+ ///
+ /// On platforms where Rust does not know how to detect a terminal yet, this will return
+ /// `false`. This will also return `false` if an unexpected error occurred, such as from
+ /// passing an invalid file descriptor.
+ fn is_terminal(&self) -> bool;
+}
+
const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
#[cfg(feature = "stdio")]
@@ -376,29 +385,30 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>
buf.reserve(32); // buf is full, need more space
}
- let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
+ let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
// SAFETY: These bytes were initialized but not filled in the previous loop
unsafe {
- read_buf.assume_init(initialized);
+ read_buf.set_init(initialized);
}
- match r.read_buf(&mut read_buf) {
+ let mut cursor = read_buf.unfilled();
+ match r.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
- if read_buf.filled_len() == 0 {
+ if cursor.written() == 0 {
return Ok(buf.len() - start_len);
}
// store how much was initialized but not filled
- initialized = read_buf.initialized_len() - read_buf.filled_len();
- let new_len = read_buf.filled_len() + buf.len();
+ initialized = cursor.init_ref().len();
- // SAFETY: ReadBuf's invariants mean this much memory is init
+ // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
unsafe {
+ let new_len = read_buf.filled().len() + buf.len();
buf.set_len(new_len);
}
@@ -475,12 +485,15 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
}
}
-pub(crate) fn default_read_buf<F>(read: F, buf: &mut ReadBuf<'_>) -> Result<()>
+pub(crate) fn default_read_buf<F>(read: F, mut cursor: BorrowedCursor<'_>) -> Result<()>
where
F: FnOnce(&mut [u8]) -> Result<usize>,
{
- let n = read(buf.initialize_unfilled())?;
- buf.add_filled(n);
+ let n = read(cursor.ensure_init().init_mut())?;
+ unsafe {
+ // SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to.
+ cursor.advance(n);
+ }
Ok(())
}
@@ -809,28 +822,28 @@ pub trait Read {
/// Pull some bytes from this source into the specified buffer.
///
- /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to allow use
+ /// This is equivalent to the [`read`](Read::read) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
/// with uninitialized buffers. The new data will be appended to any existing contents of `buf`.
///
/// The default implementation delegates to `read`.
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> {
default_read_buf(|b| self.read(b), buf)
}
- /// Read the exact number of bytes required to fill `buf`.
+ /// Read the exact number of bytes required to fill `cursor`.
///
- /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`ReadBuf`] rather than `[u8]` to
+ /// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to
/// allow use with uninitialized buffers.
- fn read_buf_exact(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
- while buf.remaining() > 0 {
- let prev_filled = buf.filled().len();
- match self.read_buf(buf) {
+ fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> {
+ while cursor.capacity() > 0 {
+ let prev_written = cursor.written();
+ match self.read_buf(cursor.reborrow()) {
Ok(()) => {}
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
}
- if buf.filled().len() == prev_filled {
+ if cursor.written() == prev_written {
return Err(Error::new(ErrorKind::UnexpectedEof, "failed to fill buffer"));
}
}
@@ -886,6 +899,10 @@ pub trait Read {
/// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
/// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
+ /// The default implementation calls `read` for each byte,
+ /// which can be very inefficient for data that's not in memory,
+ /// such as [`File`]. Consider using a [`BufReader`] in such cases.
+ ///
/// # Examples
///
/// [`File`]s implement `Read`:
@@ -898,10 +915,11 @@ pub trait Read {
/// ```no_run
/// use std::io;
/// use std::io::prelude::*;
+ /// use std::io::BufReader;
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
+ /// let f = BufReader::new(File::open("foo.txt")?);
///
/// for byte in f.bytes() {
/// println!("{}", byte.unwrap());
@@ -934,8 +952,8 @@ pub trait Read {
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f1 = File::open("foo.txt")?;
- /// let mut f2 = File::open("bar.txt")?;
+ /// let f1 = File::open("foo.txt")?;
+ /// let f2 = File::open("bar.txt")?;
///
/// let mut handle = f1.chain(f2);
/// let mut buffer = String::new();
@@ -974,7 +992,7 @@ pub trait Read {
/// use std::fs::File;
///
/// fn main() -> io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
+ /// let f = File::open("foo.txt")?;
/// let mut buffer = [0; 5];
///
/// // read at most five bytes
@@ -1028,13 +1046,11 @@ pub trait Read {
/// # Examples
///
/// ```no_run
-/// #![feature(io_read_to_string)]
-///
/// # use std::io;
/// fn main() -> io::Result<()> {
/// let stdin = io::read_to_string(io::stdin())?;
/// println!("Stdin was:");
-/// println!("{}", stdin);
+/// println!("{stdin}");
/// Ok(())
/// }
/// ```
@@ -1078,6 +1094,10 @@ impl<'a> IoSliceMut<'a> {
/// Also see [`IoSliceMut::advance_slices`] to advance the cursors of
/// multiple buffers.
///
+ /// # Panics
+ ///
+ /// Panics when trying to advance beyond the end of the slice.
+ ///
/// # Examples
///
/// ```
@@ -1098,15 +1118,18 @@ impl<'a> IoSliceMut<'a> {
self.0.advance(n)
}
- /// Advance the internal cursor of the slices.
+ /// Advance a slice of slices.
///
- /// # Notes
+ /// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over.
+ /// If the cursor ends up in the middle of an `IoSliceMut`, it is modified
+ /// to start at that cursor.
+ ///
+ /// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes,
+ /// the result will only include the second `IoSliceMut`, advanced by 2 bytes.
///
- /// Elements in the slice may be modified if the cursor is not advanced to
- /// the end of the slice. For example if we have a slice of buffers with 2
- /// `IoSliceMut`s, both of length 8, and we advance the cursor by 10 bytes
- /// the first `IoSliceMut` will be untouched however the second will be
- /// modified to remove the first 2 bytes (10 - 8).
+ /// # Panics
+ ///
+ /// Panics when trying to advance beyond the end of the slices.
///
/// # Examples
///
@@ -1147,7 +1170,9 @@ impl<'a> IoSliceMut<'a> {
}
*bufs = &mut replace(bufs, &mut [])[remove..];
- if !bufs.is_empty() {
+ if bufs.is_empty() {
+ assert!(n == accumulated_len, "advancing io slices beyond their length");
+ } else {
bufs[0].advance(n - accumulated_len)
}
}
@@ -1205,6 +1230,10 @@ impl<'a> IoSlice<'a> {
/// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple
/// buffers.
///
+ /// # Panics
+ ///
+ /// Panics when trying to advance beyond the end of the slice.
+ ///
/// # Examples
///
/// ```
@@ -1213,8 +1242,8 @@ impl<'a> IoSlice<'a> {
/// use std::io::IoSlice;
/// use std::ops::Deref;
///
- /// let mut data = [1; 8];
- /// let mut buf = IoSlice::new(&mut data);
+ /// let data = [1; 8];
+ /// let mut buf = IoSlice::new(&data);
///
/// // Mark 3 bytes as read.
/// buf.advance(3);
@@ -1225,15 +1254,18 @@ impl<'a> IoSlice<'a> {
self.0.advance(n)
}
- /// Advance the internal cursor of the slices.
+ /// Advance a slice of slices.
///
- /// # Notes
+ /// Shrinks the slice to remove any `IoSlice`s that are fully advanced over.
+ /// If the cursor ends up in the middle of an `IoSlice`, it is modified
+ /// to start at that cursor.
+ ///
+ /// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes,
+ /// the result will only include the second `IoSlice`, advanced by 2 bytes.
+ ///
+ /// # Panics
///
- /// Elements in the slice may be modified if the cursor is not advanced to
- /// the end of the slice. For example if we have a slice of buffers with 2
- /// `IoSlice`s, both of length 8, and we advance the cursor by 10 bytes the
- /// first `IoSlice` will be untouched however the second will be modified to
- /// remove the first 2 bytes (10 - 8).
+ /// Panics when trying to advance beyond the end of the slices.
///
/// # Examples
///
@@ -1273,7 +1305,9 @@ impl<'a> IoSlice<'a> {
}
*bufs = &mut replace(bufs, &mut [])[remove..];
- if !bufs.is_empty() {
+ if bufs.is_empty() {
+ assert!(n == accumulated_len, "advancing io slices beyond their length");
+ } else {
bufs[0].advance(n - accumulated_len)
}
}
@@ -1398,10 +1432,10 @@ pub trait Write {
/// use std::fs::File;
///
/// fn main() -> std::io::Result<()> {
- /// let mut data1 = [1; 8];
- /// let mut data2 = [15; 8];
- /// let io_slice1 = IoSlice::new(&mut data1);
- /// let io_slice2 = IoSlice::new(&mut data2);
+ /// let data1 = [1; 8];
+ /// let data2 = [15; 8];
+ /// let io_slice1 = IoSlice::new(&data1);
+ /// let io_slice2 = IoSlice::new(&data2);
///
/// let mut buffer = File::create("foo.txt")?;
///
@@ -1732,7 +1766,7 @@ pub trait Seek {
/// .open("foo.txt").unwrap();
///
/// let hello = "Hello!\n";
- /// write!(f, "{}", hello).unwrap();
+ /// write!(f, "{hello}").unwrap();
/// f.rewind().unwrap();
///
/// let mut buf = String::new();
@@ -1774,7 +1808,7 @@ pub trait Seek {
/// let mut f = File::open("foo.txt")?;
///
/// let len = f.stream_len()?;
- /// println!("The file is currently {} bytes long", len);
+ /// println!("The file is currently {len} bytes long");
/// Ok(())
/// }
/// ```
@@ -1951,7 +1985,7 @@ pub trait BufRead: Read {
/// let buffer = stdin.fill_buf().unwrap();
///
/// // work with buffer
- /// println!("{:?}", buffer);
+ /// println!("{buffer:?}");
///
/// // ensure the bytes we worked with aren't returned again later
/// let length = buffer.len();
@@ -2003,7 +2037,7 @@ pub trait BufRead: Read {
/// let mut line = String::new();
/// stdin.read_line(&mut line).unwrap();
/// // work with line
- /// println!("{:?}", line);
+ /// println!("{line:?}");
/// }
/// ```
fn has_data_left(&mut self) -> Result<bool> {
@@ -2069,7 +2103,8 @@ pub trait BufRead: Read {
}
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
- /// them to the provided buffer.
+ /// them to the provided buffer. You do not need to clear the buffer before
+ /// appending.
///
/// This function will read bytes from the underlying stream until the
/// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes
@@ -2502,54 +2537,53 @@ impl<T: Read> Read for Take<T> {
let max = cmp::min(buf.len() as u64, self.limit) as usize;
let n = self.inner.read(&mut buf[..max])?;
+ assert!(n as u64 <= self.limit, "number of read bytes exceeds limit");
self.limit -= n as u64;
Ok(n)
}
- fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> Result<()> {
+ fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
// Don't call into inner reader at all at EOF because it may still block
if self.limit == 0 {
return Ok(());
}
- let prev_filled = buf.filled_len();
-
- if self.limit <= buf.remaining() as u64 {
+ if self.limit <= buf.capacity() as u64 {
// if we just use an as cast to convert, limit may wrap around on a 32 bit target
let limit = cmp::min(self.limit, usize::MAX as u64) as usize;
- let extra_init = cmp::min(limit as usize, buf.initialized_len() - buf.filled_len());
+ let extra_init = cmp::min(limit, buf.init_ref().len());
// SAFETY: no uninit data is written to ibuf
- let ibuf = unsafe { &mut buf.unfilled_mut()[..limit] };
+ let ibuf = unsafe { &mut buf.as_mut()[..limit] };
- let mut sliced_buf = ReadBuf::uninit(ibuf);
+ let mut sliced_buf: BorrowedBuf<'_> = ibuf.into();
// SAFETY: extra_init bytes of ibuf are known to be initialized
unsafe {
- sliced_buf.assume_init(extra_init);
+ sliced_buf.set_init(extra_init);
}
- self.inner.read_buf(&mut sliced_buf)?;
+ let mut cursor = sliced_buf.unfilled();
+ self.inner.read_buf(cursor.reborrow())?;
- let new_init = sliced_buf.initialized_len();
- let filled = sliced_buf.filled_len();
+ let new_init = cursor.init_ref().len();
+ let filled = sliced_buf.len();
- // sliced_buf / ibuf must drop here
+ // cursor / sliced_buf / ibuf must drop here
- // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
unsafe {
- buf.assume_init(new_init);
+ // SAFETY: filled bytes have been filled and therefore initialized
+ buf.advance(filled);
+ // SAFETY: new_init bytes of buf's unfilled buffer have been initialized
+ buf.set_init(new_init);
}
- buf.add_filled(filled);
-
self.limit -= filled as u64;
} else {
- self.inner.read_buf(buf)?;
-
- //inner may unfill
- self.limit -= buf.filled_len().saturating_sub(prev_filled) as u64;
+ let written = buf.written();
+ self.inner.read_buf(buf.reborrow())?;
+ self.limit -= (buf.written() - written) as u64;
}
Ok(())
diff --git a/sgx_tstd/src/io/readbuf.rs b/sgx_tstd/src/io/readbuf.rs
index db776d76..5889ee95 100644
--- a/sgx_tstd/src/io/readbuf.rs
+++ b/sgx_tstd/src/io/readbuf.rs
@@ -15,11 +15,12 @@
// specific language governing permissions and limitations
// under the License..
-use crate::cmp;
use crate::fmt::{self, Debug, Formatter};
-use crate::mem::MaybeUninit;
+use crate::io::{Result, Write};
+use crate::mem::{self, MaybeUninit};
+use crate::{cmp, ptr};
-/// A wrapper around a byte buffer that is incrementally filled and initialized.
+/// A borrowed byte buffer which is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the buffer: a region at the beginning of the
/// buffer that has been logically filled with data, a region that has been initialized at some point but not yet
@@ -32,226 +33,289 @@ use crate::mem::MaybeUninit;
/// [ filled | unfilled ]
/// [ initialized | uninitialized ]
/// ```
-pub struct ReadBuf<'a> {
- buf: &'a mut [MaybeUninit<u8>],
+///
+/// A `BorrowedBuf` is created around some existing data (or capacity for data) via a unique reference
+/// (`&mut`). The `BorrowedBuf` can be configured (e.g., using `clear` or `set_init`), but cannot be
+/// directly written. To write into the buffer, use `unfilled` to create a `BorrowedCursor`. The cursor
+/// has write-only access to the unfilled portion of the buffer (you can think of it as a
+/// write-only iterator).
+///
+/// The lifetime `'data` is a bound on the lifetime of the underlying data.
+pub struct BorrowedBuf<'data> {
+ /// The buffer's underlying data.
+ buf: &'data mut [MaybeUninit<u8>],
+ /// The length of `self.buf` which is known to be filled.
filled: usize,
- initialized: usize,
+ /// The length of `self.buf` which is known to be initialized.
+ init: usize,
}
-impl Debug for ReadBuf<'_> {
+impl Debug for BorrowedBuf<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
- f.debug_struct("ReadBuf")
- .field("init", &self.initialized())
+ f.debug_struct("BorrowedBuf")
+ .field("init", &self.init)
.field("filled", &self.filled)
.field("capacity", &self.capacity())
.finish()
}
}
-impl<'a> ReadBuf<'a> {
- /// Creates a new `ReadBuf` from a fully initialized buffer.
+/// Create a new `BorrowedBuf` from a fully initialized slice.
+impl<'data> From<&'data mut [u8]> for BorrowedBuf<'data> {
#[inline]
- pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
- let len = buf.len();
+ fn from(slice: &'data mut [u8]) -> BorrowedBuf<'data> {
+ let len = slice.len();
- ReadBuf {
- //SAFETY: initialized data never becoming uninitialized is an invariant of ReadBuf
- buf: unsafe { (buf as *mut [u8]).as_uninit_slice_mut().unwrap() },
+ BorrowedBuf {
+ // SAFETY: initialized data never becoming uninitialized is an invariant of BorrowedBuf
+ buf: unsafe { (slice as *mut [u8]).as_uninit_slice_mut().unwrap() },
filled: 0,
- initialized: len,
+ init: len,
}
}
+}
- /// Creates a new `ReadBuf` from a fully uninitialized buffer.
- ///
- /// Use `assume_init` if part of the buffer is known to be already initialized.
+/// Create a new `BorrowedBuf` from an uninitialized buffer.
+///
+/// Use `set_init` if part of the buffer is known to be already initialized.
+impl<'data> From<&'data mut [MaybeUninit<u8>]> for BorrowedBuf<'data> {
#[inline]
- pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
- ReadBuf { buf, filled: 0, initialized: 0 }
+ fn from(buf: &'data mut [MaybeUninit<u8>]) -> BorrowedBuf<'data> {
+ BorrowedBuf { buf, filled: 0, init: 0 }
}
+}
+impl<'data> BorrowedBuf<'data> {
/// Returns the total capacity of the buffer.
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
+ /// Returns the length of the filled part of the buffer.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.filled
+ }
+
+ /// Returns the length of the initialized part of the buffer.
+ #[inline]
+ pub fn init_len(&self) -> usize {
+ self.init
+ }
+
/// Returns a shared reference to the filled portion of the buffer.
#[inline]
pub fn filled(&self) -> &[u8] {
- //SAFETY: We only slice the filled part of the buffer, which is always valid
+ // SAFETY: We only slice the filled part of the buffer, which is always valid
unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
}
- /// Returns a mutable reference to the filled portion of the buffer.
+ /// Returns a cursor over the unfilled part of the buffer.
#[inline]
- pub fn filled_mut(&mut self) -> &mut [u8] {
- //SAFETY: We only slice the filled part of the buffer, which is always valid
- unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+ pub fn unfilled<'this>(&'this mut self) -> BorrowedCursor<'this> {
+ BorrowedCursor {
+ start: self.filled,
+ // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
+ // lifetime covariantly is safe.
+ buf: unsafe {
+ mem::transmute::<&'this mut BorrowedBuf<'data>, &'this mut BorrowedBuf<'this>>(self)
+ },
+ }
}
- /// Returns a shared reference to the initialized portion of the buffer.
+ /// Clears the buffer, resetting the filled region to empty.
///
- /// This includes the filled portion.
+ /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
#[inline]
- pub fn initialized(&self) -> &[u8] {
- //SAFETY: We only slice the initialized part of the buffer, which is always valid
- unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.initialized]) }
+ pub fn clear(&mut self) -> &mut Self {
+ self.filled = 0;
+ self
}
- /// Returns a mutable reference to the initialized portion of the buffer.
+ /// Asserts that the first `n` bytes of the buffer are initialized.
///
- /// This includes the filled portion.
- #[inline]
- pub fn initialized_mut(&mut self) -> &mut [u8] {
- //SAFETY: We only slice the initialized part of the buffer, which is always valid
- unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.initialized]) }
- }
-
- /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
- /// initialized.
+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
+ /// bytes than are already known to be initialized.
///
/// # Safety
///
- /// The caller must not de-initialize portions of the buffer that have already been initialized.
+ /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
#[inline]
- pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf[self.filled..]
+ pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+ self.init = cmp::max(self.init, n);
+ self
}
+}
+
+/// A writeable view of the unfilled portion of a [`BorrowedBuf`](BorrowedBuf).
+///
+/// Provides access to the initialized and uninitialized parts of the underlying `BorrowedBuf`.
+/// Data can be written directly to the cursor by using [`append`](BorrowedCursor::append) or
+/// indirectly by getting a slice of part or all of the cursor and writing into the slice. In the
+/// indirect case, the caller must call [`advance`](BorrowedCursor::advance) after writing to inform
+/// the cursor how many bytes have been written.
+///
+/// Once data is written to the cursor, it becomes part of the filled portion of the underlying
+/// `BorrowedBuf` and can no longer be accessed or re-written by the cursor. I.e., the cursor tracks
+/// the unfilled part of the underlying `BorrowedBuf`.
+///
+/// The lifetime `'a` is a bound on the lifetime of the underlying buffer (which means it is a bound
+/// on the data in that buffer by transitivity).
+#[derive(Debug)]
+pub struct BorrowedCursor<'a> {
+ /// The underlying buffer.
+ // Safety invariant: we treat the type of buf as covariant in the lifetime of `BorrowedBuf` when
+ // we create a `BorrowedCursor`. This is only safe if we never replace `buf` by assigning into
+ // it, so don't do that!
+ buf: &'a mut BorrowedBuf<'a>,
+ /// The length of the filled portion of the underlying buffer at the time of the cursor's
+ /// creation.
+ start: usize,
+}
- /// Returns a mutable reference to the uninitialized part of the buffer.
+impl<'a> BorrowedCursor<'a> {
+ /// Reborrow this cursor by cloning it with a smaller lifetime.
///
- /// It is safe to uninitialize any of these bytes.
+ /// Since a cursor maintains unique access to its underlying buffer, the borrowed cursor is
+ /// not accessible while the new cursor exists.
#[inline]
- pub fn uninitialized_mut(&mut self) -> &mut [MaybeUninit<u8>] {
- &mut self.buf[self.initialized..]
+ pub fn reborrow<'this>(&'this mut self) -> BorrowedCursor<'this> {
+ BorrowedCursor {
+ // SAFETY: we never assign into `BorrowedCursor::buf`, so treating its
+ // lifetime covariantly is safe.
+ buf: unsafe {
+ mem::transmute::<&'this mut BorrowedBuf<'a>, &'this mut BorrowedBuf<'this>>(
+ self.buf,
+ )
+ },
+ start: self.start,
+ }
}
- /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
- ///
- /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
- /// the first use.
+ /// Returns the available space in the cursor.
#[inline]
- pub fn initialize_unfilled(&mut self) -> &mut [u8] {
- // should optimize out the assertion
- self.initialize_unfilled_to(self.remaining())
+ pub fn capacity(&self) -> usize {
+ self.buf.capacity() - self.buf.filled
}
- /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
- /// fully initialized.
- ///
- /// # Panics
+ /// Returns the number of bytes written to this cursor since it was created from a `BorrowedBuf`.
///
- /// Panics if `self.remaining()` is less than `n`.
+ /// Note that if this cursor is a reborrowed clone of another, then the count returned is the
+ /// count written via either cursor, not the count since the cursor was reborrowed.
#[inline]
- pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
- assert!(self.remaining() >= n);
-
- let extra_init = self.initialized - self.filled;
- // If we don't have enough initialized, do zeroing
- if n > extra_init {
- let uninit = n - extra_init;
- let unfilled = &mut self.uninitialized_mut()[0..uninit];
-
- for byte in unfilled.iter_mut() {
- byte.write(0);
- }
-
- // SAFETY: we just initialized uninit bytes, and the previous bytes were already init
- unsafe {
- self.assume_init(n);
- }
- }
-
- let filled = self.filled;
+ pub fn written(&self) -> usize {
+ self.buf.filled - self.start
+ }
- &mut self.initialized_mut()[filled..filled + n]
+ /// Returns a shared reference to the initialized portion of the cursor.
+ #[inline]
+ pub fn init_ref(&self) -> &[u8] {
+ // SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
}
- /// Returns the number of bytes at the end of the slice that have not yet been filled.
+ /// Returns a mutable reference to the initialized portion of the cursor.
#[inline]
- pub fn remaining(&self) -> usize {
- self.capacity() - self.filled
+ pub fn init_mut(&mut self) -> &mut [u8] {
+ // SAFETY: We only slice the initialized part of the buffer, which is always valid
+ unsafe {
+ MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
+ }
}
- /// Clears the buffer, resetting the filled region to empty.
+ /// Returns a mutable reference to the uninitialized part of the cursor.
///
- /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
+ /// It is safe to uninitialize any of these bytes.
#[inline]
- pub fn clear(&mut self) {
- self.set_filled(0); // The assertion in `set_filled` is optimized out
+ pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf.buf[self.buf.init..]
}
- /// Increases the size of the filled region of the buffer.
- ///
- /// The number of initialized bytes is not changed.
+ /// Returns a mutable reference to the whole cursor.
///
- /// # Panics
+ /// # Safety
///
- /// Panics if the filled region of the buffer would become larger than the initialized region.
+ /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
#[inline]
- pub fn add_filled(&mut self, n: usize) {
- self.set_filled(self.filled + n);
+ pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+ &mut self.buf.buf[self.buf.filled..]
}
- /// Sets the size of the filled region of the buffer.
+ /// Advance the cursor by asserting that `n` bytes have been filled.
///
- /// The number of initialized bytes is not changed.
+ /// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
+ /// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
+ /// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
///
- /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
- /// example, by a `Read` implementation that compresses data in-place).
- ///
- /// # Panics
+ /// # Safety
///
- /// Panics if the filled region of the buffer would become larger than the initialized region.
+ /// The caller must ensure that the first `n` bytes of the cursor have been properly
+ /// initialised.
+ #[inline]
+ pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
+ self.buf.filled += n;
+ self.buf.init = cmp::max(self.buf.init, self.buf.filled);
+ self
+ }
+
+ /// Initializes all bytes in the cursor.
#[inline]
- pub fn set_filled(&mut self, n: usize) {
- assert!(n <= self.initialized);
+ pub fn ensure_init(&mut self) -> &mut Self {
+ let uninit = self.uninit_mut();
+ // SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
+ // since it is comes from a slice reference.
+ unsafe {
+ ptr::write_bytes(uninit.as_mut_ptr(), 0, uninit.len());
+ }
+ self.buf.init = self.buf.capacity();
- self.filled = n;
+ self
}
- /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
+ /// Asserts that the first `n` unfilled bytes of the cursor are initialized.
///
- /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
- /// bytes than are already known to be initialized.
+ /// `BorrowedBuf` assumes that bytes are never de-initialized, so this method does nothing when
+ /// called with fewer bytes than are already known to be initialized.
///
/// # Safety
///
- /// The caller must ensure that the first `n` unfilled bytes of the buffer have already been initialized.
+ /// The caller must ensure that the first `n` bytes of the buffer have already been initialized.
#[inline]
- pub unsafe fn assume_init(&mut self, n: usize) {
- self.initialized = cmp::max(self.initialized, self.filled + n);
+ pub unsafe fn set_init(&mut self, n: usize) -> &mut Self {
+ self.buf.init = cmp::max(self.buf.init, self.buf.filled + n);
+ self
}
- /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
+ /// Appends data to the cursor, advancing position within its buffer.
///
/// # Panics
///
- /// Panics if `self.remaining()` is less than `buf.len()`.
+ /// Panics if `self.capacity()` is less than `buf.len()`.
#[inline]
pub fn append(&mut self, buf: &[u8]) {
- assert!(self.remaining() >= buf.len());
+ assert!(self.capacity() >= buf.len());
// SAFETY: we do not de-initialize any of the elements of the slice
unsafe {
- MaybeUninit::write_slice(&mut self.unfilled_mut()[..buf.len()], buf);
+ MaybeUninit::write_slice(&mut self.as_mut()[..buf.len()], buf);
}
// SAFETY: We just added the entire contents of buf to the filled section.
- unsafe { self.assume_init(buf.len()) }
- self.add_filled(buf.len());
+ unsafe {
+ self.set_init(buf.len());
+ }
+ self.buf.filled += buf.len();
}
+}
- /// Returns the amount of bytes that have been filled.
- #[inline]
- pub fn filled_len(&self) -> usize {
- self.filled
+impl<'a> Write for BorrowedCursor<'a> {
+ fn write(&mut self, buf: &[u8]) -> Result<usize> {
+ self.append(buf);
+ Ok(buf.len())
}
- /// Returns the amount of bytes that have been initialized.
- #[inline]
- pub fn initialized_len(&self) -> usize {
- self.initialized
+ fn flush(&mut self) -> Result<()> {
+ Ok(())
}
}
diff --git a/sgx_tstd/src/io/stdio.rs b/sgx_tstd/src/io/stdio.rs
index 8a18478f..646d0bd6 100644
--- a/sgx_tstd/src/io/stdio.rs
+++ b/sgx_tstd/src/io/stdio.rs
@@ -17,14 +17,37 @@
use crate::io::prelude::*;
-use crate::cell::RefCell;
+use crate::cell::{Cell, RefCell};
use crate::fmt;
+use crate::fs::File;
use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
-use crate::lazy::SyncOnceCell;
-use crate::pin::Pin;
-use crate::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard};
+use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::{Arc, SgxMutex as Mutex, SgxMutexGuard as MutexGuard, OnceLock};
use crate::sys::stdio;
-use crate::sys_common::remutex::{SgxReentrantMutex as ReentrantMutex, SgxReentrantMutexGuard as ReentrantMutexGuard};
+use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+
+type LocalStream = Arc<Mutex<Vec<u8>>>;
+
+thread_local! {
+ /// Used by the test crate to capture the output of the print macros and panics.
+ static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = {
+ Cell::new(None)
+ }
+}
+
+/// Flag to indicate OUTPUT_CAPTURE is used.
+///
+/// If it is None and was never set on any thread, this flag is set to false,
+/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time
+/// and memory registering an unused thread local.
+///
+/// Note about memory ordering: This contains information about whether a
+/// thread local variable might be in use. Although this is a global flag, the
+/// memory ordering between threads does not matter: we only want this flag to
+/// have a consistent order between set_output_capture and print_to *within
+/// the same thread*. Within the same thread, things always have a perfectly
+/// consistent order. So Ordering::Relaxed is fine.
+static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
/// A handle to a raw instance of the standard input stream of this process.
///
@@ -187,12 +210,18 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
///
/// [`io::stdin`]: stdin
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// # Examples
///
/// ```no_run
@@ -200,7 +229,7 @@ fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
///
/// fn main() -> io::Result<()> {
/// let mut buffer = String::new();
-/// let mut stdin = io::stdin(); // We get `Stdin` here.
+/// let stdin = io::stdin(); // We get `Stdin` here.
/// stdin.read_line(&mut buffer)?;
/// Ok(())
/// }
@@ -214,12 +243,18 @@ pub struct Stdin {
/// This handle implements both the [`Read`] and [`BufRead`] traits, and
/// is constructed via the [`Stdin::lock`] method.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// # Examples
///
/// ```no_run
@@ -246,11 +281,18 @@ pub struct StdinLock<'a> {
/// is synchronized via a mutex. If you need more explicit control over
/// locking, see the [`Stdin::lock`] method.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// # Examples
///
/// Using implicit synchronization:
@@ -281,7 +323,7 @@ pub struct StdinLock<'a> {
/// ```
#[must_use]
pub fn stdin() -> Stdin {
- static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
+ static INSTANCE: OnceLock<Mutex<BufReader<StdinRaw>>> = OnceLock::new();
Stdin {
inner: INSTANCE.get_or_init(|| {
Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw()))
@@ -289,47 +331,6 @@ pub fn stdin() -> Stdin {
}
}
-/// Constructs a new locked handle to the standard input of the current
-/// process.
-///
-/// Each handle returned is a guard granting locked access to a shared
-/// global buffer whose access is synchronized via a mutex. If you need
-/// more explicit control over locking, for example, in a multi-threaded
-/// program, use the [`io::stdin`] function to obtain an unlocked handle,
-/// along with the [`Stdin::lock`] method.
-///
-/// The lock is released when the returned guard goes out of scope. The
-/// returned guard also implements the [`Read`] and [`BufRead`] traits for
-/// accessing the underlying data.
-///
-/// **Note**: The mutex locked by this handle is not reentrant. Even in a
-/// single-threaded program, calling other code that accesses [`Stdin`]
-/// could cause a deadlock or panic, if this locked handle is held across
-/// that call.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Examples
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, BufRead};
-///
-/// fn main() -> io::Result<()> {
-/// let mut buffer = String::new();
-/// let mut handle = io::stdin_locked();
-///
-/// handle.read_line(&mut buffer)?;
-/// Ok(())
-/// }
-/// ```
-pub fn stdin_locked() -> StdinLock<'static> {
- stdin().into_locked()
-}
-
impl Stdin {
/// Locks this handle to the standard input stream, returning a readable
/// guard.
@@ -352,8 +353,10 @@ impl Stdin {
/// Ok(())
/// }
/// ```
- pub fn lock(&self) -> StdinLock<'_> {
- self.lock_any()
+ pub fn lock(&self) -> StdinLock<'static> {
+ // Locks this handle with 'static lifetime. This depends on the
+ // implementation detail that the underlying `Mutex` is static.
+ StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
}
/// Locks this handle and reads a line of input, appending it to the specified buffer.
@@ -369,10 +372,10 @@ impl Stdin {
/// let mut input = String::new();
/// match io::stdin().read_line(&mut input) {
/// Ok(n) => {
- /// println!("{} bytes read", n);
- /// println!("{}", input);
+ /// println!("{n} bytes read");
+ /// println!("{input}");
/// }
- /// Err(error) => println!("error: {}", error),
+ /// Err(error) => println!("error: {error}"),
/// }
/// ```
///
@@ -386,42 +389,6 @@ impl Stdin {
self.lock().read_line(buf)
}
- // Locks this handle with any lifetime. This depends on the
- // implementation detail that the underlying `Mutex` is static.
- fn lock_any<'a>(&self) -> StdinLock<'a> {
- StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) }
- }
-
- /// Consumes this handle to the standard input stream, locking the
- /// shared global buffer associated with the stream and returning a
- /// readable guard.
- ///
- /// The lock is released when the returned guard goes out of scope. The
- /// returned guard also implements the [`Read`] and [`BufRead`] traits
- /// for accessing the underlying data.
- ///
- /// It is often simpler to directly get a locked handle using the
- /// [`stdin_locked`] function instead, unless nearby code also needs to
- /// use an unlocked handle.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(stdio_locked)]
- /// use std::io::{self, BufRead};
- ///
- /// fn main() -> io::Result<()> {
- /// let mut buffer = String::new();
- /// let mut handle = io::stdin().into_locked();
- ///
- /// handle.read_line(&mut buffer)?;
- /// Ok(())
- /// }
- /// ```
- pub fn into_locked(self) -> StdinLock<'static> {
- self.lock_any()
- }
-
/// Consumes this handle and returns an iterator over input lines.
///
/// For detailed semantics of this method, see the documentation on
@@ -430,7 +397,6 @@ impl Stdin {
/// # Examples
///
/// ```no_run
- /// #![feature(stdin_forwarders)]
/// use std::io;
///
/// let lines = io::stdin().lines();
@@ -440,7 +406,7 @@ impl Stdin {
/// ```
#[must_use = "`self` will be dropped if the result is not used"]
pub fn lines(self) -> Lines<StdinLock<'static>> {
- self.into_locked().lines()
+ self.lock().lines()
}
}
@@ -538,18 +504,25 @@ impl fmt::Debug for StdinLock<'_> {
///
/// Created by the [`io::stdout`] method.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// [`lock`]: Stdout::lock
/// [`io::stdout`]: stdout
pub struct Stdout {
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
- inner: Pin<&'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
+ inner: &'static ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>,
}
/// A locked reference to the [`Stdout`] handle.
@@ -557,16 +530,23 @@ pub struct Stdout {
/// This handle implements the [`Write`] trait, and is constructed via
/// the [`Stdout::lock`] method. See its documentation for more.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
#[must_use = "if unused stdout will immediately unlock"]
pub struct StdoutLock<'a> {
inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
}
-static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = SyncOnceCell::new();
+static STDOUT: OnceLock<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = OnceLock::new();
/// Constructs a new handle to the standard output of the current process.
///
@@ -574,11 +554,18 @@ static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Sy
/// is synchronized via a mutex. If you need more explicit control over
/// locking, see the [`Stdout::lock`] method.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// # Examples
///
/// Using implicit synchronization:
@@ -610,57 +597,27 @@ static STDOUT: SyncOnceCell<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = Sy
#[must_use]
pub fn stdout() -> Stdout {
Stdout {
- inner: Pin::static_ref(&STDOUT).get_or_init_pin(
- || ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))),
- |_| (),
- ),
+ inner: STDOUT
+ .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))),
}
}
-/// Constructs a new locked handle to the standard output of the current
-/// process.
-///
-/// Each handle returned is a guard granting locked access to a shared
-/// global buffer whose access is synchronized via a mutex. If you need
-/// more explicit control over locking, for example, in a multi-threaded
-/// program, use the [`io::stdout`] function to obtain an unlocked handle,
-/// along with the [`Stdout::lock`] method.
-///
-/// The lock is released when the returned guard goes out of scope. The
-/// returned guard also implements the [`Write`] trait for writing data.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Examples
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, Write};
-///
-/// fn main() -> io::Result<()> {
-/// let mut handle = io::stdout_locked();
-///
-/// handle.write_all(b"hello world")?;
-///
-/// Ok(())
-/// }
-/// ```
-pub fn stdout_locked() -> StdoutLock<'static> {
- stdout().into_locked()
-}
-
+// Flush the data and disable buffering during shutdown
+// by replacing the line writer by one with zero
+// buffering capacity.
pub fn cleanup() {
- if let Some(instance) = STDOUT.get() {
- // Flush the data and disable buffering during shutdown
- // by replacing the line writer by one with zero
- // buffering capacity.
+ let mut initialized = false;
+ let stdout = STDOUT.get_or_init(|| {
+ initialized = true;
+ ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw())))
+ });
+
+ if !initialized {
+ // The buffer was previously initialized, overwrite it here.
// We use try_lock() instead of lock(), because someone
// might have leaked a StdoutLock, which would
// otherwise cause a deadlock here.
- if let Some(lock) = Pin::static_ref(instance).try_lock() {
+ if let Some(lock) = stdout.try_lock() {
*lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw());
}
}
@@ -679,53 +636,19 @@ impl Stdout {
/// use std::io::{self, Write};
///
/// fn main() -> io::Result<()> {
- /// let stdout = io::stdout();
- /// let mut handle = stdout.lock();
+ /// let mut stdout = io::stdout().lock();
///
- /// handle.write_all(b"hello world")?;
+ /// stdout.write_all(b"hello world")?;
///
/// Ok(())
/// }
/// ```
- pub fn lock(&self) -> StdoutLock<'_> {
- self.lock_any()
- }
-
- // Locks this handle with any lifetime. This depends on the
- // implementation detail that the underlying `ReentrantMutex` is
- // static.
- fn lock_any<'a>(&self) -> StdoutLock<'a> {
+ pub fn lock(&self) -> StdoutLock<'static> {
+ // Locks this handle with 'static lifetime. This depends on the
+ // implementation detail that the underlying `ReentrantMutex` is
+ // static.
StdoutLock { inner: self.inner.lock() }
}
-
- /// Consumes this handle to the standard output stream, locking the
- /// shared global buffer associated with the stream and returning a
- /// writable guard.
- ///
- /// The lock is released when the returned lock goes out of scope. The
- /// returned guard also implements the [`Write`] trait for writing data.
- ///
- /// It is often simpler to directly get a locked handle using the
- /// [`io::stdout_locked`] function instead, unless nearby code also
- /// needs to use an unlocked handle.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// #![feature(stdio_locked)]
- /// use std::io::{self, Write};
- ///
- /// fn main() -> io::Result<()> {
- /// let mut handle = io::stdout().into_locked();
- ///
- /// handle.write_all(b"hello world")?;
- ///
- /// Ok(())
- /// }
- /// ```
- pub fn into_locked(self) -> StdoutLock<'static> {
- self.lock_any()
- }
}
impl fmt::Debug for Stdout {
@@ -743,7 +666,7 @@ impl Write for Stdout {
}
#[inline]
fn is_write_vectored(&self) -> bool {
- io::Write::is_write_vectored(&&*self)
+ io::Write::is_write_vectored(&self)
}
fn flush(&mut self) -> io::Result<()> {
(&*self).flush()
@@ -818,12 +741,19 @@ impl fmt::Debug for StdoutLock<'_> {
///
/// [`io::stderr`]: stderr
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
pub struct Stderr {
- inner: Pin<&'static ReentrantMutex<RefCell<StderrRaw>>>,
+ inner: &'static ReentrantMutex<RefCell<StderrRaw>>,
}
/// A locked reference to the [`Stderr`] handle.
@@ -831,10 +761,17 @@ pub struct Stderr {
/// This handle implements the [`Write`] trait and is constructed via
/// the [`Stderr::lock`] method. See its documentation for more.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
+///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
#[must_use = "if unused stderr will immediately unlock"]
pub struct StderrLock<'a> {
inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>,
@@ -844,11 +781,18 @@ pub struct StderrLock<'a> {
///
/// This handle is not buffered.
///
-/// ### Note: Windows Portability Consideration
+/// ### Note: Windows Portability Considerations
+///
/// When operating in a console, the Windows implementation of this stream does not support
/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
/// an error.
///
+/// In a process with a detached console, such as one using
+/// `#![windows_subsystem = "windows"]`, or in a child process spawned from such a process,
+/// the contained handle will be null. In such cases, the standard library's `Read` and
+/// `Write` will do nothing and silently succeed. All other I/O operations, via the
+/// standard library or via raw Windows API calls, will fail.
+///
/// # Examples
///
/// Using implicit synchronization:
@@ -880,44 +824,12 @@ pub struct StderrLock<'a> {
#[must_use]
pub fn stderr() -> Stderr {
// Note that unlike `stdout()` we don't use `at_exit` here to register a
- // destructor. Stderr is not buffered , so there's no need to run a
+ // destructor. Stderr is not buffered, so there's no need to run a
// destructor for flushing the buffer
- static INSTANCE: SyncOnceCell<ReentrantMutex<RefCell<StderrRaw>>> = SyncOnceCell::new();
+ static INSTANCE: ReentrantMutex<RefCell<StderrRaw>> =
+ ReentrantMutex::new(RefCell::new(stderr_raw()));
- Stderr {
- inner: Pin::static_ref(&INSTANCE).get_or_init_pin(
- || ReentrantMutex::new(RefCell::new(stderr_raw())),
- |_| (),
- ),
- }
-}
-
-/// Constructs a new locked handle to the standard error of the current
-/// process.
-///
-/// This handle is not buffered.
-///
-/// ### Note: Windows Portability Consideration
-/// When operating in a console, the Windows implementation of this stream does not support
-/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return
-/// an error.
-///
-/// # Example
-///
-/// ```no_run
-/// #![feature(stdio_locked)]
-/// use std::io::{self, Write};
-///
-/// fn main() -> io::Result<()> {
-/// let mut handle = io::stderr_locked();
-///
-/// handle.write_all(b"hello world")?;
-///
-/// Ok(())
-/// }
-/// ```
-pub fn stderr_locked() -> StderrLock<'static> {
- stderr().into_locked()
+ Stderr { inner: &INSTANCE }
... 14276 lines suppressed ...
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org