nix/sys/
mman.rs

1//! Memory management declarations.
2
3use crate::Result;
4#[cfg(not(target_os = "android"))]
5use crate::NixPath;
6use crate::errno::Errno;
7#[cfg(not(target_os = "android"))]
8use crate::fcntl::OFlag;
9use libc::{self, c_int, c_void, size_t, off_t};
10#[cfg(not(target_os = "android"))]
11use crate::sys::stat::Mode;
12use std::os::unix::io::RawFd;
13
14libc_bitflags!{
15    /// Desired memory protection of a memory mapping.
16    pub struct ProtFlags: c_int {
17        /// Pages cannot be accessed.
18        PROT_NONE;
19        /// Pages can be read.
20        PROT_READ;
21        /// Pages can be written.
22        PROT_WRITE;
23        /// Pages can be executed
24        PROT_EXEC;
25        /// Apply protection up to the end of a mapping that grows upwards.
26        #[cfg(any(target_os = "android", target_os = "linux"))]
27        PROT_GROWSDOWN;
28        /// Apply protection down to the beginning of a mapping that grows downwards.
29        #[cfg(any(target_os = "android", target_os = "linux"))]
30        PROT_GROWSUP;
31    }
32}
33
34libc_bitflags!{
35    /// Additional parameters for [`mmap`].
36    pub struct MapFlags: c_int {
37        /// Compatibility flag. Ignored.
38        MAP_FILE;
39        /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
40        MAP_SHARED;
41        /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
42        MAP_PRIVATE;
43        /// Place the mapping at exactly the address specified in `addr`.
44        MAP_FIXED;
45        /// To be used with `MAP_FIXED`, to forbid the system
46        /// to select a different address than the one specified.
47        #[cfg(target_os = "freebsd")]
48        MAP_EXCL;
49        /// Synonym for `MAP_ANONYMOUS`.
50        MAP_ANON;
51        /// The mapping is not backed by any file.
52        MAP_ANONYMOUS;
53        /// Put the mapping into the first 2GB of the process address space.
54        #[cfg(any(all(any(target_os = "android", target_os = "linux"),
55                      any(target_arch = "x86", target_arch = "x86_64")),
56                  all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
57                  all(target_os = "freebsd", target_pointer_width = "64")))]
58        MAP_32BIT;
59        /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
60        #[cfg(any(target_os = "android", target_os = "linux"))]
61        MAP_GROWSDOWN;
62        /// Compatibility flag. Ignored.
63        #[cfg(any(target_os = "android", target_os = "linux"))]
64        MAP_DENYWRITE;
65        /// Compatibility flag. Ignored.
66        #[cfg(any(target_os = "android", target_os = "linux"))]
67        MAP_EXECUTABLE;
68        /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
69        #[cfg(any(target_os = "android", target_os = "linux"))]
70        MAP_LOCKED;
71        /// Do not reserve swap space for this mapping.
72        ///
73        /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
74        #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd")))]
75        MAP_NORESERVE;
76        /// Populate page tables for a mapping.
77        #[cfg(any(target_os = "android", target_os = "linux"))]
78        MAP_POPULATE;
79        /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
80        #[cfg(any(target_os = "android", target_os = "linux"))]
81        MAP_NONBLOCK;
82        /// Allocate the mapping using "huge pages."
83        #[cfg(any(target_os = "android", target_os = "linux"))]
84        MAP_HUGETLB;
85        /// Make use of 64KB huge page (must be supported by the system)
86        #[cfg(target_os = "linux")]
87        MAP_HUGE_64KB;
88        /// Make use of 512KB huge page (must be supported by the system)
89        #[cfg(target_os = "linux")]
90        MAP_HUGE_512KB;
91        /// Make use of 1MB huge page (must be supported by the system)
92        #[cfg(target_os = "linux")]
93        MAP_HUGE_1MB;
94        /// Make use of 2MB huge page (must be supported by the system)
95        #[cfg(target_os = "linux")]
96        MAP_HUGE_2MB;
97        /// Make use of 8MB huge page (must be supported by the system)
98        #[cfg(target_os = "linux")]
99        MAP_HUGE_8MB;
100        /// Make use of 16MB huge page (must be supported by the system)
101        #[cfg(target_os = "linux")]
102        MAP_HUGE_16MB;
103        /// Make use of 32MB huge page (must be supported by the system)
104        #[cfg(target_os = "linux")]
105        MAP_HUGE_32MB;
106        /// Make use of 256MB huge page (must be supported by the system)
107        #[cfg(target_os = "linux")]
108        MAP_HUGE_256MB;
109        /// Make use of 512MB huge page (must be supported by the system)
110        #[cfg(target_os = "linux")]
111        MAP_HUGE_512MB;
112        /// Make use of 1GB huge page (must be supported by the system)
113        #[cfg(target_os = "linux")]
114        MAP_HUGE_1GB;
115        /// Make use of 2GB huge page (must be supported by the system)
116        #[cfg(target_os = "linux")]
117        MAP_HUGE_2GB;
118        /// Make use of 16GB huge page (must be supported by the system)
119        #[cfg(target_os = "linux")]
120        MAP_HUGE_16GB;
121
122        /// Lock the mapped region into memory as with `mlock(2)`.
123        #[cfg(target_os = "netbsd")]
124        MAP_WIRED;
125        /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
126        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
127        MAP_NOSYNC;
128        /// Rename private pages to a file.
129        ///
130        /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD.
131        #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
132        MAP_RENAME;
133        /// Region may contain semaphores.
134        #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
135        MAP_HASSEMAPHORE;
136        /// Region grows down, like a stack.
137        #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux", target_os = "openbsd"))]
138        MAP_STACK;
139        /// Pages in this mapping are not retained in the kernel's memory cache.
140        #[cfg(any(target_os = "ios", target_os = "macos"))]
141        MAP_NOCACHE;
142        /// Allows the W/X bit on the page, it's necessary on aarch64 architecture.
143        #[cfg(any(target_os = "ios", target_os = "macos"))]
144        MAP_JIT;
145        /// Allows to use large pages, underlying alignment based on size.
146        #[cfg(target_os = "freebsd")]
147        MAP_ALIGNED_SUPER;
148        /// Pages will be discarded in the core dumps.
149        #[cfg(target_os = "openbsd")]
150        MAP_CONCEAL;
151    }
152}
153
154#[cfg(any(target_os = "linux", target_os = "netbsd"))]
155libc_bitflags!{
156    /// Options for [`mremap`].
157    pub struct MRemapFlags: c_int {
158        /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
159        #[cfg(target_os = "linux")]
160        MREMAP_MAYMOVE;
161        /// Place the mapping at exactly the address specified in `new_address`.
162        #[cfg(target_os = "linux")]
163        MREMAP_FIXED;
164        /// Permits to use the old and new address as hints to relocate the mapping.
165        #[cfg(target_os = "netbsd")]
166        MAP_FIXED;
167        /// Allows to duplicate the mapping to be able to apply different flags on the copy.
168        #[cfg(target_os = "netbsd")]
169        MAP_REMAPDUP;
170    }
171}
172
173libc_enum!{
174    /// Usage information for a range of memory to allow for performance optimizations by the kernel.
175    ///
176    /// Used by [`madvise`].
177    #[repr(i32)]
178    #[non_exhaustive]
179    pub enum MmapAdvise {
180        /// No further special treatment. This is the default.
181        MADV_NORMAL,
182        /// Expect random page references.
183        MADV_RANDOM,
184        /// Expect sequential page references.
185        MADV_SEQUENTIAL,
186        /// Expect access in the near future.
187        MADV_WILLNEED,
188        /// Do not expect access in the near future.
189        MADV_DONTNEED,
190        /// Free up a given range of pages and its associated backing store.
191        #[cfg(any(target_os = "android", target_os = "linux"))]
192        MADV_REMOVE,
193        /// Do not make pages in this range available to the child after a `fork(2)`.
194        #[cfg(any(target_os = "android", target_os = "linux"))]
195        MADV_DONTFORK,
196        /// Undo the effect of `MADV_DONTFORK`.
197        #[cfg(any(target_os = "android", target_os = "linux"))]
198        MADV_DOFORK,
199        /// Poison the given pages.
200        ///
201        /// Subsequent references to those pages are treated like hardware memory corruption.
202        #[cfg(any(target_os = "android", target_os = "linux"))]
203        MADV_HWPOISON,
204        /// Enable Kernel Samepage Merging (KSM) for the given pages.
205        #[cfg(any(target_os = "android", target_os = "linux"))]
206        MADV_MERGEABLE,
207        /// Undo the effect of `MADV_MERGEABLE`
208        #[cfg(any(target_os = "android", target_os = "linux"))]
209        MADV_UNMERGEABLE,
210        /// Preserve the memory of each page but offline the original page.
211        #[cfg(any(target_os = "android",
212            all(target_os = "linux", any(
213                target_arch = "aarch64",
214                target_arch = "arm",
215                target_arch = "powerpc",
216                target_arch = "powerpc64",
217                target_arch = "s390x",
218                target_arch = "x86",
219                target_arch = "x86_64",
220                target_arch = "sparc64"))))]
221        MADV_SOFT_OFFLINE,
222        /// Enable Transparent Huge Pages (THP) for pages in the given range.
223        #[cfg(any(target_os = "android", target_os = "linux"))]
224        MADV_HUGEPAGE,
225        /// Undo the effect of `MADV_HUGEPAGE`.
226        #[cfg(any(target_os = "android", target_os = "linux"))]
227        MADV_NOHUGEPAGE,
228        /// Exclude the given range from a core dump.
229        #[cfg(any(target_os = "android", target_os = "linux"))]
230        MADV_DONTDUMP,
231        /// Undo the effect of an earlier `MADV_DONTDUMP`.
232        #[cfg(any(target_os = "android", target_os = "linux"))]
233        MADV_DODUMP,
234        /// Specify that the application no longer needs the pages in the given range.
235        MADV_FREE,
236        /// Request that the system not flush the current range to disk unless it needs to.
237        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
238        MADV_NOSYNC,
239        /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
240        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
241        MADV_AUTOSYNC,
242        /// Region is not included in a core file.
243        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
244        MADV_NOCORE,
245        /// Include region in a core file
246        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
247        MADV_CORE,
248        #[cfg(any(target_os = "freebsd"))]
249        MADV_PROTECT,
250        /// Invalidate the hardware page table for the given region.
251        #[cfg(target_os = "dragonfly")]
252        MADV_INVAL,
253        /// Set the offset of the page directory page to `value` for the virtual page table.
254        #[cfg(target_os = "dragonfly")]
255        MADV_SETMAP,
256        /// Indicates that the application will not need the data in the given range.
257        #[cfg(any(target_os = "ios", target_os = "macos"))]
258        MADV_ZERO_WIRED_PAGES,
259        #[cfg(any(target_os = "ios", target_os = "macos"))]
260        MADV_FREE_REUSABLE,
261        #[cfg(any(target_os = "ios", target_os = "macos"))]
262        MADV_FREE_REUSE,
263        #[cfg(any(target_os = "ios", target_os = "macos"))]
264        MADV_CAN_REUSE,
265    }
266}
267
268libc_bitflags!{
269    /// Configuration flags for [`msync`].
270    pub struct MsFlags: c_int {
271        /// Schedule an update but return immediately.
272        MS_ASYNC;
273        /// Invalidate all cached data.
274        MS_INVALIDATE;
275        /// Invalidate pages, but leave them mapped.
276        #[cfg(any(target_os = "ios", target_os = "macos"))]
277        MS_KILLPAGES;
278        /// Deactivate pages, but leave them mapped.
279        #[cfg(any(target_os = "ios", target_os = "macos"))]
280        MS_DEACTIVATE;
281        /// Perform an update and wait for it to complete.
282        MS_SYNC;
283    }
284}
285
286libc_bitflags!{
287    /// Flags for [`mlockall`].
288    pub struct MlockAllFlags: c_int {
289        /// Lock pages that are currently mapped into the address space of the process.
290        MCL_CURRENT;
291        /// Lock pages which will become mapped into the address space of the process in the future.
292        MCL_FUTURE;
293    }
294}
295
296/// Locks all memory pages that contain part of the address range with `length`
297/// bytes starting at `addr`.
298///
299/// Locked pages never move to the swap area.
300///
301/// # Safety
302///
303/// `addr` must meet all the requirements described in the [`mlock(2)`] man page.
304///
305/// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html
306pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
307    Errno::result(libc::mlock(addr, length)).map(drop)
308}
309
310/// Unlocks all memory pages that contain part of the address range with
311/// `length` bytes starting at `addr`.
312///
313/// # Safety
314///
315/// `addr` must meet all the requirements described in the [`munlock(2)`] man
316/// page.
317///
318/// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html
319pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
320    Errno::result(libc::munlock(addr, length)).map(drop)
321}
322
323/// Locks all memory pages mapped into this process' address space.
324///
325/// Locked pages never move to the swap area. For more information, see [`mlockall(2)`].
326///
327/// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html
328pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
329    unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
330}
331
332/// Unlocks all memory pages mapped into this process' address space.
333///
334/// For more information, see [`munlockall(2)`].
335///
336/// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html
337pub fn munlockall() -> Result<()> {
338    unsafe { Errno::result(libc::munlockall()) }.map(drop)
339}
340
341/// allocate memory, or map files or devices into memory
342///
343/// # Safety
344///
345/// See the [`mmap(2)`] man page for detailed requirements.
346///
347/// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html
348pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
349    let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
350
351    if ret == libc::MAP_FAILED {
352        Err(Errno::last())
353    } else {
354        Ok(ret)
355    }
356}
357
358/// Expands (or shrinks) an existing memory mapping, potentially moving it at
359/// the same time.
360///
361/// # Safety
362///
363/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
364/// detailed requirements.
365#[cfg(any(target_os = "linux", target_os = "netbsd"))]
366pub unsafe fn mremap(
367    addr: *mut c_void,
368    old_size: size_t,
369    new_size: size_t,
370    flags: MRemapFlags,
371    new_address: Option<* mut c_void>,
372) -> Result<*mut c_void> {
373    #[cfg(target_os = "linux")]
374    let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
375    #[cfg(target_os = "netbsd")]
376    let ret = libc::mremap(
377        addr,
378        old_size,
379        new_address.unwrap_or(std::ptr::null_mut()),
380        new_size,
381        flags.bits(),
382        );
383
384    if ret == libc::MAP_FAILED {
385        Err(Errno::last())
386    } else {
387        Ok(ret)
388    }
389}
390
391/// remove a mapping
392///
393/// # Safety
394///
395/// `addr` must meet all the requirements described in the [`munmap(2)`] man
396/// page.
397///
398/// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html
399pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
400    Errno::result(libc::munmap(addr, len)).map(drop)
401}
402
403/// give advice about use of memory
404///
405/// # Safety
406///
407/// See the [`madvise(2)`] man page.  Take special care when using
408/// [`MmapAdvise::MADV_FREE`].
409///
410/// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html
411pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
412    Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
413}
414
415/// Set protection of memory mapping.
416///
417/// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for
418/// details.
419///
420/// # Safety
421///
422/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to
423/// SIGSEGVs.
424///
425/// ```
426/// # use nix::libc::size_t;
427/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
428/// # use std::ptr;
429/// const ONE_K: size_t = 1024;
430/// let mut slice: &mut [u8] = unsafe {
431///     let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE,
432///                    MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
433///     mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
434///     std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
435/// };
436/// assert_eq!(slice[0], 0x00);
437/// slice[0] = 0xFF;
438/// assert_eq!(slice[0], 0xFF);
439/// ```
440pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> {
441    Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
442}
443
444/// synchronize a mapped region
445///
446/// # Safety
447///
448/// `addr` must meet all the requirements described in the [`msync(2)`] man
449/// page.
450///
451/// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html
452pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
453    Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
454}
455
456/// Creates and opens a new, or opens an existing, POSIX shared memory object.
457///
458/// For more information, see [`shm_open(3)`].
459///
460/// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html
461#[cfg(not(target_os = "android"))]
462pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
463    let ret = name.with_nix_path(|cstr| {
464        #[cfg(any(target_os = "macos", target_os = "ios"))]
465        unsafe {
466            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
467        }
468        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
469        unsafe {
470            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
471        }
472    })?;
473
474    Errno::result(ret)
475}
476
477/// Performs the converse of [`shm_open`], removing an object previously created.
478///
479/// For more information, see [`shm_unlink(3)`].
480///
481/// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html
482#[cfg(not(target_os = "android"))]
483pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
484    let ret = name.with_nix_path(|cstr| {
485        unsafe { libc::shm_unlink(cstr.as_ptr()) }
486    })?;
487
488    Errno::result(ret).map(drop)
489}