mirror of
https://github.com/openharmony/third_party_rust_rustix.git
synced 2026-06-30 20:57:57 -04:00
rustix 0.38.8 社区漏洞 CVE-2024-43806 修复
修复措施:升级rustix版本到0.38.16版本 Signed-off-by: ljy9810 <longjianyin@h-partners.com>
This commit is contained in:
+19
-13
@@ -1,16 +1,22 @@
|
||||
# Implementation derived from `.cirrus.yml` in Rust's libc bindings
|
||||
# at revision 7f4774e76bd5cb9ccb7140d71ef9be9c16009cdf.
|
||||
|
||||
task:
|
||||
name: stable x86_64-unknown-freebsd-13
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-0-snap
|
||||
setup_script:
|
||||
- pkg install -y curl
|
||||
- curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
- sh rustup.sh --default-toolchain stable -y --profile=minimal
|
||||
- . $HOME/.cargo/env
|
||||
- rustup default stable
|
||||
test_script:
|
||||
- . $HOME/.cargo/env
|
||||
- cargo test --workspace --features=all-apis
|
||||
# Disable FreeBSD testing for now, as we currently hit this error:
|
||||
#
|
||||
# [4/4] Extracting curl-7.88.1: .......... done
|
||||
# curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
# ld-elf.so.1: /usr/local/lib/libcurl.so.4: Undefined symbol "nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation"
|
||||
|
||||
#task:
|
||||
# name: stable x86_64-unknown-freebsd-13
|
||||
# freebsd_instance:
|
||||
# image_family: freebsd-13-1
|
||||
# setup_script:
|
||||
# - pkg install -y curl
|
||||
# - curl https://sh.rustup.rs -sSf --output rustup.sh
|
||||
# - sh rustup.sh --default-toolchain stable -y --profile=minimal
|
||||
# - . $HOME/.cargo/env
|
||||
# - rustup default stable
|
||||
# test_script:
|
||||
# - . $HOME/.cargo/env
|
||||
# - cargo test --workspace --features=all-apis
|
||||
|
||||
+41
-163
@@ -62,12 +62,9 @@ jobs:
|
||||
i686-unknown-linux-gnu
|
||||
i686-unknown-linux-musl
|
||||
wasm32-unknown-emscripten
|
||||
riscv64gc-unknown-linux-gnu
|
||||
aarch64-unknown-linux-gnu
|
||||
aarch64-unknown-linux-musl
|
||||
powerpc64le-unknown-linux-gnu
|
||||
mipsel-unknown-linux-gnu
|
||||
mips64el-unknown-linux-gnuabi64
|
||||
armv5te-unknown-linux-gnueabi
|
||||
s390x-unknown-linux-gnu
|
||||
arm-linux-androideabi
|
||||
@@ -75,20 +72,31 @@ jobs:
|
||||
sparcv9-sun-solaris
|
||||
aarch64-linux-android
|
||||
aarch64-apple-ios
|
||||
- if: matrix.rust == 'nightly'
|
||||
wasm32-wasi
|
||||
- if: matrix.rust != '1.48'
|
||||
run: rustup target add x86_64-unknown-fuchsia
|
||||
- if: matrix.rust != 'nightly'
|
||||
- if: matrix.rust == '1.48'
|
||||
run: rustup target add x86_64-fuchsia
|
||||
|
||||
- name: Install cross-compilation tools
|
||||
run: |
|
||||
set -ex
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-i686-linux-gnu gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu gcc-arm-linux-gnueabi musl-tools
|
||||
sudo apt-get install -y gcc-i686-linux-gnu gcc-aarch64-linux-gnu gcc-arm-linux-gnueabi musl-tools
|
||||
|
||||
- name: Use specific dependency versions for Rust 1.48 compatibility.
|
||||
if: matrix.rust == '1.48'
|
||||
run: cargo update --package=once_cell --precise 1.14.0
|
||||
run: |
|
||||
cargo update --package=once_cell --precise 1.14.0
|
||||
cargo update --package=tempfile --precise=3.4.0
|
||||
cargo update --package=io-lifetimes --precise 1.0.6
|
||||
cargo update --package=flate2 --precise=1.0.25
|
||||
for crate in test-crates/*; do
|
||||
cd $crate
|
||||
cargo update --package=io-lifetimes --precise 1.0.6
|
||||
cd - >/dev/null
|
||||
done
|
||||
cargo update --package=tempfile --precise=3.6.0
|
||||
|
||||
- run: cargo check --workspace --release -vv --all-targets
|
||||
- run: cargo check --workspace --release -vv --features=all-apis --all-targets
|
||||
@@ -102,22 +110,19 @@ jobs:
|
||||
- run: cargo check --workspace --release -vv --target=x86_64-apple-darwin --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=x86_64-unknown-freebsd --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=x86_64-unknown-netbsd --features=all-apis --all-targets
|
||||
- if: matrix.rust == 'nightly'
|
||||
- if: matrix.rust != '1.48'
|
||||
run: cargo check --workspace --release -vv --target=x86_64-unknown-fuchsia --features=all-apis --all-targets
|
||||
- if: matrix.rust != 'nightly'
|
||||
- if: matrix.rust == '1.48'
|
||||
run: cargo check --workspace --release -vv --target=x86_64-fuchsia --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=x86_64-unknown-illumos --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=i686-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=i686-unknown-linux-musl --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=i686-unknown-linux-musl --features=use-libc,all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=wasm32-unknown-emscripten --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=riscv64gc-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=aarch64-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=aarch64-unknown-linux-musl --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=aarch64-unknown-linux-musl --features=use-libc,all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=powerpc64le-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=mipsel-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=mips64el-unknown-linux-gnuabi64 --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=armv5te-unknown-linux-gnueabi --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=s390x-unknown-linux-gnu --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=arm-linux-androideabi --features=all-apis --all-targets
|
||||
@@ -125,6 +130,10 @@ jobs:
|
||||
- run: cargo check --workspace --release -vv --target=sparcv9-sun-solaris --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=aarch64-apple-ios --features=all-apis --all-targets
|
||||
- run: cargo check --workspace --release -vv --target=aarch64-linux-android --features=all-apis --all-targets
|
||||
# Omit --all-targets for WASI until all the dev-dependencies support WASI
|
||||
# on stable.
|
||||
- if: matrix.rust != '1.48'
|
||||
run: cargo check --workspace --release -vv --target=wasm32-wasi --features=all-apis
|
||||
|
||||
check_no_default_features:
|
||||
name: Check --no-default-features
|
||||
@@ -204,6 +213,8 @@ jobs:
|
||||
- run: cargo check -Z build-std --target x86_64-unknown-dragonfly --all-targets --features=all-apis
|
||||
- run: cargo check -Z build-std --target sparc-unknown-linux-gnu --all-targets --features=all-apis
|
||||
- run: cargo check -Z build-std --target armv7-unknown-freebsd --all-targets --features=all-apis
|
||||
# Omit --all-targets on gnu_ilp32 because dev-dependency tempfile depends on an older rustix
|
||||
- run: cargo check -Z build-std --target aarch64-unknown-linux-gnu_ilp32 --features=all-apis
|
||||
# Omit --all-targets on haiku because not all the tests build yet.
|
||||
- run: cargo check -Z build-std --target x86_64-unknown-haiku --features=all-apis
|
||||
# x86_64-uwp-windows-msvc isn't currently working.
|
||||
@@ -216,13 +227,13 @@ jobs:
|
||||
QEMU_BUILD_VERSION: 7.0.0
|
||||
strategy:
|
||||
matrix:
|
||||
build: [ubuntu, ubuntu-18.04, i686-linux, aarch64-linux, powerpc64le-linux, riscv64-linux, s390x-linux, arm-linux, ubuntu-stable, ubuntu-1.48, i686-linux-stable, aarch64-linux-stable, riscv64-linux-stable, s390x-linux-stable, mipsel-linux-stable, mips64el-linux-stable, powerpc64le-linux-stable, arm-linux-stable, ubuntu-1.48, i686-linux-1.48, aarch64-linux-1.48, riscv64-linux-1.48, s390x-linux-1.48, mipsel-linux-1.48, mips64el-linux-1.48, powerpc64le-linux-1.48, arm-linux-1.48, macos-latest, macos-10.15, windows, windows-2019]
|
||||
build: [ubuntu, ubuntu-20.04, i686-linux, aarch64-linux, powerpc64le-linux, s390x-linux, arm-linux, ubuntu-stable, ubuntu-1.48, i686-linux-stable, aarch64-linux-stable, s390x-linux-stable, powerpc64le-linux-stable, arm-linux-stable, ubuntu-1.48, i686-linux-1.48, aarch64-linux-1.48, s390x-linux-1.48, powerpc64le-linux-1.48, arm-linux-1.48, macos-latest, macos-11, windows, windows-2019]
|
||||
include:
|
||||
- build: ubuntu
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: nightly
|
||||
- build: ubuntu-18.04
|
||||
os: ubuntu-18.04
|
||||
- build: ubuntu-20.04
|
||||
os: ubuntu-20.04
|
||||
rust: nightly
|
||||
- build: i686-linux
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
@@ -249,33 +260,6 @@ jobs:
|
||||
qemu: qemu-ppc64le
|
||||
qemu_args: -L /usr/powerpc64le-linux-gnu
|
||||
qemu_target: ppc64le-linux-user
|
||||
- build: mips64el-linux
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: nightly
|
||||
target: mips64el-unknown-linux-gnuabi64
|
||||
gcc_package: gcc-mips64el-linux-gnuabi64
|
||||
gcc: mips64el-linux-gnuabi64-gcc
|
||||
qemu: qemu-mips64el
|
||||
qemu_args: -L /usr/mips64el-linux-gnuabi64
|
||||
qemu_target: mips64el-linux-user
|
||||
- build: mipsel-linux
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: nightly
|
||||
target: mipsel-unknown-linux-gnu
|
||||
gcc_package: gcc-mipsel-linux-gnu
|
||||
gcc: mipsel-linux-gnu-gcc
|
||||
qemu: qemu-mipsel
|
||||
qemu_args: -L /usr/mipsel-linux-gnu
|
||||
qemu_target: mipsel-linux-user
|
||||
- build: riscv64-linux
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: nightly
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
gcc_package: gcc-riscv64-linux-gnu
|
||||
gcc: riscv64-linux-gnu-gcc
|
||||
qemu: qemu-riscv64
|
||||
qemu_args: -L /usr/riscv64-linux-gnu
|
||||
qemu_target: riscv64-linux-user
|
||||
- build: s390x-linux
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: nightly
|
||||
@@ -313,15 +297,6 @@ jobs:
|
||||
qemu: qemu-aarch64
|
||||
qemu_args: -L /usr/aarch64-linux-gnu
|
||||
qemu_target: aarch64-linux-user
|
||||
- build: riscv64-linux-stable
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: stable
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
gcc_package: gcc-riscv64-linux-gnu
|
||||
gcc: riscv64-linux-gnu-gcc
|
||||
qemu: qemu-riscv64
|
||||
qemu_args: -L /usr/riscv64-linux-gnu
|
||||
qemu_target: riscv64-linux-user
|
||||
- build: s390x-linux-stable
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: stable
|
||||
@@ -340,24 +315,6 @@ jobs:
|
||||
qemu: qemu-ppc64le
|
||||
qemu_args: -L /usr/powerpc64le-linux-gnu
|
||||
qemu_target: ppc64le-linux-user
|
||||
- build: mips64el-linux-stable
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: stable
|
||||
target: mips64el-unknown-linux-gnuabi64
|
||||
gcc_package: gcc-mips64el-linux-gnuabi64
|
||||
gcc: mips64el-linux-gnuabi64-gcc
|
||||
qemu: qemu-mips64el
|
||||
qemu_args: -L /usr/mips64el-linux-gnuabi64
|
||||
qemu_target: mips64el-linux-user
|
||||
- build: mipsel-linux-stable
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: stable
|
||||
target: mipsel-unknown-linux-gnu
|
||||
gcc_package: gcc-mipsel-linux-gnu
|
||||
gcc: mipsel-linux-gnu-gcc
|
||||
qemu: qemu-mipsel
|
||||
qemu_args: -L /usr/mipsel-linux-gnu
|
||||
qemu_target: mipsel-linux-user
|
||||
- build: arm-linux-stable
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: stable
|
||||
@@ -386,15 +343,6 @@ jobs:
|
||||
qemu: qemu-aarch64
|
||||
qemu_args: -L /usr/aarch64-linux-gnu
|
||||
qemu_target: aarch64-linux-user
|
||||
- build: riscv64-linux-1.48
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: 1.48
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
gcc_package: gcc-riscv64-linux-gnu
|
||||
gcc: riscv64-linux-gnu-gcc
|
||||
qemu: qemu-riscv64
|
||||
qemu_args: -L /usr/riscv64-linux-gnu
|
||||
qemu_target: riscv64-linux-user
|
||||
- build: s390x-linux-1.48
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: 1.48
|
||||
@@ -413,24 +361,6 @@ jobs:
|
||||
qemu: qemu-ppc64le
|
||||
qemu_args: -L /usr/powerpc64le-linux-gnu
|
||||
qemu_target: ppc64le-linux-user
|
||||
- build: mips64el-linux-1.48
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: 1.48
|
||||
target: mips64el-unknown-linux-gnuabi64
|
||||
gcc_package: gcc-mips64el-linux-gnuabi64
|
||||
gcc: mips64el-linux-gnuabi64-gcc
|
||||
qemu: qemu-mips64el
|
||||
qemu_args: -L /usr/mips64el-linux-gnuabi64
|
||||
qemu_target: mips64el-linux-user
|
||||
- build: mipsel-linux-1.48
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: 1.48
|
||||
target: mipsel-unknown-linux-gnu
|
||||
gcc_package: gcc-mipsel-linux-gnu
|
||||
gcc: mipsel-linux-gnu-gcc
|
||||
qemu: qemu-mipsel
|
||||
qemu_args: -L /usr/mipsel-linux-gnu
|
||||
qemu_target: mipsel-linux-user
|
||||
- build: arm-linux-1.48
|
||||
os: ubuntu-20.04 # TODO: remove pin when fixed (#483)
|
||||
rust: 1.48
|
||||
@@ -443,8 +373,8 @@ jobs:
|
||||
- build: macos-latest
|
||||
os: macos-latest
|
||||
rust: stable
|
||||
- build: macos-10.15
|
||||
os: macos-10.15
|
||||
- build: macos-11
|
||||
os: macos-11
|
||||
rust: stable
|
||||
- build: windows
|
||||
os: windows-latest
|
||||
@@ -495,11 +425,6 @@ jobs:
|
||||
upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
|
||||
echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ${{ matrix.qemu_args }} >> $GITHUB_ENV
|
||||
|
||||
# See if qemu is already in the cache
|
||||
if [ -f ${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Download and build qemu from source since the most recent release is
|
||||
# way faster at arm emulation than the current version github actions'
|
||||
# ubuntu image uses. Disable as much as we can to get it to build
|
||||
@@ -516,7 +441,17 @@ jobs:
|
||||
|
||||
- name: Use specific dependency versions for Rust 1.48 compatibility.
|
||||
if: matrix.rust == '1.48'
|
||||
run: cargo update --package=once_cell --precise 1.14.0
|
||||
run: |
|
||||
cargo update --package=once_cell --precise 1.14.0
|
||||
cargo update --package=tempfile --precise=3.4.0
|
||||
cargo update --package=io-lifetimes --precise 1.0.6
|
||||
cargo update --package=flate2 --precise=1.0.25
|
||||
for crate in test-crates/*; do
|
||||
cd $crate
|
||||
cargo update --package=io-lifetimes --precise 1.0.6
|
||||
cd - >/dev/null
|
||||
done
|
||||
cargo update --package=tempfile --precise=3.6.0
|
||||
|
||||
- run: |
|
||||
# Run the tests, and check the prebuilt release libraries.
|
||||
@@ -555,7 +490,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
build: [ubuntu, i686-linux, aarch64-linux, powerpc64le-linux, mips64el-linux, mipsel-linux, riscv64-linux, arm-linux]
|
||||
build: [ubuntu, i686-linux, aarch64-linux, powerpc64le-linux, arm-linux]
|
||||
include:
|
||||
- build: ubuntu
|
||||
os: ubuntu-latest
|
||||
@@ -585,33 +520,6 @@ jobs:
|
||||
qemu: qemu-ppc64le
|
||||
qemu_args: -L /usr/powerpc64le-linux-gnu
|
||||
qemu_target: ppc64le-linux-user
|
||||
- build: mips64el-linux
|
||||
os: ubuntu-latest
|
||||
rust: stable
|
||||
target: mips64el-unknown-linux-gnuabi64
|
||||
gcc_package: gcc-mips64el-linux-gnuabi64
|
||||
gcc: mips64el-linux-gnuabi64-gcc
|
||||
qemu: qemu-mips64el
|
||||
qemu_args: -L /usr/mips64el-linux-gnuabi64
|
||||
qemu_target: mips64el-linux-user
|
||||
- build: mipsel-linux
|
||||
os: ubuntu-latest
|
||||
rust: stable
|
||||
target: mipsel-unknown-linux-gnu
|
||||
gcc_package: gcc-mipsel-linux-gnu
|
||||
gcc: mipsel-linux-gnu-gcc
|
||||
qemu: qemu-mipsel
|
||||
qemu_args: -L /usr/mipsel-linux-gnu
|
||||
qemu_target: mipsel-linux-user
|
||||
- build: riscv64-linux
|
||||
os: ubuntu-latest
|
||||
rust: stable
|
||||
target: riscv64gc-unknown-linux-gnu
|
||||
gcc_package: gcc-riscv64-linux-gnu
|
||||
gcc: riscv64-linux-gnu-gcc
|
||||
qemu: qemu-riscv64
|
||||
qemu_args: -L /usr/riscv64-linux-gnu
|
||||
qemu_target: riscv64-linux-user
|
||||
- build: arm-linux
|
||||
os: ubuntu-latest
|
||||
rust: stable
|
||||
@@ -668,11 +576,6 @@ jobs:
|
||||
upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
|
||||
echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ${{ matrix.qemu_args }} >> $GITHUB_ENV
|
||||
|
||||
# See if qemu is already in the cache
|
||||
if [ -f ${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Download and build qemu from source since the most recent release is
|
||||
# way faster at arm emulation than the current version github actions'
|
||||
# ubuntu image uses. Disable as much as we can to get it to build
|
||||
@@ -697,7 +600,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
build: [powerpc64le-linux, mipsel-linux, mips64el-linux]
|
||||
build: [powerpc64le-linux]
|
||||
include:
|
||||
- build: powerpc64le-linux
|
||||
os: ubuntu-latest
|
||||
@@ -708,31 +611,11 @@ jobs:
|
||||
qemu: qemu-ppc64le
|
||||
qemu_args: -L /usr/powerpc64le-linux-gnu
|
||||
qemu_target: ppc64le-linux-user
|
||||
- build: mips64el-linux
|
||||
os: ubuntu-latest
|
||||
rust: nightly
|
||||
target: mips64el-unknown-linux-gnuabi64
|
||||
gcc_package: gcc-mips64el-linux-gnuabi64
|
||||
gcc: mips64el-linux-gnuabi64-gcc
|
||||
qemu: qemu-mips64el
|
||||
qemu_args: -L /usr/mips64el-linux-gnuabi64
|
||||
qemu_target: mips64el-linux-user
|
||||
- build: mipsel-linux
|
||||
os: ubuntu-latest
|
||||
rust: nightly
|
||||
target: mipsel-unknown-linux-gnu
|
||||
gcc_package: gcc-mipsel-linux-gnu
|
||||
gcc: mipsel-linux-gnu-gcc
|
||||
qemu: qemu-mipsel
|
||||
qemu_args: -L /usr/mipsel-linux-gnu
|
||||
qemu_target: mipsel-linux-user
|
||||
env:
|
||||
# -D warnings is commented out in our install-rust action; re-add it here.
|
||||
RUSTFLAGS: --cfg rustix_use_experimental_asm -D warnings
|
||||
RUSTDOCFLAGS: --cfg rustix_use_experimental_asm
|
||||
CARGO_TARGET_POWERPC64LE_UNKNOWN_LINUX_GNU_RUSTFLAGS: --cfg rustix_use_experimental_asm
|
||||
CARGO_TARGET_MIPSEL_UNKNOWN_LINUX_GNU_RUSTFLAGS: --cfg rustix_use_experimental_asm
|
||||
CARGO_TARGET_MIPS64EL_UNKNOWN_LINUX_GNUABI64_RUSTFLAGS: --cfg rustix_use_experimental_asm
|
||||
QEMU_BUILD_VERSION: 7.0.0
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -777,11 +660,6 @@ jobs:
|
||||
upcase=$(echo ${{ matrix.target }} | awk '{ print toupper($0) }' | sed 's/-/_/g')
|
||||
echo CARGO_TARGET_${upcase}_RUNNER=${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ${{ matrix.qemu_args }} >> $GITHUB_ENV
|
||||
|
||||
# See if qemu is already in the cache
|
||||
if [ -f ${{ runner.tool_cache }}/qemu/bin/${{ matrix.qemu }} ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Download and build qemu from source since the most recent release is
|
||||
# way faster at arm emulation than the current version github actions'
|
||||
# ubuntu image uses. Disable as much as we can to get it to build
|
||||
|
||||
@@ -21,7 +21,7 @@ if (host_os != "linux" || host_cpu != "arm64") {
|
||||
|
||||
sources = [ "src/lib.rs" ]
|
||||
edition = "2018"
|
||||
cargo_pkg_version = "0.36.8"
|
||||
cargo_pkg_version = "0.36.16"
|
||||
cargo_pkg_authors = "Dan Gohman <dev@sunfishcode.online>, Jakub Konka <kubkon@jakubkonka.com>"
|
||||
cargo_pkg_name = "rustix"
|
||||
cargo_pkg_description =
|
||||
|
||||
+4
-16
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustix"
|
||||
version = "0.36.8"
|
||||
version = "0.36.16"
|
||||
authors = [
|
||||
"Dan Gohman <dev@sunfishcode.online>",
|
||||
"Jakub Konka <kubkon@jakubkonka.com>",
|
||||
@@ -40,7 +40,7 @@ once_cell = { version = "1.5.2", optional = true }
|
||||
# `RUSTFLAGS` or enabling the `use-libc` cargo feature.
|
||||
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", any(target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"), all(target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "powerpc64", target_arch = "riscv64", target_arch = "mips", target_arch = "mips64")))))'.dependencies]
|
||||
linux-raw-sys = { version = "0.1.2", default-features = false, features = ["general", "errno", "ioctl", "no_std"] }
|
||||
libc_errno = { package = "errno", version = "0.2.8", default-features = false, optional = true }
|
||||
libc_errno = { package = "errno", version = "0.3.0", default-features = false, optional = true }
|
||||
libc = { version = "0.2.133", features = ["extra_traits"], optional = true }
|
||||
|
||||
# Dependencies for platforms where only libc is supported:
|
||||
@@ -48,7 +48,7 @@ libc = { version = "0.2.133", features = ["extra_traits"], optional = true }
|
||||
# On all other Unix-family platforms, and under Miri, we always use the libc
|
||||
# backend, so enable its dependencies unconditionally.
|
||||
[target.'cfg(any(rustix_use_libc, miri, not(all(target_os = "linux", any(target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"), all(target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "powerpc64", target_arch = "riscv64", target_arch = "mips", target_arch = "mips64")))))))'.dependencies]
|
||||
libc_errno = { package = "errno", version = "0.2.8", default-features = false }
|
||||
libc_errno = { package = "errno", version = "0.3.0", default-features = false }
|
||||
libc = { version = "0.2.133", features = ["extra_traits"] }
|
||||
|
||||
# Additional dependencies for Linux with the libc backend:
|
||||
@@ -71,26 +71,14 @@ features = [
|
||||
[dev-dependencies]
|
||||
tempfile = "3.2.0"
|
||||
libc = "0.2.133"
|
||||
libc_errno = { package = "errno", version = "0.2.8", default-features = false }
|
||||
libc_errno = { package = "errno", version = "0.3.0", default-features = false }
|
||||
io-lifetimes = { version = "1.0.0", default-features = false, features = ["close"] }
|
||||
# Don't upgrade to serial_test 0.7 for now because it depends on a
|
||||
# `parking_lot_core` version which is not compatible with our MSRV of 1.48.
|
||||
serial_test = "0.6"
|
||||
memoffset = "0.7.1"
|
||||
flate2 = "1.0"
|
||||
|
||||
[target.'cfg(all(criterion, not(any(target_os = "emscripten", target_os = "wasi"))))'.dev-dependencies]
|
||||
criterion = "0.4"
|
||||
|
||||
[target.'cfg(windows)'.dev-dependencies]
|
||||
ctor = "0.1.21"
|
||||
|
||||
# Add Criterion configuration, as described here:
|
||||
# <https://bheisler.github.io/criterion.rs/book/getting_started.html#step-1---add-dependency-to-cargotoml>
|
||||
[[bench]]
|
||||
name = "mod"
|
||||
harness = false
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["all-apis"]
|
||||
rustdoc-args = ["--cfg", "doc_cfg"]
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"Name": "rustix",
|
||||
"License": "Apache-2.0_WITH_LLVM-exception, Apache License 2.0, MIT",
|
||||
"License File": "LICENSE-Apache-2.0_WITH_LLVM-exception, LICENSE-APACHE, LICENSE-MIT",
|
||||
"Version Number": "0.36.8",
|
||||
"Version Number": "0.36.16",
|
||||
"Owner": "fangting12@huawei.com",
|
||||
"Upstream URL": "https://github.com/bytecodealliance/rustix",
|
||||
"Description": "A Rust library that provides support for working with UTF-8 encoded strings."
|
||||
|
||||
@@ -87,8 +87,8 @@ by default. The rest of the API is conditional with cargo feature flags:
|
||||
|
||||
## Similar crates
|
||||
|
||||
`rustix` is similar to [`nix`], [`simple_libc`], [`unix`], [`nc`], and
|
||||
[`uapi`]. `rustix` is architected for [I/O safety] with most APIs using
|
||||
`rustix` is similar to [`nix`], [`simple_libc`], [`unix`], [`nc`], [`uapi`],
|
||||
and [`rusl`]. `rustix` is architected for [I/O safety] with most APIs using
|
||||
[`OwnedFd`] and [`AsFd`] to manipulate file descriptors rather than `File` or
|
||||
even `c_int`, and supporting multiple backends so that it can use direct
|
||||
syscalls while still being usable on all platforms `libc` supports. Like `nix`,
|
||||
@@ -136,6 +136,7 @@ version of this crate.
|
||||
[`nc`]: https://crates.io/crates/nc
|
||||
[`simple_libc`]: https://crates.io/crates/simple_libc
|
||||
[`uapi`]: https://crates.io/crates/uapi
|
||||
[`rusl`]: https://lib.rs/crates/rusl
|
||||
[`relibc`]: https://github.com/redox-os/relibc
|
||||
[`syscall`]: https://crates.io/crates/syscall
|
||||
[`sc`]: https://crates.io/crates/sc
|
||||
|
||||
-182
@@ -1,182 +0,0 @@
|
||||
/// Benchmarks for rustix.
|
||||
///
|
||||
/// To enable these benchmarks, add `--cfg=criterion` to RUSTFLAGS and enable
|
||||
/// the "fs", "time", and "process" cargo features.
|
||||
|
||||
#[cfg(any(
|
||||
not(criterion),
|
||||
not(feature = "fs"),
|
||||
not(feature = "process"),
|
||||
not(feature = "time"),
|
||||
windows,
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "wasi",
|
||||
))]
|
||||
fn main() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
not(criterion),
|
||||
not(feature = "fs"),
|
||||
not(feature = "process"),
|
||||
not(feature = "time"),
|
||||
windows,
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "wasi",
|
||||
)))]
|
||||
use criterion::{criterion_group, criterion_main};
|
||||
|
||||
#[cfg(not(any(
|
||||
not(criterion),
|
||||
not(feature = "fs"),
|
||||
not(feature = "process"),
|
||||
not(feature = "time"),
|
||||
windows,
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "wasi",
|
||||
)))]
|
||||
mod suite {
|
||||
use criterion::Criterion;
|
||||
|
||||
pub(super) fn simple_statat(c: &mut Criterion) {
|
||||
use rustix::fs::{cwd, statat, AtFlags};
|
||||
|
||||
c.bench_function("simple statat", |b| {
|
||||
b.iter(|| {
|
||||
statat(cwd(), "/", AtFlags::empty()).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn simple_statat_libc(c: &mut Criterion) {
|
||||
c.bench_function("simple statat libc", |b| {
|
||||
b.iter(|| {
|
||||
let mut s = std::mem::MaybeUninit::<libc::stat>::uninit();
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
libc::fstatat(
|
||||
libc::AT_FDCWD,
|
||||
std::ffi::CString::new("/").unwrap().as_c_str().as_ptr() as _,
|
||||
s.as_mut_ptr(),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn simple_statat_libc_cstr(c: &mut Criterion) {
|
||||
c.bench_function("simple statat libc cstr", |b| {
|
||||
b.iter(|| {
|
||||
let mut s = std::mem::MaybeUninit::<libc::stat>::uninit();
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
libc::fstatat(
|
||||
libc::AT_FDCWD,
|
||||
rustix::cstr!("/").as_ptr() as _,
|
||||
s.as_mut_ptr(),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn simple_statat_cstr(c: &mut Criterion) {
|
||||
use rustix::fs::{cwd, statat, AtFlags};
|
||||
|
||||
c.bench_function("simple statat cstr", |b| {
|
||||
b.iter(|| {
|
||||
statat(cwd(), rustix::cstr!("/"), AtFlags::empty()).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
pub(super) fn simple_clock_gettime(c: &mut Criterion) {
|
||||
use rustix::time::{clock_gettime, ClockId};
|
||||
|
||||
c.bench_function("simple clock_gettime", |b| {
|
||||
b.iter(|| {
|
||||
let _ = clock_gettime(ClockId::Monotonic);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
pub(super) fn simple_clock_gettime_libc(c: &mut Criterion) {
|
||||
c.bench_function("simple clock_gettime libc", |b| {
|
||||
b.iter(|| {
|
||||
let mut s = std::mem::MaybeUninit::<libc::timespec>::uninit();
|
||||
unsafe {
|
||||
assert_eq!(
|
||||
libc::clock_gettime(libc::CLOCK_MONOTONIC, s.as_mut_ptr()),
|
||||
0
|
||||
);
|
||||
let _ = s.assume_init();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
pub(super) fn simple_getpid(c: &mut Criterion) {
|
||||
use rustix::process::getpid;
|
||||
|
||||
c.bench_function("simple getpid", |b| {
|
||||
b.iter(|| {
|
||||
let _ = getpid();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
pub(super) fn simple_getpid_libc(c: &mut Criterion) {
|
||||
c.bench_function("simple getpid libc", |b| {
|
||||
b.iter(|| unsafe {
|
||||
let _ = libc::getpid();
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
not(criterion),
|
||||
not(feature = "fs"),
|
||||
not(feature = "process"),
|
||||
not(feature = "time"),
|
||||
windows,
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "wasi",
|
||||
)))]
|
||||
criterion_group!(
|
||||
benches,
|
||||
suite::simple_statat,
|
||||
suite::simple_statat_libc,
|
||||
suite::simple_statat_libc_cstr,
|
||||
suite::simple_statat_cstr,
|
||||
suite::simple_clock_gettime,
|
||||
suite::simple_clock_gettime_libc,
|
||||
suite::simple_getpid,
|
||||
suite::simple_getpid_libc
|
||||
);
|
||||
#[cfg(not(any(
|
||||
not(criterion),
|
||||
not(feature = "fs"),
|
||||
not(feature = "process"),
|
||||
not(feature = "time"),
|
||||
windows,
|
||||
target_os = "emscripten",
|
||||
target_os = "redox",
|
||||
target_os = "wasi",
|
||||
)))]
|
||||
criterion_main!(benches);
|
||||
@@ -26,7 +26,7 @@ fn main() {
|
||||
let arch = var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let asm_name = format!("{}/{}.s", OUTLINE_PATH, arch);
|
||||
let asm_name_present = std::fs::metadata(&asm_name).is_ok();
|
||||
let os_name = var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let target_os = var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let pointer_width = var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap();
|
||||
let endian = var("CARGO_CFG_TARGET_ENDIAN").unwrap();
|
||||
|
||||
@@ -69,7 +69,7 @@ fn main() {
|
||||
// install the toolchain for it.
|
||||
if feature_use_libc
|
||||
|| cfg_use_libc
|
||||
|| os_name != "linux"
|
||||
|| target_os != "linux"
|
||||
|| !asm_name_present
|
||||
|| is_unsupported_abi
|
||||
|| miri
|
||||
@@ -106,7 +106,17 @@ fn main() {
|
||||
use_feature("thumb_mode");
|
||||
}
|
||||
|
||||
if target_os == "wasi" {
|
||||
use_feature_or_nothing("wasi_ext");
|
||||
}
|
||||
println!("cargo:rerun-if-env-changed=CARGO_CFG_RUSTIX_USE_EXPERIMENTAL_ASM");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_CFG_RUSTIX_USE_LIBC");
|
||||
|
||||
// Rerun this script if any of our features or configuration flags change,
|
||||
// or if the toolchain we used for feature detection changes.
|
||||
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_USE_LIBC");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_RUSTC_DEP_OF_STD");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_CFG_MIRI");
|
||||
}
|
||||
|
||||
/// Link in the desired version of librustix_outline_{arch}.a, containing the
|
||||
@@ -187,7 +197,14 @@ fn can_compile<T: AsRef<str>>(test: T) -> bool {
|
||||
let rustc = var("RUSTC").unwrap();
|
||||
let target = var("TARGET").unwrap();
|
||||
|
||||
let mut cmd = if let Ok(wrapper) = var("CARGO_RUSTC_WRAPPER") {
|
||||
// Use `RUSTC_WRAPPER` if it's set, unless it's set to an empty string,
|
||||
// as documented [here].
|
||||
// [here]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-reads
|
||||
let wrapper = var("RUSTC_WRAPPER")
|
||||
.ok()
|
||||
.and_then(|w| if w.is_empty() { None } else { Some(w) });
|
||||
|
||||
let mut cmd = if let Some(wrapper) = wrapper {
|
||||
let mut cmd = std::process::Command::new(wrapper);
|
||||
// The wrapper's first argument is supposed to be the path to rustc.
|
||||
cmd.arg(rustc);
|
||||
|
||||
+90
-12
@@ -57,8 +57,13 @@ use core::ptr::NonNull;
|
||||
use libc_errno::{errno, set_errno, Errno};
|
||||
|
||||
/// `DIR*`
|
||||
#[repr(transparent)]
|
||||
pub struct Dir(NonNull<c::DIR>);
|
||||
pub struct Dir {
|
||||
/// The `libc` `DIR` pointer.
|
||||
libc_dir: NonNull<c::DIR>,
|
||||
|
||||
/// Have we seen any errors in this iteration?
|
||||
any_errors: bool,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
/// Construct a `Dir` that reads entries from the given directory
|
||||
@@ -69,21 +74,38 @@ impl Dir {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unused_mut)]
|
||||
fn _read_from(fd: BorrowedFd<'_>) -> io::Result<Self> {
|
||||
let mut any_errors = false;
|
||||
|
||||
// Given an arbitrary `OwnedFd`, it's impossible to know whether the
|
||||
// user holds a `dup`'d copy which could continue to modify the
|
||||
// file description state, which would cause Undefined Behavior after
|
||||
// our call to `fdopendir`. To prevent this, we obtain an independent
|
||||
// `OwnedFd`.
|
||||
let flags = fcntl_getfl(fd)?;
|
||||
let fd_for_dir = openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty())?;
|
||||
let fd_for_dir = match openat(fd, cstr!("."), flags | OFlags::CLOEXEC, Mode::empty()) {
|
||||
Ok(fd) => fd,
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
Err(io::Errno::NOENT) => {
|
||||
// If "." doesn't exist, it means the directory was removed.
|
||||
// We treat that as iterating through a directory with no
|
||||
// entries.
|
||||
any_errors = true;
|
||||
crate::io::dup(fd)?
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
let raw = owned_fd(fd_for_dir);
|
||||
unsafe {
|
||||
let libc_dir = c::fdopendir(raw);
|
||||
|
||||
if let Some(libc_dir) = NonNull::new(libc_dir) {
|
||||
Ok(Self(libc_dir))
|
||||
Ok(Self {
|
||||
libc_dir,
|
||||
any_errors,
|
||||
})
|
||||
} else {
|
||||
let err = io::Errno::last_os_error();
|
||||
let _ = c::close(raw);
|
||||
@@ -95,13 +117,19 @@ impl Dir {
|
||||
/// `rewinddir(self)`
|
||||
#[inline]
|
||||
pub fn rewind(&mut self) {
|
||||
unsafe { c::rewinddir(self.0.as_ptr()) }
|
||||
self.any_errors = false;
|
||||
unsafe { c::rewinddir(self.libc_dir.as_ptr()) }
|
||||
}
|
||||
|
||||
/// `readdir(self)`, where `None` means the end of the directory.
|
||||
pub fn read(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
// If we've seen errors, don't continue to try to read anyting further.
|
||||
if self.any_errors {
|
||||
return None;
|
||||
}
|
||||
|
||||
set_errno(Errno(0));
|
||||
let dirent_ptr = unsafe { libc_readdir(self.0.as_ptr()) };
|
||||
let dirent_ptr = unsafe { libc_readdir(self.libc_dir.as_ptr()) };
|
||||
if dirent_ptr.is_null() {
|
||||
let curr_errno = errno().0;
|
||||
if curr_errno == 0 {
|
||||
@@ -109,6 +137,7 @@ impl Dir {
|
||||
None
|
||||
} else {
|
||||
// `errno` is unknown or non-zero, so an error occurred.
|
||||
self.any_errors = true;
|
||||
Some(Err(io::Errno(curr_errno)))
|
||||
}
|
||||
} else {
|
||||
@@ -134,7 +163,7 @@ impl Dir {
|
||||
/// `fstat(self)`
|
||||
#[inline]
|
||||
pub fn stat(&self) -> io::Result<Stat> {
|
||||
fstat(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) })
|
||||
fstat(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) })
|
||||
}
|
||||
|
||||
/// `fstatfs(self)`
|
||||
@@ -148,7 +177,7 @@ impl Dir {
|
||||
)))]
|
||||
#[inline]
|
||||
pub fn statfs(&self) -> io::Result<StatFs> {
|
||||
fstatfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) })
|
||||
fstatfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) })
|
||||
}
|
||||
|
||||
/// `fstatvfs(self)`
|
||||
@@ -161,14 +190,14 @@ impl Dir {
|
||||
)))]
|
||||
#[inline]
|
||||
pub fn statvfs(&self) -> io::Result<StatVfs> {
|
||||
fstatvfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) })
|
||||
fstatvfs(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) })
|
||||
}
|
||||
|
||||
/// `fchdir(self)`
|
||||
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
|
||||
#[inline]
|
||||
pub fn chdir(&self) -> io::Result<()> {
|
||||
fchdir(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.0.as_ptr())) })
|
||||
fchdir(unsafe { BorrowedFd::borrow_raw(c::dirfd(self.libc_dir.as_ptr())) })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +371,7 @@ unsafe impl Send for Dir {}
|
||||
impl Drop for Dir {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::closedir(self.0.as_ptr()) };
|
||||
unsafe { c::closedir(self.libc_dir.as_ptr()) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +387,7 @@ impl Iterator for Dir {
|
||||
impl fmt::Debug for Dir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Dir")
|
||||
.field("fd", unsafe { &c::dirfd(self.0.as_ptr()) })
|
||||
.field("fd", unsafe { &c::dirfd(self.libc_dir.as_ptr()) })
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -485,3 +514,52 @@ fn check_dirent_layout(dirent: &c::dirent) {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir_iterator_handles_io_errors() {
|
||||
// create a dir, keep the FD, then delete the dir
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let fd = crate::fs::openat(
|
||||
crate::fs::cwd(),
|
||||
tmp.path(),
|
||||
crate::fs::OFlags::RDONLY | crate::fs::OFlags::CLOEXEC,
|
||||
crate::fs::Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let file_fd = crate::fs::openat(
|
||||
&fd,
|
||||
tmp.path().join("test.txt"),
|
||||
crate::fs::OFlags::WRONLY | crate::fs::OFlags::CREATE,
|
||||
crate::fs::Mode::RWXU,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut dir = Dir::read_from(&fd).unwrap();
|
||||
|
||||
// Reach inside the `Dir` and replace its directory with a file, which
|
||||
// will cause the subsequent `readdir` to fail.
|
||||
unsafe {
|
||||
let raw_fd = c::dirfd(dir.libc_dir.as_ptr());
|
||||
let mut owned_fd: crate::fd::OwnedFd = crate::fd::FromRawFd::from_raw_fd(raw_fd);
|
||||
crate::io::dup2(&file_fd, &mut owned_fd).unwrap();
|
||||
core::mem::forget(owned_fd);
|
||||
}
|
||||
|
||||
// FreeBSD and macOS seem to read some directory entries before we call
|
||||
// `.next()`.
|
||||
#[cfg(any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "watchos",
|
||||
target_os = "tvos",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonflybsd"
|
||||
))]
|
||||
{
|
||||
dir.rewind();
|
||||
}
|
||||
|
||||
assert!(matches!(dir.next(), Some(Err(_))));
|
||||
assert!(matches!(dir.next(), None));
|
||||
}
|
||||
|
||||
@@ -1485,13 +1485,20 @@ fn stat64_to_stat(s64: c::stat64) -> io::Result<Stat> {
|
||||
mod sys {
|
||||
use super::{c, BorrowedFd, Statx};
|
||||
|
||||
// Some versions of the libc bindings don't have these, so provide
|
||||
// our own definitions (which may become unused when libc gains
|
||||
// bindings for them).
|
||||
#[cfg(all(target_os = "android", target_arch = "arm"))]
|
||||
#[allow(dead_code)]
|
||||
const SYS_statx: c::c_long = 397;
|
||||
#[cfg(all(target_os = "android", target_arch = "x86"))]
|
||||
#[allow(dead_code)]
|
||||
const SYS_statx: c::c_long = 383;
|
||||
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
||||
#[allow(dead_code)]
|
||||
const SYS_statx: c::c_long = 291;
|
||||
#[cfg(all(target_os = "android", target_arch = "x86_64"))]
|
||||
#[allow(dead_code)]
|
||||
const SYS_statx: c::c_long = 332;
|
||||
|
||||
weak_or_syscall! {
|
||||
|
||||
+109
-14
@@ -213,8 +213,21 @@ pub(super) use c::posix_fadvise64 as libc_posix_fadvise;
|
||||
pub(super) use c::{pread as libc_pread, pwrite as libc_pwrite};
|
||||
#[cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten"))]
|
||||
pub(super) use c::{pread64 as libc_pread, pwrite64 as libc_pwrite};
|
||||
#[cfg(not(any(
|
||||
windows,
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "redox",
|
||||
target_os = "solaris",
|
||||
)))]
|
||||
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
|
||||
#[cfg(any(target_os = "linux", target_os = "emscripten"))]
|
||||
pub(super) use c::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
mod readwrite_pv64 {
|
||||
use super::c;
|
||||
@@ -302,20 +315,9 @@ mod readwrite_pv64 {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(
|
||||
windows,
|
||||
target_os = "android",
|
||||
target_os = "emscripten",
|
||||
target_os = "haiku",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "redox",
|
||||
target_os = "solaris",
|
||||
)))]
|
||||
pub(super) use c::{preadv as libc_preadv, pwritev as libc_pwritev};
|
||||
#[cfg(target_os = "android")]
|
||||
pub(super) use readwrite_pv64::{preadv64 as libc_preadv, pwritev64 as libc_pwritev};
|
||||
|
||||
// macOS added preadv and pwritev in version 11.0
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
mod readwrite_pv {
|
||||
@@ -337,11 +339,104 @@ mod readwrite_pv {
|
||||
) -> c::ssize_t
|
||||
}
|
||||
}
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
pub(super) use c::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
|
||||
#[cfg(any(target_os = "ios", target_os = "macos"))]
|
||||
pub(super) use readwrite_pv::{preadv as libc_preadv, pwritev as libc_pwritev};
|
||||
|
||||
// GLIBC added `preadv64v2` and `pwritev64v2` in version 2.26.
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
mod readwrite_pv64v2 {
|
||||
use super::c;
|
||||
|
||||
// 64-bit offsets on 32-bit platforms are passed in endianness-specific
|
||||
// lo/hi pairs. See src/backend/linux_raw/conv.rs for details.
|
||||
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
|
||||
fn lo(x: u64) -> usize {
|
||||
(x >> 32) as usize
|
||||
}
|
||||
#[cfg(all(target_endian = "little", target_pointer_width = "32"))]
|
||||
fn hi(x: u64) -> usize {
|
||||
(x & 0xffff_ffff) as usize
|
||||
}
|
||||
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
|
||||
fn lo(x: u64) -> usize {
|
||||
(x & 0xffff_ffff) as usize
|
||||
}
|
||||
#[cfg(all(target_endian = "big", target_pointer_width = "32"))]
|
||||
fn hi(x: u64) -> usize {
|
||||
(x >> 32) as usize
|
||||
}
|
||||
|
||||
pub(in super::super) unsafe fn preadv64v2(
|
||||
fd: c::c_int,
|
||||
iov: *const c::iovec,
|
||||
iovcnt: c::c_int,
|
||||
offset: c::off64_t,
|
||||
flags: c::c_int,
|
||||
) -> c::ssize_t {
|
||||
// Older GLIBC lacks `preadv64v2`, so use the `weak!` mechanism to
|
||||
// test for it, and call back to `c::syscall`. We don't use
|
||||
// `weak_or_syscall` here because we need to pass the 64-bit offset
|
||||
// specially.
|
||||
weak! {
|
||||
fn preadv64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
|
||||
}
|
||||
if let Some(fun) = preadv64v2.get() {
|
||||
fun(fd, iov, iovcnt, offset, flags)
|
||||
} else {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
c::syscall(
|
||||
c::SYS_preadv,
|
||||
fd,
|
||||
iov,
|
||||
iovcnt,
|
||||
hi(offset as u64),
|
||||
lo(offset as u64),
|
||||
flags,
|
||||
) as c::ssize_t
|
||||
}
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
{
|
||||
c::syscall(c::SYS_preadv2, fd, iov, iovcnt, offset, flags) as c::ssize_t
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(in super::super) unsafe fn pwritev64v2(
|
||||
fd: c::c_int,
|
||||
iov: *const c::iovec,
|
||||
iovcnt: c::c_int,
|
||||
offset: c::off64_t,
|
||||
flags: c::c_int,
|
||||
) -> c::ssize_t {
|
||||
// See the comments in `preadv64v2`.
|
||||
weak! {
|
||||
fn pwritev64v2(c::c_int, *const c::iovec, c::c_int, c::off64_t, c::c_int) -> c::ssize_t
|
||||
}
|
||||
if let Some(fun) = pwritev64v2.get() {
|
||||
fun(fd, iov, iovcnt, offset, flags)
|
||||
} else {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
{
|
||||
c::syscall(
|
||||
c::SYS_pwritev,
|
||||
fd,
|
||||
iov,
|
||||
iovcnt,
|
||||
hi(offset as u64),
|
||||
lo(offset as u64),
|
||||
flags,
|
||||
) as c::ssize_t
|
||||
}
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
{
|
||||
c::syscall(c::SYS_pwritev2, fd, iov, iovcnt, offset, flags) as c::ssize_t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
pub(super) use readwrite_pv64v2::{preadv64v2 as libc_preadv2, pwritev64v2 as libc_pwritev2};
|
||||
|
||||
#[cfg(not(any(
|
||||
windows,
|
||||
target_os = "aix",
|
||||
|
||||
@@ -291,7 +291,13 @@ pub(crate) fn gettid() -> Pid {
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[inline]
|
||||
pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
|
||||
unsafe { ret_c_int(c::setns(borrowed_fd(fd), nstype)) }
|
||||
// `setns` wasn't supported in glibc until 2.14, and musl until 0.9.5,
|
||||
// so use `syscall`.
|
||||
weak_or_syscall! {
|
||||
fn setns(fd: c::c_int, nstype: c::c_int) via SYS_setns -> c::c_int
|
||||
}
|
||||
|
||||
unsafe { ret_c_int(setns(borrowed_fd(fd), nstype)) }
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
//! instruction.
|
||||
//!
|
||||
//! Most `rustix` syscalls use the vsyscall mechanism rather than going using
|
||||
//! `int 0x80` sequences.
|
||||
//! `int 0x80` sequences, as vsyscall is much faster.
|
||||
//!
|
||||
//! Syscalls made with `int 0x80` preserve the flags register, while syscalls
|
||||
//! made using vsyscall do not.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
@@ -25,7 +28,6 @@ pub(in crate::backend) unsafe fn indirect_syscall0(
|
||||
"call {callee}",
|
||||
callee = in(reg) callee,
|
||||
inlateout("eax") nr.to_asm() => r0,
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -42,7 +44,6 @@ pub(in crate::backend) unsafe fn indirect_syscall1(
|
||||
callee = in(reg) callee,
|
||||
inlateout("eax") nr.to_asm() => r0,
|
||||
in("ebx") a0.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -76,7 +77,6 @@ pub(in crate::backend) unsafe fn indirect_syscall2(
|
||||
inlateout("eax") nr.to_asm() => r0,
|
||||
in("ebx") a0.to_asm(),
|
||||
in("ecx") a1.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -97,7 +97,6 @@ pub(in crate::backend) unsafe fn indirect_syscall3(
|
||||
in("ebx") a0.to_asm(),
|
||||
in("ecx") a1.to_asm(),
|
||||
in("edx") a2.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -128,7 +127,6 @@ pub(in crate::backend) unsafe fn indirect_syscall4(
|
||||
in("ebx") a0.to_asm(),
|
||||
in("ecx") a1.to_asm(),
|
||||
in("edx") a2.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -161,7 +159,6 @@ pub(in crate::backend) unsafe fn indirect_syscall5(
|
||||
in("ecx") a1.to_asm(),
|
||||
in("edx") a2.to_asm(),
|
||||
in("edi") a4.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
@@ -203,7 +200,6 @@ pub(in crate::backend) unsafe fn indirect_syscall6(
|
||||
in("ecx") a1.to_asm(),
|
||||
in("edx") a2.to_asm(),
|
||||
in("edi") a4.to_asm(),
|
||||
options(preserves_flags)
|
||||
);
|
||||
FromAsm::from_asm(r0)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,17 @@ pub struct Dir {
|
||||
/// The `OwnedFd` that we read directory entries from.
|
||||
fd: OwnedFd,
|
||||
|
||||
/// Have we seen any errors in this iteration?
|
||||
any_errors: bool,
|
||||
|
||||
/// Should we rewind the stream on the next iteration?
|
||||
rewind: bool,
|
||||
|
||||
/// The buffer for `linux_dirent64` entries.
|
||||
buf: Vec<u8>,
|
||||
|
||||
/// Where we are in the buffer.
|
||||
pos: usize,
|
||||
next: Option<u64>,
|
||||
}
|
||||
|
||||
impl Dir {
|
||||
@@ -37,25 +45,39 @@ impl Dir {
|
||||
|
||||
Ok(Self {
|
||||
fd: fd_for_dir,
|
||||
any_errors: false,
|
||||
rewind: false,
|
||||
buf: Vec::new(),
|
||||
pos: 0,
|
||||
next: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// `rewinddir(self)`
|
||||
#[inline]
|
||||
pub fn rewind(&mut self) {
|
||||
self.any_errors = false;
|
||||
self.rewind = true;
|
||||
self.pos = self.buf.len();
|
||||
self.next = Some(0);
|
||||
}
|
||||
|
||||
/// `readdir(self)`, where `None` means the end of the directory.
|
||||
pub fn read(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
if let Some(next) = self.next.take() {
|
||||
match crate::backend::fs::syscalls::_seek(self.fd.as_fd(), next as i64, SEEK_SET) {
|
||||
// If we've seen errors, don't continue to try to read anyting further.
|
||||
if self.any_errors {
|
||||
return None;
|
||||
}
|
||||
|
||||
// If a rewind was requested, seek to the beginning.
|
||||
if self.rewind {
|
||||
self.rewind = false;
|
||||
match io::retry_on_intr(|| {
|
||||
crate::backend::fs::syscalls::_seek(self.fd.as_fd(), 0, SEEK_SET)
|
||||
}) {
|
||||
Ok(_) => (),
|
||||
Err(err) => return Some(Err(err)),
|
||||
Err(err) => {
|
||||
self.any_errors = true;
|
||||
return Some(Err(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +99,7 @@ impl Dir {
|
||||
if self.buf.len() - self.pos < size_of::<linux_dirent64>() {
|
||||
match self.read_more()? {
|
||||
Ok(()) => (),
|
||||
Err(e) => return Some(Err(e)),
|
||||
Err(err) => return Some(Err(err)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,14 +158,31 @@ impl Dir {
|
||||
}
|
||||
|
||||
fn read_more(&mut self) -> Option<io::Result<()>> {
|
||||
let og_len = self.buf.len();
|
||||
// Capacity increment currently chosen by wild guess.
|
||||
self.buf
|
||||
.resize(self.buf.capacity() + 32 * size_of::<linux_dirent64>(), 0);
|
||||
let nread = match crate::backend::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf) {
|
||||
// The first few times we're called, we allocate a relatively small
|
||||
// buffer, because many directories are small. If we're called more,
|
||||
// use progressively larger allocations, up to a fixed maximum.
|
||||
//
|
||||
// The specific sizes and policy here have not been tuned in detail yet
|
||||
// and may need to be adjusted. In doing so, we should be careful to
|
||||
// avoid unbounded buffer growth. This buffer only exists to share the
|
||||
// cost of a `getdents` call over many entries, so if it gets too big,
|
||||
// cache and heap usage will outweigh the benefit. And ultimately,
|
||||
// directories can contain more entries than we can allocate contiguous
|
||||
// memory for, so we'll always need to cap the size at some point.
|
||||
if self.buf.len() < 1024 * size_of::<linux_dirent64>() {
|
||||
self.buf.reserve(32 * size_of::<linux_dirent64>());
|
||||
}
|
||||
self.buf.resize(self.buf.capacity(), 0);
|
||||
let nread = match io::retry_on_intr(|| {
|
||||
crate::backend::fs::syscalls::getdents(self.fd.as_fd(), &mut self.buf)
|
||||
}) {
|
||||
Ok(nread) => nread,
|
||||
Err(io::Errno::NOENT) => {
|
||||
self.any_errors = true;
|
||||
return None;
|
||||
}
|
||||
Err(err) => {
|
||||
self.buf.resize(og_len, 0);
|
||||
self.any_errors = true;
|
||||
return Some(Err(err));
|
||||
}
|
||||
};
|
||||
@@ -223,3 +262,33 @@ impl DirEntry {
|
||||
self.d_ino
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dir_iterator_handles_io_errors() {
|
||||
// create a dir, keep the FD, then delete the dir
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let fd = crate::fs::openat(
|
||||
crate::fs::cwd(),
|
||||
tmp.path(),
|
||||
crate::fs::OFlags::RDONLY | crate::fs::OFlags::CLOEXEC,
|
||||
crate::fs::Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let file_fd = crate::fs::openat(
|
||||
&fd,
|
||||
tmp.path().join("test.txt"),
|
||||
crate::fs::OFlags::WRONLY | crate::fs::OFlags::CREATE,
|
||||
crate::fs::Mode::RWXU,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut dir = Dir::read_from(&fd).unwrap();
|
||||
|
||||
// Reach inside the `Dir` and replace its directory with a file, which
|
||||
// will cause the subsequent `getdents64` to fail.
|
||||
crate::io::dup2(&file_fd, &mut dir.fd).unwrap();
|
||||
|
||||
assert!(matches!(dir.next(), Some(Err(_))));
|
||||
assert!(matches!(dir.next(), None));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
//! such as which pointers are array slices, out parameters, or in-out
|
||||
//! parameters, which integers are owned or borrowed file descriptors, etc.
|
||||
|
||||
// Weak symbols used by the use-libc-auxv feature for glibc 2.15 support.
|
||||
#[cfg(feature = "use-libc-auxv")]
|
||||
#[macro_use]
|
||||
mod weak;
|
||||
|
||||
#[macro_use]
|
||||
mod arch;
|
||||
mod conv;
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
//! This uses raw pointers to locate and read the kernel-provided auxv array.
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
#[cfg(any(feature = "param", feature = "runtime"))]
|
||||
use super::super::c;
|
||||
use super::super::elf::*;
|
||||
#[cfg(feature = "param")]
|
||||
use crate::ffi::CStr;
|
||||
#[cfg(feature = "runtime")]
|
||||
use core::slice;
|
||||
|
||||
// `getauxval` wasn't supported in glibc until 2.16.
|
||||
weak!(fn getauxval(libc::c_ulong) -> *mut libc::c_void);
|
||||
|
||||
#[cfg(feature = "param")]
|
||||
#[inline]
|
||||
pub(crate) fn page_size() -> usize {
|
||||
@@ -22,35 +23,39 @@ pub(crate) fn page_size() -> usize {
|
||||
#[cfg(feature = "param")]
|
||||
#[inline]
|
||||
pub(crate) fn clock_ticks_per_second() -> u64 {
|
||||
unsafe { libc::getauxval(libc::AT_CLKTCK) as u64 }
|
||||
unsafe { libc::sysconf(libc::_SC_CLK_TCK) as u64 }
|
||||
}
|
||||
|
||||
#[cfg(feature = "param")]
|
||||
#[inline]
|
||||
pub(crate) fn linux_hwcap() -> (usize, usize) {
|
||||
unsafe {
|
||||
(
|
||||
libc::getauxval(libc::AT_HWCAP) as usize,
|
||||
libc::getauxval(libc::AT_HWCAP2) as usize,
|
||||
)
|
||||
if let Some(libc_getauxval) = getauxval.get() {
|
||||
unsafe {
|
||||
let hwcap = libc_getauxval(libc::AT_HWCAP) as usize;
|
||||
let hwcap2 = libc_getauxval(libc::AT_HWCAP2) as usize;
|
||||
(hwcap, hwcap2)
|
||||
}
|
||||
} else {
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "param")]
|
||||
#[inline]
|
||||
pub(crate) fn linux_execfn() -> &'static CStr {
|
||||
unsafe {
|
||||
let execfn = libc::getauxval(libc::AT_EXECFN) as *const c::c_char;
|
||||
CStr::from_ptr(execfn.cast())
|
||||
if let Some(libc_getauxval) = getauxval.get() {
|
||||
unsafe { CStr::from_ptr(libc_getauxval(libc::AT_EXECFN).cast()) }
|
||||
} else {
|
||||
cstr!("")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime")]
|
||||
#[inline]
|
||||
pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) {
|
||||
pub(crate) fn exe_phdrs() -> (*const libc::c_void, usize) {
|
||||
unsafe {
|
||||
(
|
||||
libc::getauxval(libc::AT_PHDR) as *const c::c_void,
|
||||
libc::getauxval(libc::AT_PHDR) as *const libc::c_void,
|
||||
libc::getauxval(libc::AT_PHNUM) as usize,
|
||||
)
|
||||
}
|
||||
@@ -70,5 +75,9 @@ pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] {
|
||||
/// so if we don't see it, this function returns a null pointer.
|
||||
#[inline]
|
||||
pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
|
||||
unsafe { libc::getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr }
|
||||
if let Some(libc_getauxval) = getauxval.get() {
|
||||
unsafe { libc_getauxval(linux_raw_sys::general::AT_SYSINFO_EHDR.into()) as *const Elf_Ehdr }
|
||||
} else {
|
||||
core::ptr::null()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
// Implementation derived from `weak` in Rust's
|
||||
// library/std/src/sys/unix/weak.rs at revision
|
||||
// fd0cb0cdc21dd9c06025277d772108f8d42cb25f.
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
//! Support for "weak linkage" to symbols on Unix
|
||||
//!
|
||||
//! Some I/O operations we do in libstd require newer versions of OSes but we
|
||||
//! need to maintain binary compatibility with older releases for now. In order
|
||||
//! to use the new functionality when available we use this module for
|
||||
//! detection.
|
||||
//!
|
||||
//! One option to use here is weak linkage, but that is unfortunately only
|
||||
//! really workable on Linux. Hence, use dlsym to get the symbol value at
|
||||
//! runtime. This is also done for compatibility with older versions of glibc,
|
||||
//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes
|
||||
//! that we've been dynamically linked to the library the symbol comes from,
|
||||
//! but that is currently always the case for things like libpthread/libc.
|
||||
//!
|
||||
//! A long time ago this used weak linkage for the `__pthread_get_minstack`
|
||||
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
|
||||
//! dependency on libc6 (#23628).
|
||||
|
||||
// There are a variety of `#[cfg]`s controlling which targets are involved in
|
||||
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
|
||||
// that, we'll just allow that some unix targets don't use this module at all.
|
||||
#![allow(dead_code, unused_macros)]
|
||||
#![allow(clippy::doc_markdown)]
|
||||
|
||||
use crate::ffi::CStr;
|
||||
use core::ffi::c_void;
|
||||
use core::ptr::null_mut;
|
||||
use core::sync::atomic::{self, AtomicPtr, Ordering};
|
||||
use core::{marker, mem};
|
||||
|
||||
const NULL: *mut c_void = null_mut();
|
||||
const INVALID: *mut c_void = 1 as *mut c_void;
|
||||
|
||||
macro_rules! weak {
|
||||
($vis:vis fn $name:ident($($t:ty),*) -> $ret:ty) => (
|
||||
#[allow(non_upper_case_globals)]
|
||||
$vis static $name: $crate::backend::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
|
||||
$crate::backend::weak::Weak::new(concat!(stringify!($name), '\0'));
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) struct Weak<F> {
|
||||
name: &'static str,
|
||||
addr: AtomicPtr<c_void>,
|
||||
_marker: marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<F> Weak<F> {
|
||||
pub(crate) const fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
addr: AtomicPtr::new(INVALID),
|
||||
_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self) -> Option<F> {
|
||||
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
|
||||
unsafe {
|
||||
// Relaxed is fine here because we fence before reading through the
|
||||
// pointer (see the comment below).
|
||||
match self.addr.load(Ordering::Relaxed) {
|
||||
INVALID => self.initialize(),
|
||||
NULL => None,
|
||||
addr => {
|
||||
let func = mem::transmute_copy::<*mut c_void, F>(&addr);
|
||||
// The caller is presumably going to read through this value
|
||||
// (by calling the function we've dlsymed). This means we'd
|
||||
// need to have loaded it with at least C11's consume
|
||||
// ordering in order to be guaranteed that the data we read
|
||||
// from the pointer isn't from before the pointer was
|
||||
// stored. Rust has no equivalent to memory_order_consume,
|
||||
// so we use an acquire fence (sorry, ARM).
|
||||
//
|
||||
// Now, in practice this likely isn't needed even on CPUs
|
||||
// where relaxed and consume mean different things. The
|
||||
// symbols we're loading are probably present (or not) at
|
||||
// init, and even if they aren't the runtime dynamic loader
|
||||
// is extremely likely have sufficient barriers internally
|
||||
// (possibly implicitly, for example the ones provided by
|
||||
// invoking `mprotect`).
|
||||
//
|
||||
// That said, none of that's *guaranteed*, and so we fence.
|
||||
atomic::fence(Ordering::Acquire);
|
||||
Some(func)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cold because it should only happen during first-time initialization.
|
||||
#[cold]
|
||||
unsafe fn initialize(&self) -> Option<F> {
|
||||
let val = fetch(self.name);
|
||||
// This synchronizes with the acquire fence in `get`.
|
||||
self.addr.store(val, Ordering::Release);
|
||||
|
||||
match val {
|
||||
NULL => None,
|
||||
addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn fetch(name: &str) -> *mut c_void {
|
||||
let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
|
||||
Ok(c_str) => c_str,
|
||||
Err(..) => return null_mut(),
|
||||
};
|
||||
libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr().cast())
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
macro_rules! syscall {
|
||||
(fn $name:ident($($arg_name:ident: $t:ty),*) via $_sys_name:ident -> $ret:ty) => (
|
||||
unsafe fn $name($($arg_name: $t),*) -> $ret {
|
||||
weak! { fn $name($($t),*) -> $ret }
|
||||
|
||||
if let Some(fun) = $name.get() {
|
||||
fun($($arg_name),*)
|
||||
} else {
|
||||
libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS));
|
||||
-1
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
macro_rules! syscall {
|
||||
(fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => (
|
||||
unsafe fn $name($($arg_name:$t),*) -> $ret {
|
||||
// This looks like a hack, but concat_idents only accepts idents
|
||||
// (not paths).
|
||||
use libc::*;
|
||||
|
||||
trait AsSyscallArg {
|
||||
type SyscallArgType;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType;
|
||||
}
|
||||
|
||||
// Pass pointer types as pointers, to preserve provenance.
|
||||
impl<T> AsSyscallArg for *mut T {
|
||||
type SyscallArgType = *mut T;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType { self }
|
||||
}
|
||||
impl<T> AsSyscallArg for *const T {
|
||||
type SyscallArgType = *const T;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType { self }
|
||||
}
|
||||
|
||||
// Pass `BorrowedFd` values as the integer value.
|
||||
impl AsSyscallArg for $crate::fd::BorrowedFd<'_> {
|
||||
type SyscallArgType = c::c_long;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType {
|
||||
$crate::fd::AsRawFd::as_raw_fd(&self) as _
|
||||
}
|
||||
}
|
||||
|
||||
// Coerce integer values into `c_long`.
|
||||
impl AsSyscallArg for i32 {
|
||||
type SyscallArgType = c::c_long;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ }
|
||||
}
|
||||
impl AsSyscallArg for u32 {
|
||||
type SyscallArgType = c::c_long;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ }
|
||||
}
|
||||
impl AsSyscallArg for usize {
|
||||
type SyscallArgType = c::c_long;
|
||||
fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ }
|
||||
}
|
||||
|
||||
// `concat_idents is unstable, so we take an extra `sys_name`
|
||||
// parameter and have our users do the concat for us for now.
|
||||
/*
|
||||
syscall(
|
||||
concat_idents!(SYS_, $name),
|
||||
$($arg_name.into_syscall_arg()),*
|
||||
) as $ret
|
||||
*/
|
||||
|
||||
syscall($sys_name, $($arg_name.into_syscall_arg()),*) as $ret
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! weakcall {
|
||||
($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
|
||||
$vis unsafe fn $name($($arg_name: $t),*) -> $ret {
|
||||
weak! { fn $name($($t),*) -> $ret }
|
||||
|
||||
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
|
||||
// interposition, but if it's not found just fail.
|
||||
if let Some(fun) = $name.get() {
|
||||
fun($($arg_name),*)
|
||||
} else {
|
||||
libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS));
|
||||
-1
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/// A combination of `weakcall` and `syscall`. Use the libc function if it's
|
||||
/// available, and fall back to `libc::syscall` otherwise.
|
||||
macro_rules! weak_or_syscall {
|
||||
($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => (
|
||||
$vis unsafe fn $name($($arg_name: $t),*) -> $ret {
|
||||
weak! { fn $name($($t),*) -> $ret }
|
||||
|
||||
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
|
||||
// interposition, but if it's not found just fail.
|
||||
if let Some(fun) = $name.get() {
|
||||
fun($($arg_name),*)
|
||||
} else {
|
||||
syscall! { fn $name($($arg_name: $t),*) via $sys_name -> $ret }
|
||||
$name($($arg_name),*)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
+1
-4
@@ -3,7 +3,7 @@
|
||||
use crate::backend;
|
||||
|
||||
pub use crate::io::FdFlags;
|
||||
pub use backend::fs::types::{Access, Mode, OFlags};
|
||||
pub use backend::fs::types::{Access, Dev, Mode, OFlags};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub use backend::fs::types::AtFlags;
|
||||
@@ -14,7 +14,4 @@ pub use backend::fs::types::{CloneFlags, CopyfileFlags};
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
pub use backend::fs::types::{MountFlags, MountPropagationFlags, RenameFlags, ResolveFlags};
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
pub use backend::fs::types::Dev;
|
||||
|
||||
pub use backend::time::types::{Nsecs, Secs, Timespec};
|
||||
|
||||
+1
-1
@@ -217,5 +217,5 @@ pub use statx::{statx, Statx, StatxFlags, StatxTimestamp};
|
||||
#[cfg(unix)]
|
||||
pub use std::os::unix::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt};
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(target_os = "wasi")]
|
||||
#[cfg(all(wasi_ext, target_os = "wasi"))]
|
||||
pub use std::os::wasi::fs::{DirEntryExt, FileExt, FileTypeExt, MetadataExt, OpenOptionsExt};
|
||||
|
||||
+2
-2
@@ -195,8 +195,8 @@ impl<'buf, Fd: AsFd> RawDir<'buf, Fd> {
|
||||
|
||||
Some(Ok(RawDirEntry {
|
||||
file_type: dirent.d_type,
|
||||
inode_number: dirent.d_ino,
|
||||
next_entry_cookie: dirent.d_off,
|
||||
inode_number: dirent.d_ino.into(),
|
||||
next_entry_cookie: dirent.d_off.into(),
|
||||
// SAFETY: the kernel guarantees a NUL terminated string.
|
||||
file_name: unsafe { CStr::from_ptr(dirent.d_name.as_ptr().cast()) },
|
||||
}))
|
||||
|
||||
@@ -11,7 +11,6 @@ pub use backend::io::io_slice::{IoSlice, IoSliceMut};
|
||||
#[cfg(feature = "std")]
|
||||
pub use std::io::{IoSlice, IoSliceMut};
|
||||
|
||||
/// `RWF_*` constants for use with [`preadv2`] and [`pwritev2`].
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
pub use backend::io::types::ReadWriteFlags;
|
||||
|
||||
|
||||
+4
-1
@@ -98,7 +98,7 @@
|
||||
#![cfg_attr(linux_raw, deny(unsafe_code))]
|
||||
#![cfg_attr(rustc_attrs, feature(rustc_attrs))]
|
||||
#![cfg_attr(doc_cfg, feature(doc_cfg))]
|
||||
#![cfg_attr(all(target_os = "wasi", feature = "std"), feature(wasi_ext))]
|
||||
#![cfg_attr(all(wasi_ext, target_os = "wasi", feature = "std"), feature(wasi_ext))]
|
||||
#![cfg_attr(
|
||||
all(linux_raw, naked_functions, target_arch = "x86"),
|
||||
feature(naked_functions)
|
||||
@@ -123,6 +123,9 @@
|
||||
#![allow(clippy::unnecessary_cast)]
|
||||
// It is common in linux and libc APIs for types to vary between platforms.
|
||||
#![allow(clippy::useless_conversion)]
|
||||
// Redox and WASI have enough differences that it isn't worth
|
||||
// precisely conditionallizing all the `use`s for them.
|
||||
#![cfg_attr(any(target_os = "redox", target_os = "wasi"), allow(unused_imports))]
|
||||
|
||||
#[cfg(not(feature = "rustc-dep-of-std"))]
|
||||
extern crate alloc;
|
||||
|
||||
+17
-1
@@ -2,6 +2,13 @@ use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn test_backends() {
|
||||
// Test whether `has_dependency` works. `cargo tree` no longer works in
|
||||
// Rust 1.48 because `cargo tree` pulls in dependencies for all targets,
|
||||
// and hermit-core isn't compatible with Rust 1.48.
|
||||
if !has_dependency(".", &[], &[], &[], "io-lifetimes") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pick an arbitrary platform where linux_raw is enabled by default and
|
||||
// ensure that the use-default crate uses it.
|
||||
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
||||
@@ -51,9 +58,18 @@ fn test_backends() {
|
||||
|
||||
#[cfg(windows)]
|
||||
let libc_dep = "windows-sys";
|
||||
#[cfg(unix)]
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
let libc_dep = "libc";
|
||||
|
||||
// FIXME: Temporarily disable the subsequent tests on Windows until
|
||||
// rust-errno updates to windows-sys 0.48.
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if true {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Test the use-libc crate, which enables the "use-libc" cargo feature.
|
||||
assert!(
|
||||
has_dependency("test-crates/use-libc", &[], &[], &["RUSTFLAGS"], libc_dep),
|
||||
|
||||
+93
-1
@@ -8,7 +8,7 @@ fn test_dir() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let dir = rustix::fs::Dir::read_from(&t).unwrap();
|
||||
let mut dir = rustix::fs::Dir::read_from(&t).unwrap();
|
||||
|
||||
let _file = rustix::fs::openat(
|
||||
&t,
|
||||
@@ -18,6 +18,32 @@ fn test_dir() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Read the directory entries. We use `while let Some(entry)` so that we
|
||||
// don't consume the `Dir` so that we can run more tests on it.
|
||||
let mut saw_dot = false;
|
||||
let mut saw_dotdot = false;
|
||||
let mut saw_cargo_toml = false;
|
||||
while let Some(entry) = dir.read() {
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_name() == rustix::cstr!(".") {
|
||||
saw_dot = true;
|
||||
} else if entry.file_name() == rustix::cstr!("..") {
|
||||
saw_dotdot = true;
|
||||
} else if entry.file_name() == rustix::cstr!("Cargo.toml") {
|
||||
saw_cargo_toml = true;
|
||||
}
|
||||
}
|
||||
assert!(saw_dot);
|
||||
assert!(saw_dotdot);
|
||||
assert!(saw_cargo_toml);
|
||||
|
||||
// Rewind the directory so we can iterate over the entries again.
|
||||
dir.rewind();
|
||||
|
||||
// For what comes next, we don't need `mut` anymore.
|
||||
let dir = dir;
|
||||
|
||||
// Read the directory entries, again. This time we use `for entry in dir`.
|
||||
let mut saw_dot = false;
|
||||
let mut saw_dotdot = false;
|
||||
let mut saw_cargo_toml = false;
|
||||
@@ -35,3 +61,69 @@ fn test_dir() {
|
||||
assert!(saw_dotdot);
|
||||
assert!(saw_cargo_toml);
|
||||
}
|
||||
|
||||
// Test that `Dir` silently stops iterating if the directory has been removed.
|
||||
//
|
||||
// Except on FreeBSD and macOS, where apparently `readdir` just keeps reading.
|
||||
#[cfg_attr(
|
||||
any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "watchos",
|
||||
target_os = "tvos",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonflybsd"
|
||||
),
|
||||
ignore
|
||||
)]
|
||||
#[test]
|
||||
fn dir_iterator_handles_dir_removal() {
|
||||
// create a dir, keep the FD, then delete the dir
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let fd = rustix::fs::openat(
|
||||
rustix::fs::cwd(),
|
||||
tmp.path(),
|
||||
rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
|
||||
rustix::fs::Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Drop the `TempDir`, which deletes the directory.
|
||||
drop(tmp);
|
||||
|
||||
let mut dir = rustix::fs::Dir::read_from(&fd).unwrap();
|
||||
assert!(matches!(dir.next(), None));
|
||||
}
|
||||
|
||||
// Like `dir_iterator_handles_dir_removal`, but close the directory after
|
||||
// `Dir::read_from`.
|
||||
#[cfg_attr(
|
||||
any(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "watchos",
|
||||
target_os = "tvos",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonflybsd"
|
||||
),
|
||||
ignore
|
||||
)]
|
||||
#[test]
|
||||
fn dir_iterator_handles_dir_removal_after_open() {
|
||||
// create a dir, keep the FD, then delete the dir
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let fd = rustix::fs::openat(
|
||||
rustix::fs::cwd(),
|
||||
tmp.path(),
|
||||
rustix::fs::OFlags::RDONLY | rustix::fs::OFlags::CLOEXEC,
|
||||
rustix::fs::Mode::empty(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut dir = rustix::fs::Dir::read_from(&fd).unwrap();
|
||||
|
||||
// Drop the `TempDir`, which deletes the directory.
|
||||
drop(tmp);
|
||||
|
||||
assert!(matches!(dir.next(), None));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use libc::{kill, SIGSTOP};
|
||||
use rustix::process;
|
||||
use serial_test::serial;
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
// These tests must execute serially to prevent race condition, where
|
||||
@@ -8,7 +7,7 @@ use std::process::{Command, Stdio};
|
||||
// the tests to get stuck.
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[ignore]
|
||||
fn test_waitpid() {
|
||||
let child = Command::new("yes")
|
||||
.stdout(Stdio::null())
|
||||
|
||||
@@ -4,7 +4,11 @@ use std::fs::File;
|
||||
|
||||
#[test]
|
||||
fn test_ttyname_ok() {
|
||||
let file = File::open("/dev/stdin").unwrap();
|
||||
let file = match File::open("/dev/stdin") {
|
||||
Ok(file) => file,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => return,
|
||||
Err(err) => Err(err).unwrap(),
|
||||
};
|
||||
if isatty(&file) {
|
||||
assert!(ttyname(&file, Vec::new())
|
||||
.unwrap()
|
||||
|
||||
Reference in New Issue
Block a user