rustix/mm/
mmap.rs

1//! The `mmap` API.
2//!
3//! # Safety
4//!
5//! `mmap` and related functions manipulate raw pointers and have special
6//! semantics.
7#![allow(unsafe_code)]
8
9use crate::{backend, io};
10use backend::fd::AsFd;
11use core::ffi::c_void;
12
13#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
14pub use backend::mm::types::MlockAllFlags;
15#[cfg(linux_kernel)]
16pub use backend::mm::types::MlockFlags;
17#[cfg(any(target_os = "emscripten", target_os = "linux"))]
18pub use backend::mm::types::MremapFlags;
19pub use backend::mm::types::{MapFlags, MprotectFlags, ProtFlags};
20
21impl MapFlags {
22    /// Create `MAP_HUGETLB` with provided size of huge page.
23    ///
24    /// Under the hood it computes
25    /// `MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT)`.
26    /// `huge_page_size_log2` denotes logarithm of huge page size to use and
27    /// should be between 16 and 63 (inclusive).
28    ///
29    /// ```
30    /// use rustix::mm::MapFlags;
31    ///
32    /// let f = MapFlags::hugetlb_with_size_log2(30).unwrap();
33    /// assert_eq!(f, MapFlags::HUGETLB | MapFlags::HUGE_1GB);
34    /// ```
35    #[cfg(linux_kernel)]
36    pub const fn hugetlb_with_size_log2(huge_page_size_log2: u32) -> Option<Self> {
37        use linux_raw_sys::general::{MAP_HUGETLB, MAP_HUGE_SHIFT};
38        if 16 <= huge_page_size_log2 && huge_page_size_log2 <= 63 {
39            let bits = MAP_HUGETLB | (huge_page_size_log2 << MAP_HUGE_SHIFT);
40            Self::from_bits(bits)
41        } else {
42            None
43        }
44    }
45}
46
47/// `mmap(ptr, len, prot, flags, fd, offset)`—Create a file-backed memory
48/// mapping.
49///
50/// For anonymous mappings (`MAP_ANON`/`MAP_ANONYMOUS`), see
51/// [`mmap_anonymous`].
52///
53/// # Safety
54///
55/// If `ptr` is not null, it must be aligned to the applicable page size, and
56/// the range of memory starting at `ptr` and extending for `len` bytes,
57/// rounded up to the applicable page size, must be valid to mutate using
58/// `ptr`'s provenance.
59///
60/// If there exist any Rust references referring to the memory region, or if
61/// you subsequently create a Rust reference referring to the resulting region,
62/// it is your responsibility to ensure that the Rust reference invariants are
63/// preserved, including ensuring that the memory is not mutated in a way that
64/// a Rust reference would not expect.
65///
66/// # References
67///  - [POSIX]
68///  - [Linux]
69///  - [Apple]
70///  - [FreeBSD]
71///  - [NetBSD]
72///  - [OpenBSD]
73///  - [DragonFly BSD]
74///  - [illumos]
75///  - [glibc]
76///
77/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
78/// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html
79/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html
80/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2
81/// [NetBSD]: https://man.netbsd.org/mmap.2
82/// [OpenBSD]: https://man.openbsd.org/mmap.2
83/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap&section=2
84/// [illumos]: https://illumos.org/man/2/mmap
85/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-mmap
86#[inline]
87pub unsafe fn mmap<Fd: AsFd>(
88    ptr: *mut c_void,
89    len: usize,
90    prot: ProtFlags,
91    flags: MapFlags,
92    fd: Fd,
93    offset: u64,
94) -> io::Result<*mut c_void> {
95    backend::mm::syscalls::mmap(ptr, len, prot, flags, fd.as_fd(), offset)
96}
97
98/// `mmap(ptr, len, prot, MAP_ANONYMOUS | flags, -1, 0)`—Create an anonymous
99/// memory mapping.
100///
101/// For file-backed mappings, see [`mmap`].
102///
103/// # Safety
104///
105/// If `ptr` is not null, it must be aligned to the applicable page size, and
106/// the range of memory starting at `ptr` and extending for `len` bytes,
107/// rounded up to the applicable page size, must be valid to mutate with
108/// `ptr`'s provenance.
109///
110/// # References
111///  - [POSIX]
112///  - [Linux]
113///  - [Apple]
114///  - [FreeBSD]
115///  - [NetBSD]
116///  - [OpenBSD]
117///  - [DragonFly BSD]
118///  - [illumos]
119///  - [glibc]
120///
121/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mmap.html
122/// [Linux]: https://man7.org/linux/man-pages/man2/mmap.2.html
123/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html
124/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mmap&sektion=2
125/// [NetBSD]: https://man.netbsd.org/mmap.2
126/// [OpenBSD]: https://man.openbsd.org/mmap.2
127/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mmap&section=2
128/// [illumos]: https://illumos.org/man/2/mmap
129/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-mmap
130#[inline]
131#[doc(alias = "mmap")]
132pub unsafe fn mmap_anonymous(
133    ptr: *mut c_void,
134    len: usize,
135    prot: ProtFlags,
136    flags: MapFlags,
137) -> io::Result<*mut c_void> {
138    backend::mm::syscalls::mmap_anonymous(ptr, len, prot, flags)
139}
140
141/// `munmap(ptr, len)`—Remove a memory mapping.
142///
143/// # Safety
144///
145/// `ptr` must be aligned to the applicable page size, and the range of memory
146/// starting at `ptr` and extending for `len` bytes, rounded up to the
147/// applicable page size, must be valid to mutate with `ptr`'s provenance. And
148/// there must be no Rust references referring to that memory.
149///
150/// # References
151///  - [POSIX]
152///  - [Linux]
153///  - [Apple]
154///  - [FreeBSD]
155///  - [NetBSD]
156///  - [OpenBSD]
157///  - [DragonFly BSD]
158///  - [illumos]
159///  - [glibc]
160///
161/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munmap.html
162/// [Linux]: https://man7.org/linux/man-pages/man2/munmap.2.html
163/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munmap.2.html
164/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munmap&sektion=2
165/// [NetBSD]: https://man.netbsd.org/munmap.2
166/// [OpenBSD]: https://man.openbsd.org/munmap.2
167/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munmap&section=2
168/// [illumos]: https://illumos.org/man/2/munmap
169/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Memory_002dmapped-I_002fO.html#index-munmap
170#[inline]
171pub unsafe fn munmap(ptr: *mut c_void, len: usize) -> io::Result<()> {
172    backend::mm::syscalls::munmap(ptr, len)
173}
174
175/// `mremap(old_address, old_size, new_size, flags)`—Resize, modify, and/or
176/// move a memory mapping.
177///
178/// For moving a mapping to a fixed address (`MREMAP_FIXED`), see
179/// [`mremap_fixed`].
180///
181/// # Safety
182///
183/// `old_address` must be aligned to the applicable page size, and the range of
184/// memory starting at `old_address` and extending for `old_size` bytes,
185/// rounded up to the applicable page size, must be valid to mutate with
186/// `old_address`'s provenance. If `MremapFlags::MAY_MOVE` is set in `flags`,
187/// there must be no Rust references referring to that the memory.
188///
189/// If `new_size` is less than `old_size`, than there must be no Rust
190/// references referring to the memory starting at offset `new_size` and ending
191/// at `old_size`.
192///
193/// # References
194///  - [Linux]
195///
196/// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html
197#[cfg(any(target_os = "emscripten", target_os = "linux"))]
198#[inline]
199pub unsafe fn mremap(
200    old_address: *mut c_void,
201    old_size: usize,
202    new_size: usize,
203    flags: MremapFlags,
204) -> io::Result<*mut c_void> {
205    backend::mm::syscalls::mremap(old_address, old_size, new_size, flags)
206}
207
208/// `mremap(old_address, old_size, new_size, MREMAP_FIXED | flags)`—Resize,
209/// modify, and/or move a memory mapping to a specific address.
210///
211/// For `mremap` without moving to a specific address, see [`mremap`].
212/// [`mremap_fixed`].
213///
214/// # Safety
215///
216/// `old_address` and `new_address` must be aligned to the applicable page
217/// size, the range of memory starting at `old_address` and extending for
218/// `old_size` bytes, rounded up to the applicable page size, must be valid to
219/// mutate with `old_address`'s provenance, and the range of memory starting at
220/// `new_address` and extending for `new_size` bytes, rounded up to the
221/// applicable page size, must be valid to mutate with `new_address`'s
222/// provenance.
223///
224/// There must be no Rust references referring to either of those memory
225/// regions.
226///
227/// # References
228///  - [Linux]
229///
230/// [Linux]: https://man7.org/linux/man-pages/man2/mremap.2.html
231#[cfg(any(target_os = "emscripten", target_os = "linux"))]
232#[inline]
233#[doc(alias = "mremap")]
234pub unsafe fn mremap_fixed(
235    old_address: *mut c_void,
236    old_size: usize,
237    new_size: usize,
238    flags: MremapFlags,
239    new_address: *mut c_void,
240) -> io::Result<*mut c_void> {
241    backend::mm::syscalls::mremap_fixed(old_address, old_size, new_size, flags, new_address)
242}
243
244/// `mprotect(ptr, len, flags)`—Change the protection flags of a region of
245/// memory.
246///
247/// # Safety
248///
249/// The range of memory starting at `ptr` and extending for `len` bytes,
250/// rounded up to the applicable page size, must be valid to read with `ptr`'s
251/// provenance.
252///
253/// # References
254///  - [POSIX]
255///  - [Linux]
256///  - [Apple]
257///  - [FreeBSD]
258///  - [NetBSD]
259///  - [OpenBSD]
260///  - [DragonFly BSD]
261///  - [illumos]
262///
263/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mprotect.html
264/// [Linux]: https://man7.org/linux/man-pages/man2/mprotect.2.html
265/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mprotect.2.html
266/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mprotect&sektion=2
267/// [NetBSD]: https://man.netbsd.org/mprotect.2
268/// [OpenBSD]: https://man.openbsd.org/mprotect.2
269/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mprotect&section=2
270/// [illumos]: https://illumos.org/man/2/mprotect
271#[inline]
272pub unsafe fn mprotect(ptr: *mut c_void, len: usize, flags: MprotectFlags) -> io::Result<()> {
273    backend::mm::syscalls::mprotect(ptr, len, flags)
274}
275
276/// `mlock(ptr, len)`—Lock memory into RAM.
277///
278/// Some implementations implicitly round the memory region out to the nearest
279/// page boundaries, so this function may lock more memory than explicitly
280/// requested if the memory isn't page-aligned. Other implementations fail if
281/// the memory isn't page-aligned.
282///
283/// # Safety
284///
285/// The range of memory starting at `ptr`, rounded down to the applicable page
286/// boundary, and extending for `len` bytes, rounded up to the applicable page
287/// size, must be valid to read with `ptr`'s provenance.
288///
289/// # References
290///  - [POSIX]
291///  - [Linux]
292///  - [Apple]
293///  - [FreeBSD]
294///  - [NetBSD]
295///  - [OpenBSD]
296///  - [DragonFly BSD]
297///  - [illumos]
298///  - [glibc]
299///
300/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mlock.html
301/// [Linux]: https://man7.org/linux/man-pages/man2/mlock.2.html
302/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mlock.2.html
303/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlock&sektion=2
304/// [NetBSD]: https://man.netbsd.org/mlock.2
305/// [OpenBSD]: https://man.openbsd.org/mlock.2
306/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlock&section=2
307/// [illumos]: https://illumos.org/man/3C/mlock
308/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlock
309#[inline]
310pub unsafe fn mlock(ptr: *mut c_void, len: usize) -> io::Result<()> {
311    backend::mm::syscalls::mlock(ptr, len)
312}
313
314/// `mlock2(ptr, len, flags)`—Lock memory into RAM, with flags.
315///
316/// `mlock_with` is the same as [`mlock`] but adds an additional flags operand.
317///
318/// Some implementations implicitly round the memory region out to the nearest
319/// page boundaries, so this function may lock more memory than explicitly
320/// requested if the memory isn't page-aligned.
321///
322/// # Safety
323///
324/// The range of memory starting at `ptr`, rounded down to the applicable page
325/// boundary, and extending for `len` bytes, rounded up to the applicable page
326/// size, must be valid to read with `ptr`'s provenance.
327///
328/// # References
329///  - [Linux]
330///  - [glibc]
331///
332/// [Linux]: https://man7.org/linux/man-pages/man2/mlock2.2.html
333/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlock2
334#[cfg(linux_kernel)]
335#[inline]
336#[doc(alias = "mlock2")]
337pub unsafe fn mlock_with(ptr: *mut c_void, len: usize, flags: MlockFlags) -> io::Result<()> {
338    backend::mm::syscalls::mlock_with(ptr, len, flags)
339}
340
341/// `munlock(ptr, len)`—Unlock memory.
342///
343/// Some implementations implicitly round the memory region out to the nearest
344/// page boundaries, so this function may unlock more memory than explicitly
345/// requested if the memory isn't page-aligned.
346///
347/// # Safety
348///
349/// The range of memory starting at `ptr`, rounded down to the applicable page
350/// boundary, and extending for `len` bytes, rounded up to the applicable page
351/// size, must be valid to read with `ptr`'s provenance.
352///
353/// # References
354///  - [POSIX]
355///  - [Linux]
356///  - [Apple]
357///  - [FreeBSD]
358///  - [NetBSD]
359///  - [OpenBSD]
360///  - [DragonFly BSD]
361///  - [illumos]
362///  - [glibc]
363///
364/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munlock.html
365/// [Linux]: https://man7.org/linux/man-pages/man2/munlock.2.html
366/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/munlock.2.html
367/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlock&sektion=2
368/// [NetBSD]: https://man.netbsd.org/munlock.2
369/// [OpenBSD]: https://man.openbsd.org/munlock.2
370/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlock&section=2
371/// [illumos]: https://illumos.org/man/3C/munlock
372/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-munlock
373#[inline]
374pub unsafe fn munlock(ptr: *mut c_void, len: usize) -> io::Result<()> {
375    backend::mm::syscalls::munlock(ptr, len)
376}
377
378/// Locks all pages mapped into the address space of the calling process.
379///
380/// This includes the pages of the code, data, and stack segment, as well as
381/// shared libraries, user space kernel data, shared memory, and memory-mapped
382/// files. All mapped pages are guaranteed to be resident in RAM when the call
383/// returns successfully; the pages are guaranteed to stay in RAM until later
384/// unlocked.
385///
386/// # References
387///  - [POSIX]
388///  - [Linux]
389///  - [FreeBSD]
390///  - [NetBSD]
391///  - [OpenBSD]
392///  - [DragonFly BSD]
393///  - [illumos]
394///  - [glibc]
395///
396/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/mlockall.html
397/// [Linux]: https://man7.org/linux/man-pages/man2/mlockall.2.html
398/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=mlockall&sektion=2
399/// [NetBSD]: https://man.netbsd.org/mlockall.2
400/// [OpenBSD]: https://man.openbsd.org/mlockall.2
401/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=mlockall&section=2
402/// [illumos]: https://illumos.org/man/3C/mlockall
403/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-mlockall
404#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
405#[inline]
406pub fn mlockall(flags: MlockAllFlags) -> io::Result<()> {
407    backend::mm::syscalls::mlockall(flags)
408}
409
410/// Unlocks all pages mapped into the address space of the calling process.
411///
412/// # Warnings
413///
414/// This function is aware of all the memory pages in the process, as if it
415/// were a debugger. It unlocks all the pages, which could potentially
416/// compromise security assumptions made by code about memory it has
417/// encapsulated.
418///
419/// # References
420///  - [POSIX]
421///  - [Linux]
422///  - [FreeBSD]
423///  - [NetBSD]
424///  - [OpenBSD]
425///  - [DragonFly BSD]
426///  - [illumos]
427///  - [glibc]
428///
429/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/munlockall.html
430/// [Linux]: https://man7.org/linux/man-pages/man2/munlockall.2.html
431/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=munlockall&sektion=2
432/// [NetBSD]: https://man.netbsd.org/munlockall.2
433/// [OpenBSD]: https://man.openbsd.org/munlockall.2
434/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=munlockall&section=2
435/// [illumos]: https://illumos.org/man/3C/munlockall
436/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Page-Lock-Functions.html#index-munlockall
437#[cfg(any(linux_kernel, freebsdlike, netbsdlike))]
438#[inline]
439pub fn munlockall() -> io::Result<()> {
440    backend::mm::syscalls::munlockall()
441}