diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c050d5b2..4c70121c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -19,7 +19,7 @@ jobs: uses: actions-rs/toolchain@v1.0.7 with: profile: minimal - toolchain: stable + toolchain: 1.56.1 override: true components: rustfmt, clippy @@ -35,6 +35,11 @@ jobs: - name: Remove pre-generated prost files to force regeneration run: rm proto/*.rs + - name: Specify dependency version for old Rust + run: | + sed -i "s|inferno = { version = \"0.11\"|inferno = { version = \"=0.11.1\"|g" ./Cargo.toml + sed -i "s|criterion = \"0.4\"|criterion = \"=0.3.0\"\ncsv = \"=1.1.0\"|g" Cargo.toml + - name: Run cargo clippy prost uses: actions-rs/cargo@v1.0.3 with: @@ -74,6 +79,7 @@ jobs: target: aarch64-unknown-linux-gnu - os: macos-latest target: x86_64-unknown-linux-musl + fail-fast: false runs-on: ${{ matrix.os }} steps: @@ -88,6 +94,13 @@ jobs: target: ${{ matrix.target }} override: true + - name: Specify dependency version for old Rust + if: ${{ matrix.toolchain == '1.56.1' }} + run: | + # sed -i is not compatible with Mac OS + mv Cargo.toml Cargo.toml.bak + sed "s|inferno = { version = \"0.11\"|inferno = { version = \"=0.11.1\"|g" Cargo.toml.bak > ./Cargo.toml + - name: Run cargo build prost uses: actions-rs/cargo@v1.0.3 with: @@ -125,6 +138,7 @@ jobs: target: x86_64-unknown-linux-gnu - os: macos-latest target: x86_64-unknown-linux-musl + fail-fast: false runs-on: ${{ matrix.os }} steps: diff --git a/src/addr_validate.rs b/src/addr_validate.rs index 9e9a34c6..1b092caf 100644 --- a/src/addr_validate.rs +++ b/src/addr_validate.rs @@ -1,13 +1,25 @@ -use std::{cell::RefCell, mem::size_of}; +use std::{cell::UnsafeCell, mem::size_of}; use nix::{ errno::Errno, unistd::{close, read, write}, }; -thread_local! { - static MEM_VALIDATE_PIPE: RefCell<[i32; 2]> = RefCell::new([-1, -1]); +struct Pipes { + fd: UnsafeCell<[i32; 2]>, } +unsafe impl Sync for Pipes {} +impl std::ops::Deref for Pipes { + type Target = UnsafeCell<[i32; 2]>; + + fn deref(&self) -> &Self::Target { + &self.fd + } +} + +static MEM_VALIDATE_PIPE: Pipes = Pipes { + fd: UnsafeCell::new([-1, -1]), +}; #[inline] #[cfg(target_os = "linux")] @@ -42,56 +54,50 @@ fn create_pipe() -> nix::Result<(i32, i32)> { } fn open_pipe() -> nix::Result<()> { - MEM_VALIDATE_PIPE.with(|pipes| { - let mut pipes = pipes.borrow_mut(); + let pipes = unsafe { &mut *MEM_VALIDATE_PIPE.get() }; - // ignore the result - let _ = close(pipes[0]); - let _ = close(pipes[1]); + // ignore the result + let _ = close(pipes[0]); + let _ = close(pipes[1]); - let (read_fd, write_fd) = create_pipe()?; + let (read_fd, write_fd) = create_pipe()?; - pipes[0] = read_fd; - pipes[1] = write_fd; + pipes[0] = read_fd; + pipes[1] = write_fd; - Ok(()) - }) + Ok(()) } pub fn validate(addr: *const libc::c_void) -> bool { const CHECK_LENGTH: usize = 2 * size_of::<*const libc::c_void>() / size_of::(); // read data in the pipe - let valid_read = MEM_VALIDATE_PIPE.with(|pipes| { - let pipes = pipes.borrow(); - loop { - let mut buf = [0u8; CHECK_LENGTH]; - - match read(pipes[0], &mut buf) { - Ok(bytes) => break bytes > 0, - Err(_err @ Errno::EINTR) => continue, - Err(_err @ Errno::EAGAIN) => break true, - Err(_) => break false, - } + let pipes = unsafe { &*MEM_VALIDATE_PIPE.get() }; + let valid_read = loop { + let mut buf = [0u8; CHECK_LENGTH]; + + match read(pipes[0], &mut buf) { + Ok(bytes) => break bytes > 0, + Err(_err @ Errno::EINTR) => continue, + Err(_err @ Errno::EAGAIN) => break true, + Err(_) => break false, } - }); + }; if !valid_read && open_pipe().is_err() { return false; } - MEM_VALIDATE_PIPE.with(|pipes| { - let pipes = pipes.borrow(); - loop { - let buf = unsafe { std::slice::from_raw_parts(addr as *const u8, CHECK_LENGTH) }; + let pipes = unsafe { &*MEM_VALIDATE_PIPE.get() }; + loop { + let buf = unsafe { std::slice::from_raw_parts(addr as *const u8, CHECK_LENGTH) }; - match write(pipes[1], buf) { - Ok(bytes) => break bytes > 0, - Err(_err @ Errno::EINTR) => continue, - Err(_) => break false, - } + match write(pipes[1], buf) { + Ok(bytes) => break bytes > 0, + Err(_err @ Errno::EINTR) => continue, + Err(_) => break false, } - }) + } } #[cfg(test)]