diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ed3c9d2..f9088ce 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -37,6 +37,20 @@ jobs: - name: Run tests (Linux 5.7 support) run: cargo test --verbose --features linux5_7 + lint: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Check formatting + run: cargo fmt --all --check + - name: Clippy + run: | + for f in "" linux4_14 linux5_7 linux5_13; do + cargo clippy --all-targets ${f:+--features $f} -- -D warnings + done + audit: runs-on: ubuntu-latest diff --git a/src/builder.rs b/src/builder.rs index 7b2a599..a65af79 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -13,7 +13,7 @@ cfg_if::cfg_if! { if #[cfg(any(feature = "linux5_7", feature = "linux4_14"))] { bitflags! { /// Used with `UffdBuilder` to determine which features are available in the current kernel. - #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct FeatureFlags: u64 { const PAGEFAULT_FLAG_WP = raw::UFFD_FEATURE_PAGEFAULT_FLAG_WP; const EVENT_FORK = raw::UFFD_FEATURE_EVENT_FORK; @@ -29,7 +29,7 @@ cfg_if::cfg_if! { } else { bitflags! { /// Used with `UffdBuilder` to determine which features are available in the current kernel. - #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct FeatureFlags: u64 { const PAGEFAULT_FLAG_WP = raw::UFFD_FEATURE_PAGEFAULT_FLAG_WP; const EVENT_FORK = raw::UFFD_FEATURE_EVENT_FORK; @@ -62,10 +62,8 @@ pub struct UffdBuilder { req_ioctls: IoctlFlags, } -impl UffdBuilder { - /// Create a new builder with no required features or ioctls, `close_on_exec` and - /// `non_blocking` both set to `false`, and `user_mode_only` set to `true`. - pub fn new() -> UffdBuilder { +impl Default for UffdBuilder { + fn default() -> Self { UffdBuilder { close_on_exec: false, non_blocking: false, @@ -74,6 +72,14 @@ impl UffdBuilder { req_ioctls: IoctlFlags::empty(), } } +} + +impl UffdBuilder { + /// Create a new builder with no required features or ioctls, `close_on_exec` and + /// `non_blocking` both set to `false`, and `user_mode_only` set to `true`. + pub fn new() -> UffdBuilder { + UffdBuilder::default() + } /// Enable the close-on-exec flag for the new userfaultfd object (see the description of /// `O_CLOEXEC` in [`open(2)`](http://man7.org/linux/man-pages/man2/open.2.html)). @@ -195,3 +201,18 @@ impl UffdBuilder { } } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_new_defaults() { + let builder = UffdBuilder::new(); + assert!(!builder.close_on_exec); + assert!(!builder.non_blocking); + assert!(builder.user_mode_only); + assert!(builder.req_features.is_empty()); + assert!(builder.req_ioctls.is_empty()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 59c2ce8..48ac4be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,6 +141,12 @@ impl Uffd { /// /// If `wake` is `true`, wake up the thread waiting for page fault resolution on the memory /// range. + /// + /// # Safety + /// + /// This writes to the memory range `[dst, dst + len)` of the calling process. The caller must + /// ensure that it is sound for the contents of that range to change, e.g. that no Rust + /// references to it are live. pub unsafe fn copy( &self, src: *const c_void, @@ -180,6 +186,12 @@ impl Uffd { /// /// If `wake` is `true`, wake up the thread waiting for page fault resolution on the memory /// address range. + /// + /// # Safety + /// + /// This writes to the memory range `[start, start + len)` of the calling process. The caller + /// must ensure that it is sound for the contents of that range to change, e.g. that no Rust + /// references to it are live. pub unsafe fn zeropage(&self, start: *mut c_void, len: usize, wake: bool) -> Result { let mut zeropage = raw::uffdio_zeropage { range: raw::uffdio_range { @@ -380,7 +392,7 @@ impl Uffd { }; let count = match read(self, buf) { - Err(e) if e == Errno::EAGAIN => 0, + Err(Errno::EAGAIN) => 0, Err(e) => return Err(Error::SystemError(e)), Ok(0) => return Err(Error::ReadEof), Ok(bytes_read) => { @@ -396,13 +408,13 @@ impl Uffd { } }; - Ok(msgs.iter().take(count).map(|msg| Event::from_uffd_msg(msg))) + Ok(msgs.iter().take(count).map(Event::from_uffd_msg)) } } bitflags! { /// Used with `UffdBuilder` and `Uffd::register()` to determine which operations are available. - #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct IoctlFlags: u64 { const REGISTER = 1 << raw::_UFFDIO_REGISTER; const UNREGISTER = 1 << raw::_UFFDIO_UNREGISTER; @@ -599,7 +611,7 @@ mod test { .. } => { let index = (addr as usize - mapping as usize) / PAGE_SIZE; - assert_eq!(seen[index], false); + assert!(!seen[index]); seen[index] = true; uffd.zeropage(addr, PAGE_SIZE, true)?; } diff --git a/src/raw.rs b/src/raw.rs index 385b1f2..8b21464 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -1,9 +1,9 @@ -use libc::{c_int, c_long, syscall, SYS_userfaultfd, INT_MAX}; +use libc::{c_int, c_long, syscall, SYS_userfaultfd}; pub use userfaultfd_sys::*; pub unsafe fn userfaultfd(flags: c_int) -> c_int { let fd = syscall(SYS_userfaultfd, flags as c_long); - if fd > INT_MAX as c_long { + if fd > c_int::MAX as c_long { panic!("fd doesn't fit in a c_int"); } else { fd as c_int diff --git a/tests/manpage_example.rs b/tests/manpage_example.rs index 49a061f..355bfe7 100644 --- a/tests/manpage_example.rs +++ b/tests/manpage_example.rs @@ -1,7 +1,7 @@ #[test] fn run_manpage_example() { let output = std::process::Command::new("cargo") - .args(&["run", "--example", "manpage", "--", "3"]) + .args(["run", "--example", "manpage", "--", "3"]) .output() .expect("manpage example failed to start"); assert!(output.status.success(), "manpage example succeeded");