summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/tests/mm/mlock.rs
blob: c4a1a83b5750b5e04cfc2d8f0b32bf040633a0e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//! Tests for `mlock`.
//!
//! We can't easily test that it actually locks memory, but we can test that we
//! can call it and either get success or a reasonable error message.

use std::ffi::c_void;

#[test]
fn test_mlock() {
    let mut buf = vec![0_u8; 4096];

    unsafe {
        match rustix::mm::mlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()) {
            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
            // Tests won't always have enough memory or permissions, and that's ok.
            Err(rustix::io::Errno::PERM) | Err(rustix::io::Errno::NOMEM) => {}
            // But they shouldn't fail otherwise.
            Err(other) => Err(other).unwrap(),
        }
    }
}

#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_mlock_with() {
    let mut buf = vec![0_u8; 4096];

    unsafe {
        match rustix::mm::mlock_with(
            buf.as_mut_ptr().cast::<c_void>(),
            buf.len(),
            rustix::mm::MlockFlags::empty(),
        ) {
            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
            // Tests won't always have enough memory or permissions, and that's ok.
            Err(rustix::io::Errno::PERM)
            | Err(rustix::io::Errno::NOMEM)
            | Err(rustix::io::Errno::NOSYS) => {}
            // But they shouldn't fail otherwise.
            Err(other) => Err(other).unwrap(),
        }
    }
}

#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn test_mlock_with_onfault() {
    // With glibc, `mlock2` with `MLOCK_ONFAULT` returns `EINVAL` if the
    // `mlock2` system call returns `ENOSYS`. That's not what we want
    // here though, because `ENOSYS` just means the OS doesn't have
    // `mlock2`, while `EINVAL` may indicate a bug in rustix.
    //
    // To work around this, we use `libc::syscall` to make a `mlock2`
    // syscall directly to test for `ENOSYS`, before running the main
    // test below.
    unsafe {
        if libc::syscall(libc::SYS_mlock2, 0, 0) == -1 && libc_errno::errno().0 == libc::ENOSYS {
            return;
        }
    }

    let mut buf = vec![0_u8; 4096];

    unsafe {
        match rustix::mm::mlock_with(
            buf.as_mut_ptr().cast::<c_void>(),
            buf.len(),
            rustix::mm::MlockFlags::ONFAULT,
        ) {
            Ok(()) => rustix::mm::munlock(buf.as_mut_ptr().cast::<c_void>(), buf.len()).unwrap(),
            // Tests won't always have enough memory or permissions, and that's ok.
            Err(rustix::io::Errno::PERM)
            | Err(rustix::io::Errno::NOMEM)
            | Err(rustix::io::Errno::NOSYS) => {}
            // But they shouldn't fail otherwise.
            Err(other) => Err(other).unwrap(),
        }
    }
}