xref: /third_party/rust/crates/rustix/tests/mm/mlock.rs (revision b8a62b91)
1//! Tests for `mlock`.
2//!
3//! We can't easily test that it actually locks memory, but we can test that we
4//! can call it and either get success or a reasonable error message.
5
6use std::ffi::c_void;
7
8#[test]
9fn test_mlock() {
10    let mut buf = vec![0_u8; 4096];
11
12    unsafe {
13        match rustix::mm::mlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()) {
14            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
15            // Tests won't always have enough memory or permissions, and that's ok.
16            Err(rustix::io::Errno::PERM) | Err(rustix::io::Errno::NOMEM) => {}
17            // But they shouldn't fail otherwise.
18            Err(other) => Err(other).unwrap(),
19        }
20    }
21}
22
23#[cfg(any(target_os = "android", target_os = "linux"))]
24#[test]
25fn test_mlock_with() {
26    let mut buf = vec![0_u8; 4096];
27
28    unsafe {
29        match rustix::mm::mlock_with(
30            buf.as_mut_ptr().cast::<c_void>(),
31            buf.len(),
32            rustix::mm::MlockFlags::empty(),
33        ) {
34            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
35            // Tests won't always have enough memory or permissions, and that's ok.
36            Err(rustix::io::Errno::PERM)
37            | Err(rustix::io::Errno::NOMEM)
38            | Err(rustix::io::Errno::NOSYS) => {}
39            // But they shouldn't fail otherwise.
40            Err(other) => Err(other).unwrap(),
41        }
42    }
43}
44
45#[cfg(any(target_os = "android", target_os = "linux"))]
46#[test]
47fn test_mlock_with_onfault() {
48    // With glibc, `mlock2` with `MLOCK_ONFAULT` returns `EINVAL` if the
49    // `mlock2` system call returns `ENOSYS`. That's not what we want
50    // here though, because `ENOSYS` just means the OS doesn't have
51    // `mlock2`, while `EINVAL` may indicate a bug in rustix.
52    //
53    // To work around this, we use `libc::syscall` to make a `mlock2`
54    // syscall directly to test for `ENOSYS`, before running the main
55    // test below.
56    unsafe {
57        if libc::syscall(libc::SYS_mlock2, 0, 0) == -1 && libc_errno::errno().0 == libc::ENOSYS {
58            return;
59        }
60    }
61
62    let mut buf = vec![0_u8; 4096];
63
64    unsafe {
65        match rustix::mm::mlock_with(
66            buf.as_mut_ptr().cast::<c_void>(),
67            buf.len(),
68            rustix::mm::MlockFlags::ONFAULT,
69        ) {
70            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
71            // Tests won't always have enough memory or permissions, and that's ok.
72            Err(rustix::io::Errno::PERM)
73            | Err(rustix::io::Errno::NOMEM)
74            | Err(rustix::io::Errno::NOSYS) => {}
75            // But they shouldn't fail otherwise.
76            Err(other) => Err(other).unwrap(),
77        }
78    }
79}
80