From 47490b4383bf48cbde8b1c33301a7f7d326ee7cc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 17 Sep 2021 15:28:56 -0700 Subject: [PATCH] Use rsix to make system calls in Wasmtime. (#3355) * Use rsix to make system calls in Wasmtime. `rsix` is a system call wrapper crate that we use in `wasi-common`, which can provide the following advantages in the rest of Wasmtime: - It eliminates some `unsafe` blocks in Wasmtime's code. There's still an `unsafe` block in the library, but this way, the `unsafe` is factored out and clearly scoped. - And, it makes error handling more consistent, factoring out code for checking return values and `io::Error::last_os_error()`, and code that does `errno::set_errno(0)`. This doesn't cover *all* system calls; `rsix` doesn't implement signal-handling APIs, and this doesn't cover calls made through `std` or crates like `userfaultfd`, `rand`, and `region`. --- .github/workflows/main.yml | 1 + Cargo.lock | 55 ++++++++--------- Cargo.toml | 3 + cranelift/native/Cargo.toml | 2 +- cranelift/native/src/lib.rs | 6 +- crates/bench-api/Cargo.toml | 2 +- crates/c-api/Cargo.toml | 2 +- crates/cache/Cargo.toml | 3 +- crates/cache/src/worker.rs | 22 +++---- crates/fiber/Cargo.toml | 2 +- crates/fiber/src/unix.rs | 44 ++++++-------- crates/jit/Cargo.toml | 6 +- crates/jit/src/profiling/jitdump_linux.rs | 35 ++++------- crates/runtime/Cargo.toml | 3 + .../src/instance/allocator/pooling/linux.rs | 10 +--- .../src/instance/allocator/pooling/uffd.rs | 8 +-- .../src/instance/allocator/pooling/unix.rs | 23 +++---- crates/runtime/src/mmap.rs | 60 +++++++------------ crates/runtime/src/traphandlers/unix.rs | 36 ++++------- crates/test-programs/Cargo.toml | 2 +- crates/wasi-common/Cargo.toml | 8 +-- crates/wasi-common/cap-std-sync/Cargo.toml | 14 ++--- crates/wasi-common/tokio/Cargo.toml | 14 ++--- tests/all/custom_signal_handler.rs | 24 ++++---- tests/all/memory_creator.rs | 23 +++---- 25 files changed, 174 insertions(+), 234 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3faf1079b3..bf9e849931 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -163,6 +163,7 @@ jobs: - run: | rustup target add wasm32-unknown-emscripten rustup target add armv7-unknown-linux-gnueabihf + sudo apt-get install -y gcc-arm-linux-gnueabihf - run: cargo check --target wasm32-unknown-emscripten -p wasi-common - run: cargo check --target armv7-unknown-linux-gnueabihf -p wasi-common diff --git a/Cargo.lock b/Cargo.lock index 305f426fcd..5e791a4ced 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,9 +287,9 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" [[package]] name = "cap-fs-ext" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e78f3c966b077a24e7bab715b983989b775f6e4fc925555b4cc64ede44022e" +checksum = "1bf5c3b436b94a1adac74032ff35d8aa5bae6ec2a7900e76432c9ae8dac4d673" dependencies = [ "cap-primitives", "cap-std", @@ -300,9 +300,9 @@ dependencies = [ [[package]] name = "cap-primitives" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdbdb79473b78acebdef84f853914cbda08f29d4fc80d8f647f68372e3b6bb" +checksum = "b51bd736eec54ae6552d18b0c958885b01d88c84c5fe6985e28c2b57ff385e94" dependencies = [ "ambient-authority", "errno", @@ -321,9 +321,9 @@ dependencies = [ [[package]] name = "cap-rand" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce38e251919457b5e2808d53d8982a6a267898907a57c4fd909305c93300efd2" +checksum = "6e6e89d00b0cebeb6da7a459b81e6a49cf2092cc4afe03f28eb99b8f0e889344" dependencies = [ "ambient-authority", "rand 0.8.3", @@ -331,9 +331,9 @@ dependencies = [ [[package]] name = "cap-std" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f659706c014c6cfdbf1e13903699bc1c2d8bb84c1a0e1ae9b4cb333e8c6f3de" +checksum = "037334fe2f30ec71bcc51af1e8cbb8a9f9ac6a6b8cbd657d58dfef2ad5b9f19a" dependencies = [ "cap-primitives", "io-lifetimes", @@ -345,9 +345,9 @@ dependencies = [ [[package]] name = "cap-tempfile" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3ec13e2e4ebce1d22ccb4553264fdb5c170d2070839d17540ddf17c05642d96" +checksum = "5160158dd17a01cfaf359e27a17fb6cc37c083347ed8c6e10583e08055d12c94" dependencies = [ "cap-std", "rand 0.8.3", @@ -356,9 +356,9 @@ dependencies = [ [[package]] name = "cap-time-ext" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d636df2f22174ea46acd0ca12b6f884139f82afbf10d9e91bdab694f988213" +checksum = "aea5319ada3a9517fc70eafe9cf3275f04da795c53770ebc5d91f4a33f4dd2b5" dependencies = [ "cap-primitives", "once_cell", @@ -708,7 +708,7 @@ name = "cranelift-native" version = "0.77.0" dependencies = [ "cranelift-codegen", - "libc", + "rsix", "target-lexicon", ] @@ -1265,9 +1265,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fs-set-times" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05f9ac4aceff7d9f3cd1701217aa72f87a0bf7c6592886efe819727292a4c7f" +checksum = "807e3ef0de04fbe498bebd560ae041e006d97bf9f726dc0b485a86316be0ebc8" dependencies = [ "io-lifetimes", "rsix", @@ -1480,9 +1480,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94e87a80ab2e1aad23d4b8c4feb954125ac4da906891e041d93f5861a5fdd78" +checksum = "47f5ce4afb9bf504b9f496a3307676bc232122f91a93c4da6d540aa99a0a0e0b" dependencies = [ "rustc_version", "winapi", @@ -1648,9 +1648,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.0.23" +version = "0.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5802c30e8a573a9af97d504e9e66a076e0b881112222a67a8e037a79658447d6" +checksum = "13d803e4a041d0deed25db109ac7ba704d1edd62588b623feb8beed5da78e579" [[package]] name = "lock_api" @@ -2603,9 +2603,9 @@ dependencies = [ [[package]] name = "rsix" -version = "0.22.4" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19dc84e006a7522c44207fcd9c1f504f7c9a503093070840105930a685e299a0" +checksum = "bcb64fd899aa29c8f920e52732489630b55dba438039eee73ee068e995f64ef2" dependencies = [ "bitflags", "cc", @@ -2934,9 +2934,9 @@ dependencies = [ [[package]] name = "system-interface" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687be991be7468d6042aeecaedea242221afadbec8d0cb86f5a0df1a4206dc7" +checksum = "6cb3a23bf923c3fdaf0c36a8c016047e415f0559a5b891de7ec3d19d58b9b503" dependencies = [ "atty", "bitflags", @@ -3628,14 +3628,13 @@ dependencies = [ "base64", "bincode", "directories-next", - "errno", "file-per-thread-logger", "filetime", "lazy_static", - "libc", "log", "more-asserts", "pretty_env_logger", + "rsix", "serde", "sha2", "tempfile", @@ -3663,6 +3662,7 @@ dependencies = [ "object", "pretty_env_logger", "rayon", + "rsix", "structopt", "target-lexicon", "tempfile", @@ -3730,7 +3730,7 @@ version = "0.30.0" dependencies = [ "backtrace", "cc", - "libc", + "rsix", "winapi", ] @@ -3783,11 +3783,11 @@ dependencies = [ "cfg-if 1.0.0", "gimli", "ittapi-rs", - "libc", "log", "more-asserts", "object", "region", + "rsix", "serde", "target-lexicon", "thiserror", @@ -3828,6 +3828,7 @@ dependencies = [ "more-asserts", "rand 0.8.3", "region", + "rsix", "thiserror", "userfaultfd", "wasmtime-environ", diff --git a/Cargo.toml b/Cargo.toml index d369645021..bb7806a973 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,9 @@ humantime = "2.0.0" wasmparser = "0.80.0" lazy_static = "1.4.0" +[target.'cfg(unix)'.dependencies] +rsix = "0.23.0" + [dev-dependencies] env_logger = "0.8.1" filecheck = "0.5.0" diff --git a/cranelift/native/Cargo.toml b/cranelift/native/Cargo.toml index 493778a463..96fe91f665 100644 --- a/cranelift/native/Cargo.toml +++ b/cranelift/native/Cargo.toml @@ -15,7 +15,7 @@ cranelift-codegen = { path = "../codegen", version = "0.77.0", default-features target-lexicon = "0.12" [target.'cfg(target_arch = "s390x")'.dependencies] -libc = "0.2.95" +rsix = "0.23.0" [features] default = ["std"] diff --git a/cranelift/native/src/lib.rs b/cranelift/native/src/lib.rs index cac50dee4e..b2364c6ad9 100644 --- a/cranelift/native/src/lib.rs +++ b/cranelift/native/src/lib.rs @@ -126,7 +126,7 @@ pub fn builder_with_options( } // There is no is_s390x_feature_detected macro yet, so for now - // we use getauxval from the libc crate directly. + // we use linux_hwcap from the rsix crate directly. #[cfg(all(target_arch = "s390x", target_os = "linux"))] { use cranelift_codegen::settings::Configurable; @@ -135,8 +135,8 @@ pub fn builder_with_options( return Ok(isa_builder); } - let v = unsafe { libc::getauxval(libc::AT_HWCAP) }; - const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768; + let v = rsix::process::linux_hwcap().0; + const HWCAP_S390X_VXRS_EXT2: usize = 32768; if (v & HWCAP_S390X_VXRS_EXT2) != 0 { isa_builder.enable("has_vxrs_ext2").unwrap(); // There is no separate HWCAP bit for mie2, so assume diff --git a/crates/bench-api/Cargo.toml b/crates/bench-api/Cargo.toml index ac12b5558a..a67b48c501 100644 --- a/crates/bench-api/Cargo.toml +++ b/crates/bench-api/Cargo.toml @@ -22,7 +22,7 @@ wasmtime-wasi = { path = "../wasi" } wasmtime-wasi-crypto = { path = "../wasi-crypto", optional = true } wasmtime-wasi-nn = { path = "../wasi-nn", optional = true } wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync" } -cap-std = "0.19.0" +cap-std = "0.19.1" [dev-dependencies] wat = "1.0" diff --git a/crates/c-api/Cargo.toml b/crates/c-api/Cargo.toml index 6ed2d9bdc0..39e99eb183 100644 --- a/crates/c-api/Cargo.toml +++ b/crates/c-api/Cargo.toml @@ -30,7 +30,7 @@ wat = { version = "1.0.36", optional = true } wasi-common = { path = "../wasi-common", optional = true } wasi-cap-std-sync = { path = "../wasi-common/cap-std-sync", optional = true } wasmtime-wasi = { path = "../wasi", optional = true } -cap-std = { version = "0.19.0", optional = true } +cap-std = { version = "0.19.1", optional = true } [features] default = ['jitdump', 'wat', 'wasi', 'cache'] diff --git a/crates/cache/Cargo.toml b/crates/cache/Cargo.toml index 005749170b..c7df172c63 100644 --- a/crates/cache/Cargo.toml +++ b/crates/cache/Cargo.toml @@ -24,8 +24,7 @@ zstd = { version = "0.9", default-features = false } winapi = "0.3.7" [target.'cfg(not(target_os = "windows"))'.dependencies] -errno = "0.2.4" -libc = "0.2.60" +rsix = "0.23.0" [dev-dependencies] filetime = "0.2.7" diff --git a/crates/cache/src/worker.rs b/crates/cache/src/worker.rs index 0a1271998c..e81f3b8c37 100644 --- a/crates/cache/src/worker.rs +++ b/crates/cache/src/worker.rs @@ -256,19 +256,15 @@ impl WorkerThread { const NICE_DELTA_FOR_BACKGROUND_TASKS: i32 = 3; - errno::set_errno(errno::Errno(0)); - let current_nice = unsafe { libc::nice(NICE_DELTA_FOR_BACKGROUND_TASKS) }; - let errno_val = errno::errno().0; - - if errno_val != 0 { - warn!( - "Failed to lower worker thread priority. It might affect application performance. \ - errno: {}", - errno_val - ); - } else { - debug!("New nice value of worker thread: {}", current_nice); - } + match rsix::process::nice(NICE_DELTA_FOR_BACKGROUND_TASKS) { + Ok(current_nice) => { + debug!("New nice value of worker thread: {}", current_nice); + } + Err(err) => { + warn!( + "Failed to lower worker thread priority ({:?}). It might affect application performance.", err); + } + }; } /// Increases the usage counter and recompresses the file diff --git a/crates/fiber/Cargo.toml b/crates/fiber/Cargo.toml index 05f89e3cba..2bb269ec63 100644 --- a/crates/fiber/Cargo.toml +++ b/crates/fiber/Cargo.toml @@ -14,7 +14,7 @@ edition = "2018" links = "wasmtime-fiber-shims" [target.'cfg(unix)'.dependencies] -libc = "0.2.80" +rsix = "0.23.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3.9" diff --git a/crates/fiber/src/unix.rs b/crates/fiber/src/unix.rs index 7061c6c8d2..d8fbff7250 100644 --- a/crates/fiber/src/unix.rs +++ b/crates/fiber/src/unix.rs @@ -45,38 +45,30 @@ pub struct FiberStack { impl FiberStack { pub fn new(size: usize) -> io::Result { - unsafe { - // Round up our stack size request to the nearest multiple of the - // page size. - let page_size = libc::sysconf(libc::_SC_PAGESIZE) as usize; - let size = if size == 0 { - page_size - } else { - (size + (page_size - 1)) & (!(page_size - 1)) - }; + // Round up our stack size request to the nearest multiple of the + // page size. + let page_size = rsix::process::page_size(); + let size = if size == 0 { + page_size + } else { + (size + (page_size - 1)) & (!(page_size - 1)) + }; + unsafe { // Add in one page for a guard page and then ask for some memory. let mmap_len = size + page_size; - let mmap = libc::mmap( + let mmap = rsix::io::mmap_anonymous( ptr::null_mut(), mmap_len, - libc::PROT_NONE, - libc::MAP_ANON | libc::MAP_PRIVATE, - -1, - 0, - ); - if mmap == libc::MAP_FAILED { - return Err(io::Error::last_os_error()); - } + rsix::io::ProtFlags::NONE, + rsix::io::MapFlags::PRIVATE, + )?; - if libc::mprotect( + rsix::io::mprotect( mmap.cast::().add(page_size).cast(), size, - libc::PROT_READ | libc::PROT_WRITE, - ) != 0 - { - return Err(io::Error::last_os_error()); - } + rsix::io::MprotectFlags::READ | rsix::io::MprotectFlags::WRITE, + )?; Ok(Self { top: mmap.cast::().add(mmap_len), @@ -98,8 +90,8 @@ impl Drop for FiberStack { fn drop(&mut self) { unsafe { if let Some(len) = self.len { - let ret = libc::munmap(self.top.sub(len) as _, len); - debug_assert!(ret == 0); + let ret = rsix::io::munmap(self.top.sub(len) as _, len); + debug_assert!(ret.is_ok()); } } } diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 711895dac1..f9d9a4dc08 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -25,15 +25,17 @@ gimli = { version = "0.25.0", default-features = false, features = ["std", "read object = { version = "0.26.0", default-features = false, features = ["std", "read_core", "elf"] } serde = { version = "1.0.94", features = ["derive"] } addr2line = { version = "0.16.0", default-features = false } -libc = { version = "0.2.60", default-features = false, optional = true } ittapi-rs = { version = "0.1.5", optional = true } bincode = "1.2.1" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.8", features = ["winnt", "impl-default"] } +[target.'cfg(target_os = "linux")'.dependencies] +rsix = { version = "0.23.0", optional = true } + [features] -jitdump = ['libc'] +jitdump = ['rsix'] vtune = ['ittapi-rs'] [badges] diff --git a/crates/jit/src/profiling/jitdump_linux.rs b/crates/jit/src/profiling/jitdump_linux.rs index b794e29d9c..9680ce8984 100644 --- a/crates/jit/src/profiling/jitdump_linux.rs +++ b/crates/jit/src/profiling/jitdump_linux.rs @@ -16,9 +16,7 @@ use anyhow::Result; use object::{Object, ObjectSection}; use std::fmt::Debug; use std::fs::{File, OpenOptions}; -use std::io; use std::io::Write; -use std::os::unix::prelude::*; use std::ptr; use std::sync::Mutex; use std::{borrow, mem, process}; @@ -177,17 +175,14 @@ impl JitDumpAgent { // To match what some perf examples are doing we keep this `mmap` alive // until this agent goes away. let map_addr = unsafe { - let ptr = libc::mmap( + let ptr = rsix::io::mmap( ptr::null_mut(), - libc::sysconf(libc::_SC_PAGESIZE) as usize, - libc::PROT_EXEC | libc::PROT_READ, - libc::MAP_PRIVATE, - jitdump_file.as_raw_fd(), + rsix::process::page_size(), + rsix::io::ProtFlags::EXEC | rsix::io::ProtFlags::READ, + rsix::io::MapFlags::PRIVATE, + &jitdump_file, 0, - ); - if ptr == libc::MAP_FAILED { - return Err(io::Error::last_os_error().into()); - } + )?; ptr as usize }; let mut state = State { @@ -216,16 +211,9 @@ impl State { // conveniently also uses, but `Instant` doesn't allow us to get access // to nanoseconds as an internal detail, so we calculate the nanoseconds // ourselves here. - unsafe { - let mut ts = mem::MaybeUninit::zeroed(); - assert_eq!( - libc::clock_gettime(libc::CLOCK_MONOTONIC, ts.as_mut_ptr()), - 0 - ); - let ts = ts.assume_init(); - // TODO: What does it mean for either sec or nsec to be negative? - (ts.tv_sec * 1_000_000_000 + ts.tv_nsec) as u64 - } + let ts = rsix::time::clock_gettime(rsix::time::ClockId::Monotonic); + // TODO: What does it mean for either sec or nsec to be negative? + (ts.tv_sec * 1_000_000_000 + ts.tv_nsec) as u64 } /// Returns the ELF machine architecture. @@ -649,10 +637,7 @@ impl State { impl Drop for State { fn drop(&mut self) { unsafe { - libc::munmap( - self.map_addr as *mut _, - libc::sysconf(libc::_SC_PAGESIZE) as usize, - ); + rsix::io::munmap(self.map_addr as *mut _, rsix::process::page_size()).unwrap(); } } } diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 4914ec9c8d..1a0138cc6d 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -29,6 +29,9 @@ anyhow = "1.0.38" [target.'cfg(target_os = "macos")'.dependencies] mach = "0.3.2" +[target.'cfg(unix)'.dependencies] +rsix = "0.23.2" + [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.7", features = ["winbase", "memoryapi", "errhandlingapi", "handleapi"] } diff --git a/crates/runtime/src/instance/allocator/pooling/linux.rs b/crates/runtime/src/instance/allocator/pooling/linux.rs index db8e6ff9bd..1fa47327b4 100644 --- a/crates/runtime/src/instance/allocator/pooling/linux.rs +++ b/crates/runtime/src/instance/allocator/pooling/linux.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> { if len == 0 { @@ -12,12 +12,8 @@ fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> { } // On Linux, this is enough to cause the kernel to initialize the pages to 0 on next access - if libc::madvise(addr as _, len, libc::MADV_DONTNEED) != 0 { - bail!( - "madvise failed to decommit: {}", - std::io::Error::last_os_error() - ); - } + rsix::io::madvise(addr as _, len, rsix::io::Advice::LinuxDontNeed) + .context("madvise failed to decommit: {}")?; } Ok(()) diff --git a/crates/runtime/src/instance/allocator/pooling/uffd.rs b/crates/runtime/src/instance/allocator/pooling/uffd.rs index 71695f1215..e82f932eba 100644 --- a/crates/runtime/src/instance/allocator/pooling/uffd.rs +++ b/crates/runtime/src/instance/allocator/pooling/uffd.rs @@ -33,6 +33,7 @@ use super::{InstancePool, MemoryPool}; use crate::instance::Instance; use anyhow::{bail, Context, Result}; +use rsix::io::{madvise, Advice}; use std::thread; use userfaultfd::{Event, FeatureFlags, IoctlFlags, Uffd, UffdBuilder}; use wasmtime_environ::{DefinedMemoryIndex, EntityRef, MemoryInitialization}; @@ -50,12 +51,7 @@ fn decommit(addr: *mut u8, len: usize) -> Result<()> { // and the user fault handler will receive the event. // If the pages are not monitored by uffd, the kernel will zero the page on next access, // as if it were mmap'd for the first time. - if libc::madvise(addr as _, len, libc::MADV_DONTNEED) != 0 { - bail!( - "madvise failed to decommit: {}", - std::io::Error::last_os_error() - ); - } + madvise(addr as _, len, Advice::LinuxDontNeed).context("madvise failed to decommit")?; } Ok(()) diff --git a/crates/runtime/src/instance/allocator/pooling/unix.rs b/crates/runtime/src/instance/allocator/pooling/unix.rs index 6a18b6b9a0..2fe2321a01 100644 --- a/crates/runtime/src/instance/allocator/pooling/unix.rs +++ b/crates/runtime/src/instance/allocator/pooling/unix.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> { if len == 0 { @@ -9,25 +9,18 @@ fn decommit(addr: *mut u8, len: usize, protect: bool) -> Result<()> { // mapping for the pages in the given range. // The new mapping will be to the CoW zero page, so this effectively // zeroes the pages. - if unsafe { - libc::mmap( + unsafe { + rsix::io::mmap_anonymous( addr as _, len, if protect { - libc::PROT_NONE + rsix::io::ProtFlags::NONE } else { - libc::PROT_READ | libc::PROT_WRITE + rsix::io::ProtFlags::READ | rsix::io::ProtFlags::WRITE }, - libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_FIXED, - -1, - 0, - ) as *mut u8 - } != addr - { - bail!( - "mmap failed to remap pages: {}", - std::io::Error::last_os_error() - ); + rsix::io::MapFlags::PRIVATE | rsix::io::MapFlags::FIXED, + ) + .context("mmap failed to remap pages: {}")?; } Ok(()) diff --git a/crates/runtime/src/mmap.rs b/crates/runtime/src/mmap.rs index cd9a6640c1..ad26ebd3c9 100644 --- a/crates/runtime/src/mmap.rs +++ b/crates/runtime/src/mmap.rs @@ -2,11 +2,10 @@ //! of memory. use anyhow::anyhow; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use more_asserts::assert_le; use std::convert::TryFrom; use std::fs::File; -use std::io; use std::ops::Range; use std::path::Path; use std::ptr; @@ -57,8 +56,6 @@ impl Mmap { pub fn from_file(path: &Path) -> Result { #[cfg(unix)] { - use std::os::unix::prelude::*; - let file = File::open(path).context("failed to open file")?; let len = file .metadata() @@ -66,19 +63,16 @@ impl Mmap { .len(); let len = usize::try_from(len).map_err(|_| anyhow!("file too large to map"))?; let ptr = unsafe { - libc::mmap( + rsix::io::mmap( ptr::null_mut(), len, - libc::PROT_READ, - libc::MAP_PRIVATE, - file.as_raw_fd(), + rsix::io::ProtFlags::READ, + rsix::io::MapFlags::PRIVATE, + &file, 0, ) + .context(format!("mmap failed to allocate {:#x} bytes", len))? }; - if ptr as isize == -1_isize { - return Err(io::Error::last_os_error()) - .context(format!("mmap failed to allocate {:#x} bytes", len)); - } Ok(Self { ptr: ptr as usize, @@ -90,6 +84,7 @@ impl Mmap { #[cfg(windows)] { use std::fs::OpenOptions; + use std::io; use std::os::windows::prelude::*; use winapi::um::handleapi::*; use winapi::um::memoryapi::*; @@ -175,22 +170,14 @@ impl Mmap { Ok(if accessible_size == mapping_size { // Allocate a single read-write region at once. let ptr = unsafe { - libc::mmap( + rsix::io::mmap_anonymous( ptr::null_mut(), mapping_size, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_PRIVATE | libc::MAP_ANON, - -1, - 0, + rsix::io::ProtFlags::READ | rsix::io::ProtFlags::WRITE, + rsix::io::MapFlags::PRIVATE, ) + .context(format!("mmap failed to allocate {:#x} bytes", mapping_size))? }; - if ptr as isize == -1_isize { - bail!( - "mmap failed to allocate {:#x} bytes: {}", - mapping_size, - io::Error::last_os_error() - ); - } Self { ptr: ptr as usize, @@ -200,22 +187,14 @@ impl Mmap { } else { // Reserve the mapping size. let ptr = unsafe { - libc::mmap( + rsix::io::mmap_anonymous( ptr::null_mut(), mapping_size, - libc::PROT_NONE, - libc::MAP_PRIVATE | libc::MAP_ANON, - -1, - 0, + rsix::io::ProtFlags::NONE, + rsix::io::MapFlags::PRIVATE, ) + .context(format!("mmap failed to allocate {:#x} bytes", mapping_size))? }; - if ptr as isize == -1_isize { - bail!( - "mmap failed to allocate {:#x} bytes: {}", - mapping_size, - io::Error::last_os_error() - ); - } let mut result = Self { ptr: ptr as usize, @@ -237,6 +216,8 @@ impl Mmap { /// must be native page-size multiples. #[cfg(target_os = "windows")] pub fn accessible_reserved(accessible_size: usize, mapping_size: usize) -> Result { + use anyhow::bail; + use std::io; use winapi::um::memoryapi::VirtualAlloc; use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_NOACCESS, PAGE_READWRITE}; @@ -316,6 +297,8 @@ impl Mmap { /// `self`'s reserved memory. #[cfg(target_os = "windows")] pub fn make_accessible(&mut self, start: usize, len: usize) -> Result<()> { + use anyhow::bail; + use std::io; use winapi::ctypes::c_void; use winapi::um::memoryapi::VirtualAlloc; use winapi::um::winnt::{MEM_COMMIT, PAGE_READWRITE}; @@ -398,6 +381,7 @@ impl Mmap { // we don't want our modifications to go back to the original file. #[cfg(windows)] { + use std::io; use winapi::um::memoryapi::*; use winapi::um::winnt::*; @@ -440,8 +424,8 @@ impl Drop for Mmap { #[cfg(not(target_os = "windows"))] fn drop(&mut self) { if self.len != 0 { - let r = unsafe { libc::munmap(self.ptr as *mut libc::c_void, self.len) }; - assert_eq!(r, 0, "munmap failed: {}", io::Error::last_os_error()); + unsafe { rsix::io::munmap(self.ptr as *mut std::ffi::c_void, self.len) } + .expect("munmap failed"); } } diff --git a/crates/runtime/src/traphandlers/unix.rs b/crates/runtime/src/traphandlers/unix.rs index d202cf297c..a8684a4713 100644 --- a/crates/runtime/src/traphandlers/unix.rs +++ b/crates/runtime/src/traphandlers/unix.rs @@ -1,6 +1,5 @@ use crate::traphandlers::{tls, wasmtime_longjmp, Trap}; use std::cell::RefCell; -use std::convert::TryInto; use std::io; use std::mem::{self, MaybeUninit}; use std::ptr::{self, null_mut}; @@ -291,36 +290,27 @@ pub fn lazy_per_thread_init() -> Result<(), Box> { // ... but failing that we need to allocate our own, so do all that // here. - let page_size: usize = libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap(); + let page_size: usize = region::page::size(); let guard_size = page_size; let alloc_size = guard_size + MIN_STACK_SIZE; - let ptr = libc::mmap( + let ptr = rsix::io::mmap_anonymous( null_mut(), alloc_size, - libc::PROT_NONE, - libc::MAP_PRIVATE | libc::MAP_ANON, - -1, - 0, - ); - if ptr == libc::MAP_FAILED { - return Err(Box::new(Trap::oom())); - } + rsix::io::ProtFlags::NONE, + rsix::io::MapFlags::PRIVATE, + ) + .map_err(|_| Box::new(Trap::oom()))?; // Prepare the stack with readable/writable memory and then register it // with `sigaltstack`. - let stack_ptr = (ptr as usize + guard_size) as *mut libc::c_void; - let r = libc::mprotect( + let stack_ptr = (ptr as usize + guard_size) as *mut std::ffi::c_void; + rsix::io::mprotect( stack_ptr, MIN_STACK_SIZE, - libc::PROT_READ | libc::PROT_WRITE, - ); - assert_eq!( - r, - 0, - "mprotect to configure memory for sigaltstack failed: {}", - io::Error::last_os_error() - ); + rsix::io::MprotectFlags::READ | rsix::io::MprotectFlags::WRITE, + ) + .expect("mprotect to configure memory for sigaltstack failed"); let new_stack = libc::stack_t { ss_sp: stack_ptr, ss_flags: 0, @@ -344,8 +334,8 @@ pub fn lazy_per_thread_init() -> Result<(), Box> { fn drop(&mut self) { unsafe { // Deallocate the stack memory. - let r = libc::munmap(self.mmap_ptr, self.mmap_size); - debug_assert_eq!(r, 0, "munmap failed during thread shutdown"); + let r = rsix::io::munmap(self.mmap_ptr, self.mmap_size); + debug_assert!(r.is_ok(), "munmap failed during thread shutdown"); } } } diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index 042b32a3d9..c3665e35f3 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -21,7 +21,7 @@ tempfile = "3.1.0" os_pipe = "0.9" anyhow = "1.0.19" wat = "1.0.37" -cap-std = "0.19.0" +cap-std = "0.19.1" tokio = { version = "1.8.0", features = ["rt-multi-thread"] } [features] diff --git a/crates/wasi-common/Cargo.toml b/crates/wasi-common/Cargo.toml index 0a2359229d..85f2304b0b 100644 --- a/crates/wasi-common/Cargo.toml +++ b/crates/wasi-common/Cargo.toml @@ -22,13 +22,13 @@ anyhow = "1.0" thiserror = "1.0" wiggle = { path = "../wiggle", default-features = false, version = "0.30.0" } tracing = "0.1.19" -cap-std = "0.19.0" -cap-rand = "0.19.0" +cap-std = "0.19.1" +cap-rand = "0.19.1" bitflags = "1.2" -io-lifetimes = { version = "0.3.0", default-features = false } +io-lifetimes = { version = "0.3.1", default-features = false } [target.'cfg(unix)'.dependencies] -rsix = "0.22.4" +rsix = "0.23.0" [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/crates/wasi-common/cap-std-sync/Cargo.toml b/crates/wasi-common/cap-std-sync/Cargo.toml index 570134dcd2..3c093f679b 100644 --- a/crates/wasi-common/cap-std-sync/Cargo.toml +++ b/crates/wasi-common/cap-std-sync/Cargo.toml @@ -15,18 +15,18 @@ include = ["src/**/*", "README.md", "LICENSE" ] wasi-common = { path = "../", version = "0.30.0" } async-trait = "0.1" anyhow = "1.0" -cap-std = "0.19.0" -cap-fs-ext = "0.19.0" -cap-time-ext = "0.19.0" -cap-rand = "0.19.0" -fs-set-times = "0.11.0" -system-interface = { version = "0.14.0", features = ["cap_std_impls"] } +cap-std = "0.19.1" +cap-fs-ext = "0.19.1" +cap-time-ext = "0.19.1" +cap-rand = "0.19.1" +fs-set-times = "0.12.0" +system-interface = { version = "0.15.0", features = ["cap_std_impls"] } tracing = "0.1.19" bitflags = "1.2" io-lifetimes = { version = "0.3.0", default-features = false } [target.'cfg(unix)'.dependencies] -rsix = "0.22.4" +rsix = "0.23.0" [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/crates/wasi-common/tokio/Cargo.toml b/crates/wasi-common/tokio/Cargo.toml index bdebd370e5..bf3fbce231 100644 --- a/crates/wasi-common/tokio/Cargo.toml +++ b/crates/wasi-common/tokio/Cargo.toml @@ -15,18 +15,18 @@ wasi-common = { path = "../", version = "0.30.0" } wasi-cap-std-sync = { path = "../cap-std-sync", version = "0.30.0" } wiggle = { path = "../../wiggle", version = "0.30.0" } tokio = { version = "1.8.0", features = [ "rt", "fs", "time", "io-util", "net", "io-std", "rt-multi-thread"] } -cap-std = "0.19.0" -cap-fs-ext = "0.19.0" -cap-time-ext = "0.19.0" -fs-set-times = "0.11.0" -system-interface = { version = "0.14.0", features = ["cap_std_impls"] } +cap-std = "0.19.1" +cap-fs-ext = "0.19.1" +cap-time-ext = "0.19.1" +fs-set-times = "0.12.0" +system-interface = { version = "0.15.0", features = ["cap_std_impls"] } tracing = "0.1.19" bitflags = "1.2" anyhow = "1" io-lifetimes = { version = "0.3.0", default-features = false } [target.'cfg(unix)'.dependencies] -rsix = "0.22.4" +rsix = "0.23.0" [target.'cfg(windows)'.dependencies] winapi = "0.3" @@ -36,4 +36,4 @@ lazy_static = "1.4" tempfile = "3.1.0" tokio = { version = "1.8.0", features = [ "macros" ] } anyhow = "1" -cap-tempfile = "0.19.0" +cap-tempfile = "0.19.1" diff --git a/tests/all/custom_signal_handler.rs b/tests/all/custom_signal_handler.rs index 0c6339cad4..a5df1466f2 100644 --- a/tests/all/custom_signal_handler.rs +++ b/tests/all/custom_signal_handler.rs @@ -4,6 +4,7 @@ ))] mod tests { use anyhow::Result; + use rsix::io::{mprotect, MprotectFlags}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use wasmtime::unix::StoreExt; @@ -59,7 +60,7 @@ mod tests { // So we can later trigger SIGSEGV by performing a read unsafe { - libc::mprotect(base as *mut libc::c_void, length, libc::PROT_NONE); + mprotect(base as *mut std::ffi::c_void, length, MprotectFlags::NONE).unwrap(); } println!("memory: base={:?}, length={}", base, length); @@ -81,11 +82,12 @@ mod tests { let result = (si_addr as u64) < (base as u64) + (length as u64); // Remove protections so the execution may resume unsafe { - libc::mprotect( + mprotect( base as *mut libc::c_void, length, - libc::PROT_READ | libc::PROT_WRITE, - ); + MprotectFlags::READ | MprotectFlags::WRITE, + ) + .unwrap(); } println!("signal handled: {}", result); result @@ -213,11 +215,12 @@ mod tests { let instance1_handler_triggered = instance1_handler_triggered.clone(); move |_signum, _siginfo, _context| { // Remove protections so the execution may resume - libc::mprotect( + mprotect( base1 as *mut libc::c_void, length1, - libc::PROT_READ | libc::PROT_WRITE, - ); + MprotectFlags::READ | MprotectFlags::WRITE, + ) + .unwrap(); instance1_handler_triggered.store(true, Ordering::SeqCst); println!( "Hello from instance1 signal handler! {}", @@ -258,11 +261,12 @@ mod tests { let instance2_handler_triggered = instance2_handler_triggered.clone(); move |_signum, _siginfo, _context| { // Remove protections so the execution may resume - libc::mprotect( + mprotect( base2 as *mut libc::c_void, length2, - libc::PROT_READ | libc::PROT_WRITE, - ); + MprotectFlags::READ | MprotectFlags::WRITE, + ) + .unwrap(); instance2_handler_triggered.store(true, Ordering::SeqCst); println!( "Hello from instance2 signal handler! {}", diff --git a/tests/all/memory_creator.rs b/tests/all/memory_creator.rs index 7ba8ed0078..3eda301045 100644 --- a/tests/all/memory_creator.rs +++ b/tests/all/memory_creator.rs @@ -3,13 +3,9 @@ mod not_for_windows { use wasmtime::*; use wasmtime_environ::{WASM32_MAX_PAGES, WASM_PAGE_SIZE}; - use libc::MAP_FAILED; - use libc::{mmap, mprotect, munmap}; - use libc::{sysconf, _SC_PAGESIZE}; - use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; + use rsix::io::{mmap_anonymous, mprotect, munmap, MapFlags, MprotectFlags, ProtFlags}; use std::convert::TryFrom; - use std::io::Error; use std::ptr::null_mut; use std::sync::{Arc, Mutex}; @@ -23,16 +19,16 @@ mod not_for_windows { impl CustomMemory { unsafe fn new(minimum: usize, maximum: usize, glob_counter: Arc>) -> Self { - let page_size = sysconf(_SC_PAGESIZE) as usize; + let page_size = rsix::process::page_size(); let guard_size = page_size; let size = maximum + guard_size; assert_eq!(size % page_size, 0); // we rely on WASM_PAGE_SIZE being multiple of host page size - let mem = mmap(null_mut(), size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); - assert_ne!(mem, MAP_FAILED, "mmap failed: {}", Error::last_os_error()); + let mem = mmap_anonymous(null_mut(), size, ProtFlags::NONE, MapFlags::PRIVATE) + .expect("mmap failed"); - let r = mprotect(mem, minimum, PROT_READ | PROT_WRITE); - assert_eq!(r, 0, "mprotect failed: {}", Error::last_os_error()); + mprotect(mem, minimum, MprotectFlags::READ | MprotectFlags::WRITE) + .expect("mprotect failed"); *glob_counter.lock().unwrap() += minimum; Self { @@ -48,8 +44,7 @@ mod not_for_windows { impl Drop for CustomMemory { fn drop(&mut self) { *self.glob_bytes_counter.lock().unwrap() -= self.used_wasm_bytes; - let r = unsafe { munmap(self.mem as *mut _, self.size) }; - assert_eq!(r, 0, "munmap failed: {}", Error::last_os_error()); + unsafe { munmap(self.mem as *mut _, self.size).expect("munmap failed") }; } } @@ -67,8 +62,8 @@ mod not_for_windows { let delta = new_size - self.used_wasm_bytes; unsafe { let start = (self.mem as *mut u8).add(self.used_wasm_bytes) as _; - let r = mprotect(start, delta, PROT_READ | PROT_WRITE); - assert_eq!(r, 0, "mprotect failed: {}", Error::last_os_error()); + mprotect(start, delta, MprotectFlags::READ | MprotectFlags::WRITE) + .expect("mprotect failed"); } *self.glob_bytes_counter.lock().unwrap() += delta;