memmap2/
lib.rs

1#![deny(clippy::all, clippy::pedantic)]
2#![allow(
3    // pedantic exceptions
4    clippy::cast_possible_truncation,
5    clippy::cast_possible_wrap,
6    clippy::cast_sign_loss,
7    clippy::doc_markdown,
8    clippy::explicit_deref_methods,
9    clippy::missing_errors_doc,
10    clippy::module_name_repetitions,
11    clippy::must_use_candidate,
12    clippy::needless_pass_by_value,
13    clippy::return_self_not_must_use,
14    clippy::unreadable_literal,
15    clippy::upper_case_acronyms,
16)]
17
18//! A cross-platform Rust API for memory mapped buffers.
19//!
20//! The core functionality is provided by either [`Mmap`] or [`MmapMut`],
21//! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
22//! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
23//! respectively. Both function by dereferencing to a slice, allowing the
24//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice
25//! types.
26//!
27//! [`File`]: std::fs::File
28//!
29//! # Examples
30//!
31//! For simple cases [`Mmap`] can be used directly:
32//!
33//! ```
34//! use std::fs::File;
35//! use std::io::Read;
36//!
37//! use memmap2::Mmap;
38//!
39//! # fn main() -> std::io::Result<()> {
40//! let mut file = File::open("LICENSE-APACHE")?;
41//!
42//! let mut contents = Vec::new();
43//! file.read_to_end(&mut contents)?;
44//!
45//! let mmap = unsafe { Mmap::map(&file)?  };
46//!
47//! assert_eq!(&contents[..], &mmap[..]);
48//! # Ok(())
49//! # }
50//! ```
51//!
52//! However for cases which require configuration of the mapping, then
53//! you can use [`MmapOptions`] in order to further configure a mapping
54//! before you create it.
55
56#![allow(clippy::len_without_is_empty, clippy::missing_safety_doc)]
57
58#[cfg_attr(unix, path = "unix.rs")]
59#[cfg_attr(windows, path = "windows.rs")]
60#[cfg_attr(not(any(unix, windows)), path = "stub.rs")]
61mod os;
62use crate::os::{file_len, MmapInner};
63
64#[cfg(unix)]
65mod advice;
66#[cfg(unix)]
67pub use crate::advice::{Advice, UncheckedAdvice};
68
69use std::fmt;
70#[cfg(not(any(unix, windows)))]
71use std::fs::File;
72use std::io::{Error, ErrorKind, Result};
73use std::ops::{Deref, DerefMut};
74#[cfg(unix)]
75use std::os::unix::io::{AsRawFd, RawFd};
76#[cfg(windows)]
77use std::os::windows::io::{AsRawHandle, RawHandle};
78use std::slice;
79
80#[cfg(not(any(unix, windows)))]
81pub struct MmapRawDescriptor<'a>(&'a File);
82
83#[cfg(unix)]
84pub struct MmapRawDescriptor(RawFd);
85
86#[cfg(windows)]
87pub struct MmapRawDescriptor(RawHandle);
88
89pub trait MmapAsRawDesc {
90    fn as_raw_desc(&self) -> MmapRawDescriptor;
91}
92
93#[cfg(not(any(unix, windows)))]
94impl MmapAsRawDesc for &File {
95    fn as_raw_desc(&self) -> MmapRawDescriptor {
96        MmapRawDescriptor(self)
97    }
98}
99
100#[cfg(unix)]
101impl MmapAsRawDesc for RawFd {
102    fn as_raw_desc(&self) -> MmapRawDescriptor {
103        MmapRawDescriptor(*self)
104    }
105}
106
107#[cfg(unix)]
108impl<T> MmapAsRawDesc for &T
109where
110    T: AsRawFd,
111{
112    fn as_raw_desc(&self) -> MmapRawDescriptor {
113        MmapRawDescriptor(self.as_raw_fd())
114    }
115}
116
117#[cfg(windows)]
118impl MmapAsRawDesc for RawHandle {
119    fn as_raw_desc(&self) -> MmapRawDescriptor {
120        MmapRawDescriptor(*self)
121    }
122}
123
124#[cfg(windows)]
125impl<T> MmapAsRawDesc for &T
126where
127    T: AsRawHandle,
128{
129    fn as_raw_desc(&self) -> MmapRawDescriptor {
130        MmapRawDescriptor(self.as_raw_handle())
131    }
132}
133
134/// A memory map builder, providing advanced options and flags for specifying memory map behavior.
135///
136/// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a
137/// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`],
138/// [`map_copy()`], or [`map_copy_read_only()`].
139///
140/// ## Safety
141///
142/// All file-backed memory map constructors are marked `unsafe` because of the potential for
143/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
144/// out of process. Applications must consider the risk and take appropriate precautions when
145/// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g.
146/// unlinked) files exist but are platform specific and limited.
147///
148/// [`map_anon()`]: MmapOptions::map_anon()
149/// [`map()`]: MmapOptions::map()
150/// [`map_mut()`]: MmapOptions::map_mut()
151/// [`map_exec()`]: MmapOptions::map_exec()
152/// [`map_copy()`]: MmapOptions::map_copy()
153/// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only()
154#[derive(Clone, Debug, Default)]
155pub struct MmapOptions {
156    offset: u64,
157    len: Option<usize>,
158    huge: Option<u8>,
159    stack: bool,
160    populate: bool,
161    no_reserve_swap: bool,
162}
163
164impl MmapOptions {
165    /// Creates a new set of options for configuring and creating a memory map.
166    ///
167    /// # Example
168    ///
169    /// ```
170    /// use memmap2::{MmapMut, MmapOptions};
171    /// # use std::io::Result;
172    ///
173    /// # fn main() -> Result<()> {
174    /// // Create a new memory map builder.
175    /// let mut mmap_options = MmapOptions::new();
176    ///
177    /// // Configure the memory map builder using option setters, then create
178    /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`,
179    /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`:
180    /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?;
181    ///
182    /// // Use the memory map:
183    /// mmap.copy_from_slice(b"...data to copy to the memory map...");
184    /// # Ok(())
185    /// # }
186    /// ```
187    pub fn new() -> MmapOptions {
188        MmapOptions::default()
189    }
190
191    /// Configures the memory map to start at byte `offset` from the beginning of the file.
192    ///
193    /// This option has no effect on anonymous memory maps.
194    ///
195    /// By default, the offset is 0.
196    ///
197    /// # Example
198    ///
199    /// ```
200    /// use memmap2::MmapOptions;
201    /// use std::fs::File;
202    ///
203    /// # fn main() -> std::io::Result<()> {
204    /// let mmap = unsafe {
205    ///     MmapOptions::new()
206    ///                 .offset(30)
207    ///                 .map(&File::open("LICENSE-APACHE")?)?
208    /// };
209    /// assert_eq!(&b"Apache License"[..],
210    ///            &mmap[..14]);
211    /// # Ok(())
212    /// # }
213    /// ```
214    pub fn offset(&mut self, offset: u64) -> &mut Self {
215        self.offset = offset;
216        self
217    }
218
219    /// Configures the created memory mapped buffer to be `len` bytes long.
220    ///
221    /// This option is mandatory for anonymous memory maps.
222    ///
223    /// For file-backed memory maps, the length will default to the file length.
224    ///
225    /// # Example
226    ///
227    /// ```
228    /// use memmap2::MmapOptions;
229    /// use std::fs::File;
230    ///
231    /// # fn main() -> std::io::Result<()> {
232    /// let mmap = unsafe {
233    ///     MmapOptions::new()
234    ///                 .len(9)
235    ///                 .map(&File::open("README.md")?)?
236    /// };
237    /// assert_eq!(&b"# memmap2"[..], &mmap[..]);
238    /// # Ok(())
239    /// # }
240    /// ```
241    pub fn len(&mut self, len: usize) -> &mut Self {
242        self.len = Some(len);
243        self
244    }
245
246    fn validate_len(len: u64) -> Result<usize> {
247        // Rust's slice cannot be larger than isize::MAX.
248        // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
249        //
250        // This is not a problem on 64-bit targets, but on 32-bit one
251        // having a file or an anonymous mapping larger than 2GB is quite normal
252        // and we have to prevent it.
253        //
254        // The code below is essentially the same as in Rust's std:
255        // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495
256        if len > isize::MAX as u64 {
257            return Err(Error::new(
258                ErrorKind::InvalidData,
259                "memory map length overflows isize",
260            ));
261        }
262
263        Ok(len as usize)
264    }
265
266    /// Returns the configured length, or the length of the provided file.
267    fn get_len<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize> {
268        let len = if let Some(len) = self.len {
269            len as u64
270        } else {
271            let desc = file.as_raw_desc();
272            let file_len = file_len(desc.0)?;
273
274            if file_len < self.offset {
275                return Err(Error::new(
276                    ErrorKind::InvalidData,
277                    "memory map offset is larger than length",
278                ));
279            }
280
281            file_len - self.offset
282        };
283        Self::validate_len(len)
284    }
285
286    /// Configures the anonymous memory map to be suitable for a process or thread stack.
287    ///
288    /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows.
289    ///
290    /// This option has no effect on file-backed memory maps.
291    ///
292    /// # Example
293    ///
294    /// ```
295    /// use memmap2::MmapOptions;
296    ///
297    /// # fn main() -> std::io::Result<()> {
298    /// let stack = MmapOptions::new().stack().len(4096).map_anon();
299    /// # Ok(())
300    /// # }
301    /// ```
302    pub fn stack(&mut self) -> &mut Self {
303        self.stack = true;
304        self
305    }
306
307    /// Configures the anonymous memory map to be allocated using huge pages.
308    ///
309    /// This option corresponds to the `MAP_HUGETLB` flag on Linux. It has no effect on Windows.
310    ///
311    /// The size of the requested page can be specified in page bits. If not provided, the system
312    /// default is requested. The requested length should be a multiple of this, or the mapping
313    /// will fail.
314    ///
315    /// This option has no effect on file-backed memory maps.
316    ///
317    /// # Example
318    ///
319    /// ```
320    /// use memmap2::MmapOptions;
321    ///
322    /// # fn main() -> std::io::Result<()> {
323    /// let stack = MmapOptions::new().huge(Some(21)).len(2*1024*1024).map_anon();
324    /// # Ok(())
325    /// # }
326    /// ```
327    ///
328    /// The number 21 corresponds to `MAP_HUGE_2MB`. See mmap(2) for more details.
329    pub fn huge(&mut self, page_bits: Option<u8>) -> &mut Self {
330        self.huge = Some(page_bits.unwrap_or(0));
331        self
332    }
333
334    /// Populate (prefault) page tables for a mapping.
335    ///
336    /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later.
337    ///
338    /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows.
339    ///
340    /// # Example
341    ///
342    /// ```
343    /// use memmap2::MmapOptions;
344    /// use std::fs::File;
345    ///
346    /// # fn main() -> std::io::Result<()> {
347    /// let file = File::open("LICENSE-MIT")?;
348    ///
349    /// let mmap = unsafe {
350    ///     MmapOptions::new().populate().map(&file)?
351    /// };
352    ///
353    /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
354    /// # Ok(())
355    /// # }
356    /// ```
357    pub fn populate(&mut self) -> &mut Self {
358        self.populate = true;
359        self
360    }
361
362    /// Do not reserve swap space for the memory map.
363    ///
364    /// By default, platforms may reserve swap space for memory maps.
365    /// This guarantees that a write to the mapped memory will succeed, even if physical memory is exhausted.
366    /// Otherwise, the write to memory could fail (on Linux with a segfault).
367    ///
368    /// This option requests that no swap space will be allocated for the memory map,
369    /// which can be useful for extremely large maps that are only written to sparsely.
370    ///
371    /// This option is currently supported on Linux, Android, macOS, iOS, NetBSD, Solaris and Illumos.
372    /// On those platforms, this option corresponds to the `MAP_NORESERVE` flag.
373    /// On Linux, this option is ignored if [`vm.overcommit_memory`](https://www.kernel.org/doc/Documentation/vm/overcommit-accounting) is set to 2.
374    ///
375    /// # Example
376    ///
377    /// ```
378    /// use memmap2::MmapOptions;
379    /// use std::fs::File;
380    ///
381    /// # fn main() -> std::io::Result<()> {
382    /// let file = File::open("LICENSE-MIT")?;
383    ///
384    /// let mmap = unsafe {
385    ///     MmapOptions::new().no_reserve_swap().map_copy(&file)?
386    /// };
387    ///
388    /// assert_eq!(&b"Copyright"[..], &mmap[..9]);
389    /// # Ok(())
390    /// # }
391    /// ```
392    pub fn no_reserve_swap(&mut self) -> &mut Self {
393        self.no_reserve_swap = true;
394        self
395    }
396
397    /// Creates a read-only memory map backed by a file.
398    ///
399    /// # Safety
400    ///
401    /// See the [type-level][MmapOptions] docs for why this function is unsafe.
402    ///
403    /// # Errors
404    ///
405    /// This method returns an error when the underlying system call fails, which can happen for a
406    /// variety of reasons, such as when the file is not open with read permissions.
407    ///
408    /// # Example
409    ///
410    /// ```
411    /// use memmap2::MmapOptions;
412    /// use std::fs::File;
413    /// use std::io::Read;
414    ///
415    /// # fn main() -> std::io::Result<()> {
416    /// let mut file = File::open("LICENSE-APACHE")?;
417    ///
418    /// let mut contents = Vec::new();
419    /// file.read_to_end(&mut contents)?;
420    ///
421    /// let mmap = unsafe {
422    ///     MmapOptions::new().map(&file)?
423    /// };
424    ///
425    /// assert_eq!(&contents[..], &mmap[..]);
426    /// # Ok(())
427    /// # }
428    /// ```
429    pub unsafe fn map<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
430        let desc = file.as_raw_desc();
431
432        MmapInner::map(
433            self.get_len(&file)?,
434            desc.0,
435            self.offset,
436            self.populate,
437            self.no_reserve_swap,
438        )
439        .map(|inner| Mmap { inner })
440    }
441
442    /// Creates a readable and executable memory map backed by a file.
443    ///
444    /// # Safety
445    ///
446    /// See the [type-level][MmapOptions] docs for why this function is unsafe.
447    ///
448    /// # Errors
449    ///
450    /// This method returns an error when the underlying system call fails, which can happen for a
451    /// variety of reasons, such as when the file is not open with read permissions.
452    pub unsafe fn map_exec<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
453        let desc = file.as_raw_desc();
454
455        MmapInner::map_exec(
456            self.get_len(&file)?,
457            desc.0,
458            self.offset,
459            self.populate,
460            self.no_reserve_swap,
461        )
462        .map(|inner| Mmap { inner })
463    }
464
465    /// Creates a writeable memory map backed by a file.
466    ///
467    /// # Safety
468    ///
469    /// See the [type-level][MmapOptions] docs for why this function is unsafe.
470    ///
471    /// # Errors
472    ///
473    /// This method returns an error when the underlying system call fails, which can happen for a
474    /// variety of reasons, such as when the file is not open with read and write permissions.
475    ///
476    /// # Example
477    ///
478    /// ```
479    /// use std::fs::OpenOptions;
480    /// use std::path::PathBuf;
481    ///
482    /// use memmap2::MmapOptions;
483    /// #
484    /// # fn main() -> std::io::Result<()> {
485    /// # let tempdir = tempfile::tempdir()?;
486    /// let path: PathBuf = /* path to file */
487    /// #   tempdir.path().join("map_mut");
488    /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
489    /// file.set_len(13)?;
490    ///
491    /// let mut mmap = unsafe {
492    ///     MmapOptions::new().map_mut(&file)?
493    /// };
494    ///
495    /// mmap.copy_from_slice(b"Hello, world!");
496    /// # Ok(())
497    /// # }
498    /// ```
499    pub unsafe fn map_mut<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> {
500        let desc = file.as_raw_desc();
501
502        MmapInner::map_mut(
503            self.get_len(&file)?,
504            desc.0,
505            self.offset,
506            self.populate,
507            self.no_reserve_swap,
508        )
509        .map(|inner| MmapMut { inner })
510    }
511
512    /// Creates a copy-on-write memory map backed by a file.
513    ///
514    /// Data written to the memory map will not be visible by other processes,
515    /// and will not be carried through to the underlying file.
516    ///
517    /// # Safety
518    ///
519    /// See the [type-level][MmapOptions] docs for why this function is unsafe.
520    ///
521    /// # Errors
522    ///
523    /// This method returns an error when the underlying system call fails, which can happen for a
524    /// variety of reasons, such as when the file is not open with writable permissions.
525    ///
526    /// # Example
527    ///
528    /// ```
529    /// use memmap2::MmapOptions;
530    /// use std::fs::File;
531    /// use std::io::Write;
532    ///
533    /// # fn main() -> std::io::Result<()> {
534    /// let file = File::open("LICENSE-APACHE")?;
535    /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? };
536    /// (&mut mmap[..]).write_all(b"Hello, world!")?;
537    /// # Ok(())
538    /// # }
539    /// ```
540    pub unsafe fn map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> {
541        let desc = file.as_raw_desc();
542
543        MmapInner::map_copy(
544            self.get_len(&file)?,
545            desc.0,
546            self.offset,
547            self.populate,
548            self.no_reserve_swap,
549        )
550        .map(|inner| MmapMut { inner })
551    }
552
553    /// Creates a copy-on-write read-only memory map backed by a file.
554    ///
555    /// # Safety
556    ///
557    /// See the [type-level][MmapOptions] docs for why this function is unsafe.
558    ///
559    /// # Errors
560    ///
561    /// This method returns an error when the underlying system call fails, which can happen for a
562    /// variety of reasons, such as when the file is not open with read permissions.
563    ///
564    /// # Example
565    ///
566    /// ```
567    /// use memmap2::MmapOptions;
568    /// use std::fs::File;
569    /// use std::io::Read;
570    ///
571    /// # fn main() -> std::io::Result<()> {
572    /// let mut file = File::open("README.md")?;
573    ///
574    /// let mut contents = Vec::new();
575    /// file.read_to_end(&mut contents)?;
576    ///
577    /// let mmap = unsafe {
578    ///     MmapOptions::new().map_copy_read_only(&file)?
579    /// };
580    ///
581    /// assert_eq!(&contents[..], &mmap[..]);
582    /// # Ok(())
583    /// # }
584    /// ```
585    pub unsafe fn map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> {
586        let desc = file.as_raw_desc();
587
588        MmapInner::map_copy_read_only(
589            self.get_len(&file)?,
590            desc.0,
591            self.offset,
592            self.populate,
593            self.no_reserve_swap,
594        )
595        .map(|inner| Mmap { inner })
596    }
597
598    /// Creates an anonymous memory map.
599    ///
600    /// The memory map length should be configured using [`MmapOptions::len()`]
601    /// before creating an anonymous memory map, otherwise a zero-length mapping
602    /// will be crated.
603    ///
604    /// # Errors
605    ///
606    /// This method returns an error when the underlying system call fails or
607    /// when `len > isize::MAX`.
608    pub fn map_anon(&self) -> Result<MmapMut> {
609        let len = self.len.unwrap_or(0);
610
611        // See get_len() for details.
612        let len = Self::validate_len(len as u64)?;
613
614        MmapInner::map_anon(
615            len,
616            self.stack,
617            self.populate,
618            self.huge,
619            self.no_reserve_swap,
620        )
621        .map(|inner| MmapMut { inner })
622    }
623
624    /// Creates a raw memory map.
625    ///
626    /// # Errors
627    ///
628    /// This method returns an error when the underlying system call fails, which can happen for a
629    /// variety of reasons, such as when the file is not open with read and write permissions.
630    pub fn map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> {
631        let desc = file.as_raw_desc();
632
633        MmapInner::map_mut(
634            self.get_len(&file)?,
635            desc.0,
636            self.offset,
637            self.populate,
638            self.no_reserve_swap,
639        )
640        .map(|inner| MmapRaw { inner })
641    }
642
643    /// Creates a read-only raw memory map
644    ///
645    /// This is primarily useful to avoid intermediate `Mmap` instances when
646    /// read-only access to files modified elsewhere are required.
647    ///
648    /// # Errors
649    ///
650    /// This method returns an error when the underlying system call fails
651    pub fn map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> {
652        let desc = file.as_raw_desc();
653
654        MmapInner::map(
655            self.get_len(&file)?,
656            desc.0,
657            self.offset,
658            self.populate,
659            self.no_reserve_swap,
660        )
661        .map(|inner| MmapRaw { inner })
662    }
663}
664
665/// A handle to an immutable memory mapped buffer.
666///
667/// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use
668/// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable
669/// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable
670/// with [`MmapMut::make_read_only()`].
671///
672/// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the
673/// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File`
674/// used to create it. For consistency, on some platforms this is achieved by duplicating the
675/// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped.
676///
677/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
678/// the mapped pages into physical memory) though the details of this are platform specific.
679///
680/// `Mmap` is [`Sync`] and [`Send`].
681///
682/// See [`MmapMut`] for the mutable version.
683///
684/// ## Safety
685///
686/// All file-backed memory map constructors are marked `unsafe` because of the potential for
687/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
688/// out of process. Applications must consider the risk and take appropriate precautions when using
689/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
690/// files exist but are platform specific and limited.
691///
692/// ## Example
693///
694/// ```
695/// use memmap2::MmapOptions;
696/// use std::io::Write;
697/// use std::fs::File;
698///
699/// # fn main() -> std::io::Result<()> {
700/// let file = File::open("README.md")?;
701/// let mmap = unsafe { MmapOptions::new().map(&file)? };
702/// assert_eq!(b"# memmap2", &mmap[0..9]);
703/// # Ok(())
704/// # }
705/// ```
706///
707/// [`map()`]: Mmap::map()
708pub struct Mmap {
709    inner: MmapInner,
710}
711
712impl Mmap {
713    /// Creates a read-only memory map backed by a file.
714    ///
715    /// This is equivalent to calling `MmapOptions::new().map(file)`.
716    ///
717    /// # Safety
718    ///
719    /// See the [type-level][Mmap] docs for why this function is unsafe.
720    ///
721    /// # Errors
722    ///
723    /// This method returns an error when the underlying system call fails, which can happen for a
724    /// variety of reasons, such as when the file is not open with read permissions.
725    ///
726    /// # Example
727    ///
728    /// ```
729    /// use std::fs::File;
730    /// use std::io::Read;
731    ///
732    /// use memmap2::Mmap;
733    ///
734    /// # fn main() -> std::io::Result<()> {
735    /// let mut file = File::open("LICENSE-APACHE")?;
736    ///
737    /// let mut contents = Vec::new();
738    /// file.read_to_end(&mut contents)?;
739    ///
740    /// let mmap = unsafe { Mmap::map(&file)?  };
741    ///
742    /// assert_eq!(&contents[..], &mmap[..]);
743    /// # Ok(())
744    /// # }
745    /// ```
746    pub unsafe fn map<T: MmapAsRawDesc>(file: T) -> Result<Mmap> {
747        MmapOptions::new().map(file)
748    }
749
750    /// Transition the memory map to be writable.
751    ///
752    /// If the memory map is file-backed, the file must have been opened with write permissions.
753    ///
754    /// # Errors
755    ///
756    /// This method returns an error when the underlying system call fails, which can happen for a
757    /// variety of reasons, such as when the file is not open with writable permissions.
758    ///
759    /// # Example
760    ///
761    /// ```
762    /// use memmap2::Mmap;
763    /// use std::ops::DerefMut;
764    /// use std::io::Write;
765    /// # use std::fs::OpenOptions;
766    ///
767    /// # fn main() -> std::io::Result<()> {
768    /// # let tempdir = tempfile::tempdir()?;
769    /// let file = /* file opened with write permissions */
770    /// #          OpenOptions::new()
771    /// #                      .read(true)
772    /// #                      .write(true)
773    /// #                      .create(true)
774    /// #                      .truncate(true)
775    /// #                      .open(tempdir.path()
776    /// #                      .join("make_mut"))?;
777    /// # file.set_len(128)?;
778    /// let mmap = unsafe { Mmap::map(&file)? };
779    /// // ... use the read-only memory map ...
780    /// let mut mut_mmap = mmap.make_mut()?;
781    /// mut_mmap.deref_mut().write_all(b"hello, world!")?;
782    /// # Ok(())
783    /// # }
784    /// ```
785    pub fn make_mut(mut self) -> Result<MmapMut> {
786        self.inner.make_mut()?;
787        Ok(MmapMut { inner: self.inner })
788    }
789
790    /// Advise OS how this memory map will be accessed.
791    ///
792    /// Only supported on Unix.
793    ///
794    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
795    #[cfg(unix)]
796    pub fn advise(&self, advice: Advice) -> Result<()> {
797        self.inner
798            .advise(advice as libc::c_int, 0, self.inner.len())
799    }
800
801    /// Advise OS how this memory map will be accessed.
802    ///
803    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
804    ///
805    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
806    #[cfg(unix)]
807    pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> {
808        self.inner
809            .advise(advice as libc::c_int, 0, self.inner.len())
810    }
811
812    /// Advise OS how this range of memory map will be accessed.
813    ///
814    /// Only supported on Unix.
815    ///
816    /// The offset and length must be in the bounds of the memory map.
817    ///
818    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
819    #[cfg(unix)]
820    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
821        self.inner.advise(advice as libc::c_int, offset, len)
822    }
823
824    /// Advise OS how this range of memory map will be accessed.
825    ///
826    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
827    ///
828    /// The offset and length must be in the bounds of the memory map.
829    ///
830    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
831    #[cfg(unix)]
832    pub unsafe fn unchecked_advise_range(
833        &self,
834        advice: UncheckedAdvice,
835        offset: usize,
836        len: usize,
837    ) -> Result<()> {
838        self.inner.advise(advice as libc::c_int, offset, len)
839    }
840
841    /// Lock the whole memory map into RAM. Only supported on Unix.
842    ///
843    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
844    #[cfg(unix)]
845    pub fn lock(&self) -> Result<()> {
846        self.inner.lock()
847    }
848
849    /// Unlock the whole memory map. Only supported on Unix.
850    ///
851    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
852    #[cfg(unix)]
853    pub fn unlock(&self) -> Result<()> {
854        self.inner.unlock()
855    }
856
857    /// Adjust the size of the memory mapping.
858    ///
859    /// This will try to resize the memory mapping in place. If
860    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
861    /// could not resize in place, otherwise it will error.
862    ///
863    /// Only supported on Linux.
864    ///
865    /// See the [`mremap(2)`] man page.
866    ///
867    /// # Safety
868    ///
869    /// Resizing the memory mapping beyond the end of the mapped file will
870    /// result in UB should you happen to access memory beyond the end of the
871    /// file.
872    ///
873    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
874    #[cfg(target_os = "linux")]
875    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
876        self.inner.remap(new_len, options)
877    }
878}
879
880#[cfg(feature = "stable_deref_trait")]
881unsafe impl stable_deref_trait::StableDeref for Mmap {}
882
883impl Deref for Mmap {
884    type Target = [u8];
885
886    #[inline]
887    fn deref(&self) -> &[u8] {
888        unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
889    }
890}
891
892impl AsRef<[u8]> for Mmap {
893    #[inline]
894    fn as_ref(&self) -> &[u8] {
895        self.deref()
896    }
897}
898
899impl fmt::Debug for Mmap {
900    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
901        fmt.debug_struct("Mmap")
902            .field("ptr", &self.as_ptr())
903            .field("len", &self.len())
904            .finish()
905    }
906}
907
908/// A handle to a raw memory mapped buffer.
909///
910/// This struct never hands out references to its interior, only raw pointers.
911/// This can be helpful when creating shared memory maps between untrusted processes.
912///
913/// For the safety concerns that arise when converting these raw pointers to references,
914/// see the [`Mmap`] safety documentation.
915pub struct MmapRaw {
916    inner: MmapInner,
917}
918
919impl MmapRaw {
920    /// Creates a writeable memory map backed by a file.
921    ///
922    /// This is equivalent to calling `MmapOptions::new().map_raw(file)`.
923    ///
924    /// # Errors
925    ///
926    /// This method returns an error when the underlying system call fails, which can happen for a
927    /// variety of reasons, such as when the file is not open with read and write permissions.
928    pub fn map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw> {
929        MmapOptions::new().map_raw(file)
930    }
931
932    /// Returns a raw pointer to the memory mapped file.
933    ///
934    /// Before dereferencing this pointer, you have to make sure that the file has not been
935    /// truncated since the memory map was created.
936    /// Avoiding this will not introduce memory safety issues in Rust terms,
937    /// but will cause SIGBUS (or equivalent) signal.
938    #[inline]
939    pub fn as_ptr(&self) -> *const u8 {
940        self.inner.ptr()
941    }
942
943    /// Returns an unsafe mutable pointer to the memory mapped file.
944    ///
945    /// Before dereferencing this pointer, you have to make sure that the file has not been
946    /// truncated since the memory map was created.
947    /// Avoiding this will not introduce memory safety issues in Rust terms,
948    /// but will cause SIGBUS (or equivalent) signal.
949    #[inline]
950    pub fn as_mut_ptr(&self) -> *mut u8 {
951        self.inner.ptr() as *mut u8
952    }
953
954    /// Returns the length in bytes of the memory map.
955    ///
956    /// Note that truncating the file can cause the length to change (and render this value unusable).
957    #[inline]
958    pub fn len(&self) -> usize {
959        self.inner.len()
960    }
961
962    /// Flushes outstanding memory map modifications to disk.
963    ///
964    /// When this method returns with a non-error result, all outstanding changes to a file-backed
965    /// memory map are guaranteed to be durably stored. The file's metadata (including last
966    /// modification timestamp) may not be updated.
967    ///
968    /// # Example
969    ///
970    /// ```
971    /// use std::fs::OpenOptions;
972    /// use std::io::Write;
973    /// use std::path::PathBuf;
974    /// use std::slice;
975    ///
976    /// use memmap2::MmapRaw;
977    ///
978    /// # fn main() -> std::io::Result<()> {
979    /// let tempdir = tempfile::tempdir()?;
980    /// let path: PathBuf = /* path to file */
981    /// #   tempdir.path().join("flush");
982    /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
983    /// file.set_len(128)?;
984    ///
985    /// let mut mmap = unsafe { MmapRaw::map_raw(&file)? };
986    ///
987    /// let mut memory = unsafe { slice::from_raw_parts_mut(mmap.as_mut_ptr(), 128) };
988    /// memory.write_all(b"Hello, world!")?;
989    /// mmap.flush()?;
990    /// # Ok(())
991    /// # }
992    /// ```
993    pub fn flush(&self) -> Result<()> {
994        let len = self.len();
995        self.inner.flush(0, len)
996    }
997
998    /// Asynchronously flushes outstanding memory map modifications to disk.
999    ///
1000    /// This method initiates flushing modified pages to durable storage, but it will not wait for
1001    /// the operation to complete before returning. The file's metadata (including last
1002    /// modification timestamp) may not be updated.
1003    pub fn flush_async(&self) -> Result<()> {
1004        let len = self.len();
1005        self.inner.flush_async(0, len)
1006    }
1007
1008    /// Flushes outstanding memory map modifications in the range to disk.
1009    ///
1010    /// The offset and length must be in the bounds of the memory map.
1011    ///
1012    /// When this method returns with a non-error result, all outstanding changes to a file-backed
1013    /// memory in the range are guaranteed to be durable stored. The file's metadata (including
1014    /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
1015    /// in the specified range are flushed; other outstanding changes to the memory map may be
1016    /// flushed as well.
1017    pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> {
1018        self.inner.flush(offset, len)
1019    }
1020
1021    /// Asynchronously flushes outstanding memory map modifications in the range to disk.
1022    ///
1023    /// The offset and length must be in the bounds of the memory map.
1024    ///
1025    /// This method initiates flushing modified pages to durable storage, but it will not wait for
1026    /// the operation to complete before returning. The file's metadata (including last
1027    /// modification timestamp) may not be updated. It is not guaranteed that the only changes
1028    /// flushed are those in the specified range; other outstanding changes to the memory map may
1029    /// be flushed as well.
1030    pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> {
1031        self.inner.flush_async(offset, len)
1032    }
1033
1034    /// Advise OS how this memory map will be accessed.
1035    ///
1036    /// Only supported on Unix.
1037    ///
1038    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1039    #[cfg(unix)]
1040    pub fn advise(&self, advice: Advice) -> Result<()> {
1041        self.inner
1042            .advise(advice as libc::c_int, 0, self.inner.len())
1043    }
1044
1045    /// Advise OS how this memory map will be accessed.
1046    ///
1047    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1048    ///
1049    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1050    #[cfg(unix)]
1051    pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> {
1052        self.inner
1053            .advise(advice as libc::c_int, 0, self.inner.len())
1054    }
1055
1056    /// Advise OS how this range of memory map will be accessed.
1057    ///
1058    /// The offset and length must be in the bounds of the memory map.
1059    ///
1060    /// Only supported on Unix.
1061    ///
1062    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1063    #[cfg(unix)]
1064    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
1065        self.inner.advise(advice as libc::c_int, offset, len)
1066    }
1067
1068    /// Advise OS how this range of memory map will be accessed.
1069    ///
1070    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1071    ///
1072    /// The offset and length must be in the bounds of the memory map.
1073    ///
1074    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1075    #[cfg(unix)]
1076    pub unsafe fn unchecked_advise_range(
1077        &self,
1078        advice: UncheckedAdvice,
1079        offset: usize,
1080        len: usize,
1081    ) -> Result<()> {
1082        self.inner.advise(advice as libc::c_int, offset, len)
1083    }
1084
1085    /// Lock the whole memory map into RAM. Only supported on Unix.
1086    ///
1087    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
1088    #[cfg(unix)]
1089    pub fn lock(&self) -> Result<()> {
1090        self.inner.lock()
1091    }
1092
1093    /// Unlock the whole memory map. Only supported on Unix.
1094    ///
1095    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
1096    #[cfg(unix)]
1097    pub fn unlock(&self) -> Result<()> {
1098        self.inner.unlock()
1099    }
1100
1101    /// Adjust the size of the memory mapping.
1102    ///
1103    /// This will try to resize the memory mapping in place. If
1104    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
1105    /// could not resize in place, otherwise it will error.
1106    ///
1107    /// Only supported on Linux.
1108    ///
1109    /// See the [`mremap(2)`] man page.
1110    ///
1111    /// # Safety
1112    ///
1113    /// Resizing the memory mapping beyond the end of the mapped file will
1114    /// result in UB should you happen to access memory beyond the end of the
1115    /// file.
1116    ///
1117    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
1118    #[cfg(target_os = "linux")]
1119    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
1120        self.inner.remap(new_len, options)
1121    }
1122}
1123
1124impl fmt::Debug for MmapRaw {
1125    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1126        fmt.debug_struct("MmapRaw")
1127            .field("ptr", &self.as_ptr())
1128            .field("len", &self.len())
1129            .finish()
1130    }
1131}
1132
1133impl From<Mmap> for MmapRaw {
1134    fn from(value: Mmap) -> Self {
1135        Self { inner: value.inner }
1136    }
1137}
1138
1139impl From<MmapMut> for MmapRaw {
1140    fn from(value: MmapMut) -> Self {
1141        Self { inner: value.inner }
1142    }
1143}
1144
1145/// A handle to a mutable memory mapped buffer.
1146///
1147/// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous
1148/// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use
1149/// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the
1150/// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default
1151/// options are required.
1152///
1153/// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the
1154/// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File`
1155/// used to create it. For consistency, on some platforms this is achieved by duplicating the
1156/// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped.
1157///
1158/// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping
1159/// the mapped pages into physical memory) though the details of this are platform specific.
1160///
1161/// `MmapMut` is [`Sync`] and [`Send`].
1162///
1163/// See [`Mmap`] for the immutable version.
1164///
1165/// ## Safety
1166///
1167/// All file-backed memory map constructors are marked `unsafe` because of the potential for
1168/// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or
1169/// out of process. Applications must consider the risk and take appropriate precautions when using
1170/// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked)
1171/// files exist but are platform specific and limited.
1172pub struct MmapMut {
1173    inner: MmapInner,
1174}
1175
1176impl MmapMut {
1177    /// Creates a writeable memory map backed by a file.
1178    ///
1179    /// This is equivalent to calling `MmapOptions::new().map_mut(file)`.
1180    ///
1181    /// # Safety
1182    ///
1183    /// See the [type-level][MmapMut] docs for why this function is unsafe.
1184    ///
1185    /// # Errors
1186    ///
1187    /// This method returns an error when the underlying system call fails, which can happen for a
1188    /// variety of reasons, such as when the file is not open with read and write permissions.
1189    ///
1190    /// # Example
1191    ///
1192    /// ```
1193    /// use std::fs::OpenOptions;
1194    /// use std::path::PathBuf;
1195    ///
1196    /// use memmap2::MmapMut;
1197    /// #
1198    /// # fn main() -> std::io::Result<()> {
1199    /// # let tempdir = tempfile::tempdir()?;
1200    /// let path: PathBuf = /* path to file */
1201    /// #   tempdir.path().join("map_mut");
1202    /// let file = OpenOptions::new()
1203    ///                        .read(true)
1204    ///                        .write(true)
1205    ///                        .create(true)
1206    ///                        .truncate(true)
1207    ///                        .open(&path)?;
1208    /// file.set_len(13)?;
1209    ///
1210    /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
1211    ///
1212    /// mmap.copy_from_slice(b"Hello, world!");
1213    /// # Ok(())
1214    /// # }
1215    /// ```
1216    pub unsafe fn map_mut<T: MmapAsRawDesc>(file: T) -> Result<MmapMut> {
1217        MmapOptions::new().map_mut(file)
1218    }
1219
1220    /// Creates an anonymous memory map.
1221    ///
1222    /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`.
1223    ///
1224    /// # Errors
1225    ///
1226    /// This method returns an error when the underlying system call fails or
1227    /// when `len > isize::MAX`.
1228    pub fn map_anon(length: usize) -> Result<MmapMut> {
1229        MmapOptions::new().len(length).map_anon()
1230    }
1231
1232    /// Flushes outstanding memory map modifications to disk.
1233    ///
1234    /// When this method returns with a non-error result, all outstanding changes to a file-backed
1235    /// memory map are guaranteed to be durably stored. The file's metadata (including last
1236    /// modification timestamp) may not be updated.
1237    ///
1238    /// # Example
1239    ///
1240    /// ```
1241    /// use std::fs::OpenOptions;
1242    /// use std::io::Write;
1243    /// use std::path::PathBuf;
1244    ///
1245    /// use memmap2::MmapMut;
1246    ///
1247    /// # fn main() -> std::io::Result<()> {
1248    /// # let tempdir = tempfile::tempdir()?;
1249    /// let path: PathBuf = /* path to file */
1250    /// #   tempdir.path().join("flush");
1251    /// let file = OpenOptions::new().read(true).write(true).create(true).truncate(true).open(&path)?;
1252    /// file.set_len(128)?;
1253    ///
1254    /// let mut mmap = unsafe { MmapMut::map_mut(&file)? };
1255    ///
1256    /// (&mut mmap[..]).write_all(b"Hello, world!")?;
1257    /// mmap.flush()?;
1258    /// # Ok(())
1259    /// # }
1260    /// ```
1261    pub fn flush(&self) -> Result<()> {
1262        let len = self.len();
1263        self.inner.flush(0, len)
1264    }
1265
1266    /// Asynchronously flushes outstanding memory map modifications to disk.
1267    ///
1268    /// This method initiates flushing modified pages to durable storage, but it will not wait for
1269    /// the operation to complete before returning. The file's metadata (including last
1270    /// modification timestamp) may not be updated.
1271    pub fn flush_async(&self) -> Result<()> {
1272        let len = self.len();
1273        self.inner.flush_async(0, len)
1274    }
1275
1276    /// Flushes outstanding memory map modifications in the range to disk.
1277    ///
1278    /// The offset and length must be in the bounds of the memory map.
1279    ///
1280    /// When this method returns with a non-error result, all outstanding changes to a file-backed
1281    /// memory in the range are guaranteed to be durable stored. The file's metadata (including
1282    /// last modification timestamp) may not be updated. It is not guaranteed the only the changes
1283    /// in the specified range are flushed; other outstanding changes to the memory map may be
1284    /// flushed as well.
1285    pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> {
1286        self.inner.flush(offset, len)
1287    }
1288
1289    /// Asynchronously flushes outstanding memory map modifications in the range to disk.
1290    ///
1291    /// The offset and length must be in the bounds of the memory map.
1292    ///
1293    /// This method initiates flushing modified pages to durable storage, but it will not wait for
1294    /// the operation to complete before returning. The file's metadata (including last
1295    /// modification timestamp) may not be updated. It is not guaranteed that the only changes
1296    /// flushed are those in the specified range; other outstanding changes to the memory map may
1297    /// be flushed as well.
1298    pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> {
1299        self.inner.flush_async(offset, len)
1300    }
1301
1302    /// Returns an immutable version of this memory mapped buffer.
1303    ///
1304    /// If the memory map is file-backed, the file must have been opened with read permissions.
1305    ///
1306    /// # Errors
1307    ///
1308    /// This method returns an error when the underlying system call fails, which can happen for a
1309    /// variety of reasons, such as when the file has not been opened with read permissions.
1310    ///
1311    /// # Example
1312    ///
1313    /// ```
1314    /// use std::io::Write;
1315    /// use std::path::PathBuf;
1316    ///
1317    /// use memmap2::{Mmap, MmapMut};
1318    ///
1319    /// # fn main() -> std::io::Result<()> {
1320    /// let mut mmap = MmapMut::map_anon(128)?;
1321    ///
1322    /// (&mut mmap[..]).write(b"Hello, world!")?;
1323    ///
1324    /// let mmap: Mmap = mmap.make_read_only()?;
1325    /// # Ok(())
1326    /// # }
1327    /// ```
1328    pub fn make_read_only(mut self) -> Result<Mmap> {
1329        self.inner.make_read_only()?;
1330        Ok(Mmap { inner: self.inner })
1331    }
1332
1333    /// Transition the memory map to be readable and executable.
1334    ///
1335    /// If the memory map is file-backed, the file must have been opened with execute permissions.
1336    ///
1337    /// On systems with separate instructions and data caches (a category that includes many ARM
1338    /// chips), a platform-specific call may be needed to ensure that the changes are visible to the
1339    /// execution unit (e.g. when using this function to implement a JIT compiler).  For more
1340    /// details, see [this ARM write-up](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code)
1341    /// or the `man` page for [`sys_icache_invalidate`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html).
1342    ///
1343    /// # Errors
1344    ///
1345    /// This method returns an error when the underlying system call fails, which can happen for a
1346    /// variety of reasons, such as when the file has not been opened with execute permissions.
1347    pub fn make_exec(mut self) -> Result<Mmap> {
1348        self.inner.make_exec()?;
1349        Ok(Mmap { inner: self.inner })
1350    }
1351
1352    /// Advise OS how this memory map will be accessed.
1353    ///
1354    /// Only supported on Unix.
1355    ///
1356    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1357    #[cfg(unix)]
1358    pub fn advise(&self, advice: Advice) -> Result<()> {
1359        self.inner
1360            .advise(advice as libc::c_int, 0, self.inner.len())
1361    }
1362
1363    /// Advise OS how this memory map will be accessed.
1364    ///
1365    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1366    ///
1367    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1368    #[cfg(unix)]
1369    pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> {
1370        self.inner
1371            .advise(advice as libc::c_int, 0, self.inner.len())
1372    }
1373
1374    /// Advise OS how this range of memory map will be accessed.
1375    ///
1376    /// Only supported on Unix.
1377    ///
1378    /// The offset and length must be in the bounds of the memory map.
1379    ///
1380    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1381    #[cfg(unix)]
1382    pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> {
1383        self.inner.advise(advice as libc::c_int, offset, len)
1384    }
1385
1386    /// Advise OS how this range of memory map will be accessed.
1387    ///
1388    /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix.
1389    ///
1390    /// The offset and length must be in the bounds of the memory map.
1391    ///
1392    /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
1393    #[cfg(unix)]
1394    pub unsafe fn unchecked_advise_range(
1395        &self,
1396        advice: UncheckedAdvice,
1397        offset: usize,
1398        len: usize,
1399    ) -> Result<()> {
1400        self.inner.advise(advice as libc::c_int, offset, len)
1401    }
1402
1403    /// Lock the whole memory map into RAM. Only supported on Unix.
1404    ///
1405    /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
1406    #[cfg(unix)]
1407    pub fn lock(&self) -> Result<()> {
1408        self.inner.lock()
1409    }
1410
1411    /// Unlock the whole memory map. Only supported on Unix.
1412    ///
1413    /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
1414    #[cfg(unix)]
1415    pub fn unlock(&self) -> Result<()> {
1416        self.inner.unlock()
1417    }
1418
1419    /// Adjust the size of the memory mapping.
1420    ///
1421    /// This will try to resize the memory mapping in place. If
1422    /// [`RemapOptions::may_move`] is specified it will move the mapping if it
1423    /// could not resize in place, otherwise it will error.
1424    ///
1425    /// Only supported on Linux.
1426    ///
1427    /// See the [`mremap(2)`] man page.
1428    ///
1429    /// # Safety
1430    ///
1431    /// Resizing the memory mapping beyond the end of the mapped file will
1432    /// result in UB should you happen to access memory beyond the end of the
1433    /// file.
1434    ///
1435    /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
1436    #[cfg(target_os = "linux")]
1437    pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
1438        self.inner.remap(new_len, options)
1439    }
1440}
1441
1442#[cfg(feature = "stable_deref_trait")]
1443unsafe impl stable_deref_trait::StableDeref for MmapMut {}
1444
1445impl Deref for MmapMut {
1446    type Target = [u8];
1447
1448    #[inline]
1449    fn deref(&self) -> &[u8] {
1450        unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) }
1451    }
1452}
1453
1454impl DerefMut for MmapMut {
1455    #[inline]
1456    fn deref_mut(&mut self) -> &mut [u8] {
1457        unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) }
1458    }
1459}
1460
1461impl AsRef<[u8]> for MmapMut {
1462    #[inline]
1463    fn as_ref(&self) -> &[u8] {
1464        self.deref()
1465    }
1466}
1467
1468impl AsMut<[u8]> for MmapMut {
1469    #[inline]
1470    fn as_mut(&mut self) -> &mut [u8] {
1471        self.deref_mut()
1472    }
1473}
1474
1475impl fmt::Debug for MmapMut {
1476    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1477        fmt.debug_struct("MmapMut")
1478            .field("ptr", &self.as_ptr())
1479            .field("len", &self.len())
1480            .finish()
1481    }
1482}
1483
1484/// Options for [`Mmap::remap`] and [`MmapMut::remap`].
1485#[derive(Copy, Clone, Default, Debug)]
1486#[cfg(target_os = "linux")]
1487pub struct RemapOptions {
1488    may_move: bool,
1489}
1490
1491#[cfg(target_os = "linux")]
1492impl RemapOptions {
1493    /// Creates a mew set of options for resizing a memory map.
1494    pub fn new() -> Self {
1495        Self::default()
1496    }
1497
1498    /// Controls whether the memory map can be moved if it is not possible to
1499    /// resize it in place.
1500    ///
1501    /// If false then the memory map is guaranteed to remain at the same
1502    /// address when being resized but attempting to resize will return an
1503    /// error if the new memory map would overlap with something else in the
1504    /// current process' memory.
1505    ///
1506    /// By default this is false.
1507    ///
1508    /// # `may_move` and `StableDeref`
1509    /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and
1510    /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the
1511    /// memory map dereferences to a fixed address, however, calling `remap`
1512    /// with `may_move` set may result in the backing memory of the mapping
1513    /// being moved to a new address. This may cause UB in other code
1514    /// depending on the `StableDeref` guarantees.
1515    pub fn may_move(mut self, may_move: bool) -> Self {
1516        self.may_move = may_move;
1517        self
1518    }
1519
1520    pub(crate) fn into_flags(self) -> libc::c_int {
1521        if self.may_move {
1522            libc::MREMAP_MAYMOVE
1523        } else {
1524            0
1525        }
1526    }
1527}
1528
1529#[cfg(test)]
1530mod test {
1531    #[cfg(unix)]
1532    use crate::advice::Advice;
1533    use std::fs::{File, OpenOptions};
1534    use std::io::{Read, Write};
1535    use std::mem;
1536    #[cfg(unix)]
1537    use std::os::unix::io::AsRawFd;
1538    #[cfg(windows)]
1539    use std::os::windows::fs::OpenOptionsExt;
1540
1541    #[cfg(windows)]
1542    const GENERIC_ALL: u32 = 0x10000000;
1543
1544    use super::{Mmap, MmapMut, MmapOptions};
1545
1546    #[test]
1547    fn map_file() {
1548        let expected_len = 128;
1549        let tempdir = tempfile::tempdir().unwrap();
1550        let path = tempdir.path().join("mmap");
1551
1552        let file = OpenOptions::new()
1553            .read(true)
1554            .write(true)
1555            .create(true)
1556            .truncate(true)
1557            .open(path)
1558            .unwrap();
1559
1560        file.set_len(expected_len as u64).unwrap();
1561
1562        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
1563        let len = mmap.len();
1564        assert_eq!(expected_len, len);
1565
1566        let zeros = vec![0; len];
1567        let incr: Vec<u8> = (0..len as u8).collect();
1568
1569        // check that the mmap is empty
1570        assert_eq!(&zeros[..], &mmap[..]);
1571
1572        // write values into the mmap
1573        (&mut mmap[..]).write_all(&incr[..]).unwrap();
1574
1575        // read values back
1576        assert_eq!(&incr[..], &mmap[..]);
1577    }
1578
1579    #[test]
1580    #[cfg(unix)]
1581    fn map_fd() {
1582        let expected_len = 128;
1583        let tempdir = tempfile::tempdir().unwrap();
1584        let path = tempdir.path().join("mmap");
1585
1586        let file = OpenOptions::new()
1587            .read(true)
1588            .write(true)
1589            .create(true)
1590            .truncate(true)
1591            .open(path)
1592            .unwrap();
1593
1594        file.set_len(expected_len as u64).unwrap();
1595
1596        let mut mmap = unsafe { MmapMut::map_mut(file.as_raw_fd()).unwrap() };
1597        let len = mmap.len();
1598        assert_eq!(expected_len, len);
1599
1600        let zeros = vec![0; len];
1601        let incr: Vec<u8> = (0..len as u8).collect();
1602
1603        // check that the mmap is empty
1604        assert_eq!(&zeros[..], &mmap[..]);
1605
1606        // write values into the mmap
1607        (&mut mmap[..]).write_all(&incr[..]).unwrap();
1608
1609        // read values back
1610        assert_eq!(&incr[..], &mmap[..]);
1611    }
1612
1613    /// Checks that "mapping" a 0-length file derefs to an empty slice.
1614    #[test]
1615    fn map_empty_file() {
1616        let tempdir = tempfile::tempdir().unwrap();
1617        let path = tempdir.path().join("mmap");
1618
1619        let file = OpenOptions::new()
1620            .read(true)
1621            .write(true)
1622            .create(true)
1623            .truncate(true)
1624            .open(path)
1625            .unwrap();
1626        let mmap = unsafe { Mmap::map(&file).unwrap() };
1627        assert!(mmap.is_empty());
1628        assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
1629        let mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
1630        assert!(mmap.is_empty());
1631        assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
1632    }
1633
1634    #[test]
1635    fn map_anon() {
1636        let expected_len = 128;
1637        let mut mmap = MmapMut::map_anon(expected_len).unwrap();
1638        let len = mmap.len();
1639        assert_eq!(expected_len, len);
1640
1641        let zeros = vec![0; len];
1642        let incr: Vec<u8> = (0..len as u8).collect();
1643
1644        // check that the mmap is empty
1645        assert_eq!(&zeros[..], &mmap[..]);
1646
1647        // write values into the mmap
1648        (&mut mmap[..]).write_all(&incr[..]).unwrap();
1649
1650        // read values back
1651        assert_eq!(&incr[..], &mmap[..]);
1652    }
1653
1654    #[test]
1655    fn map_anon_zero_len() {
1656        assert!(MmapOptions::new().map_anon().unwrap().is_empty());
1657    }
1658
1659    #[test]
1660    #[cfg(target_pointer_width = "32")]
1661    fn map_anon_len_overflow() {
1662        let res = MmapMut::map_anon(0x80000000);
1663
1664        assert_eq!(
1665            res.unwrap_err().to_string(),
1666            "memory map length overflows isize"
1667        );
1668    }
1669
1670    #[test]
1671    fn file_write() {
1672        let tempdir = tempfile::tempdir().unwrap();
1673        let path = tempdir.path().join("mmap");
1674
1675        let mut file = OpenOptions::new()
1676            .read(true)
1677            .write(true)
1678            .create(true)
1679            .truncate(true)
1680            .open(path)
1681            .unwrap();
1682        file.set_len(128).unwrap();
1683
1684        let write = b"abc123";
1685        let mut read = [0u8; 6];
1686
1687        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
1688        (&mut mmap[..]).write_all(write).unwrap();
1689        mmap.flush().unwrap();
1690
1691        file.read_exact(&mut read).unwrap();
1692        assert_eq!(write, &read);
1693    }
1694
1695    #[test]
1696    fn flush_range() {
1697        let tempdir = tempfile::tempdir().unwrap();
1698        let path = tempdir.path().join("mmap");
1699
1700        let file = OpenOptions::new()
1701            .read(true)
1702            .write(true)
1703            .create(true)
1704            .truncate(true)
1705            .open(path)
1706            .unwrap();
1707        file.set_len(128).unwrap();
1708        let write = b"abc123";
1709
1710        let mut mmap = unsafe {
1711            MmapOptions::new()
1712                .offset(2)
1713                .len(write.len())
1714                .map_mut(&file)
1715                .unwrap()
1716        };
1717        (&mut mmap[..]).write_all(write).unwrap();
1718        mmap.flush_async_range(0, write.len()).unwrap();
1719        mmap.flush_range(0, write.len()).unwrap();
1720    }
1721
1722    #[test]
1723    fn map_copy() {
1724        let tempdir = tempfile::tempdir().unwrap();
1725        let path = tempdir.path().join("mmap");
1726
1727        let mut file = OpenOptions::new()
1728            .read(true)
1729            .write(true)
1730            .create(true)
1731            .truncate(true)
1732            .open(path)
1733            .unwrap();
1734        file.set_len(128).unwrap();
1735
1736        let nulls = b"\0\0\0\0\0\0";
1737        let write = b"abc123";
1738        let mut read = [0u8; 6];
1739
1740        let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() };
1741
1742        (&mut mmap[..]).write_all(write).unwrap();
1743        mmap.flush().unwrap();
1744
1745        // The mmap contains the write
1746        (&mmap[..]).read_exact(&mut read).unwrap();
1747        assert_eq!(write, &read);
1748
1749        // The file does not contain the write
1750        file.read_exact(&mut read).unwrap();
1751        assert_eq!(nulls, &read);
1752
1753        // another mmap does not contain the write
1754        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
1755        (&mmap2[..]).read_exact(&mut read).unwrap();
1756        assert_eq!(nulls, &read);
1757    }
1758
1759    #[test]
1760    fn map_copy_read_only() {
1761        let tempdir = tempfile::tempdir().unwrap();
1762        let path = tempdir.path().join("mmap");
1763
1764        let file = OpenOptions::new()
1765            .read(true)
1766            .write(true)
1767            .create(true)
1768            .truncate(true)
1769            .open(path)
1770            .unwrap();
1771        file.set_len(128).unwrap();
1772
1773        let nulls = b"\0\0\0\0\0\0";
1774        let mut read = [0u8; 6];
1775
1776        let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() };
1777        (&mmap[..]).read_exact(&mut read).unwrap();
1778        assert_eq!(nulls, &read);
1779
1780        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
1781        (&mmap2[..]).read_exact(&mut read).unwrap();
1782        assert_eq!(nulls, &read);
1783    }
1784
1785    #[test]
1786    fn map_offset() {
1787        let tempdir = tempfile::tempdir().unwrap();
1788        let path = tempdir.path().join("mmap");
1789
1790        let file = OpenOptions::new()
1791            .read(true)
1792            .write(true)
1793            .create(true)
1794            .truncate(true)
1795            .open(path)
1796            .unwrap();
1797
1798        let offset = u64::from(u32::MAX) + 2;
1799        let len = 5432;
1800        file.set_len(offset + len as u64).unwrap();
1801
1802        // Check inferred length mmap.
1803        let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() };
1804        assert_eq!(len, mmap.len());
1805
1806        // Check explicit length mmap.
1807        let mut mmap = unsafe {
1808            MmapOptions::new()
1809                .offset(offset)
1810                .len(len)
1811                .map_mut(&file)
1812                .unwrap()
1813        };
1814        assert_eq!(len, mmap.len());
1815
1816        let zeros = vec![0; len];
1817        let incr: Vec<_> = (0..len).map(|i| i as u8).collect();
1818
1819        // check that the mmap is empty
1820        assert_eq!(&zeros[..], &mmap[..]);
1821
1822        // write values into the mmap
1823        (&mut mmap[..]).write_all(&incr[..]).unwrap();
1824
1825        // read values back
1826        assert_eq!(&incr[..], &mmap[..]);
1827    }
1828
1829    #[test]
1830    fn index() {
1831        let mut mmap = MmapMut::map_anon(128).unwrap();
1832        mmap[0] = 42;
1833        assert_eq!(42, mmap[0]);
1834    }
1835
1836    #[test]
1837    fn sync_send() {
1838        fn is_sync_send<T>(_val: T)
1839        where
1840            T: Sync + Send,
1841        {
1842        }
1843
1844        let mmap = MmapMut::map_anon(129).unwrap();
1845        is_sync_send(mmap);
1846    }
1847
1848    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1849    fn jit_x86(mut mmap: MmapMut) {
1850        mmap[0] = 0xB8; // mov eax, 0xAB
1851        mmap[1] = 0xAB;
1852        mmap[2] = 0x00;
1853        mmap[3] = 0x00;
1854        mmap[4] = 0x00;
1855        mmap[5] = 0xC3; // ret
1856
1857        let mmap = mmap.make_exec().expect("make_exec");
1858
1859        let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) };
1860        assert_eq!(jitfn(), 0xab);
1861    }
1862
1863    #[test]
1864    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1865    fn jit_x86_anon() {
1866        jit_x86(MmapMut::map_anon(4096).unwrap());
1867    }
1868
1869    #[test]
1870    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
1871    fn jit_x86_file() {
1872        let tempdir = tempfile::tempdir().unwrap();
1873        let mut options = OpenOptions::new();
1874        #[cfg(windows)]
1875        options.access_mode(GENERIC_ALL);
1876
1877        let file = options
1878            .read(true)
1879            .write(true)
1880            .create(true)
1881            .truncate(true)
1882            .open(tempdir.path().join("jit_x86"))
1883            .expect("open");
1884
1885        file.set_len(4096).expect("set_len");
1886        jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") });
1887    }
1888
1889    #[test]
1890    fn mprotect_file() {
1891        let tempdir = tempfile::tempdir().unwrap();
1892        let path = tempdir.path().join("mmap");
1893
1894        let mut options = OpenOptions::new();
1895        #[cfg(windows)]
1896        options.access_mode(GENERIC_ALL);
1897
1898        let mut file = options
1899            .read(true)
1900            .write(true)
1901            .create(true)
1902            .truncate(true)
1903            .open(path)
1904            .expect("open");
1905        file.set_len(256_u64).expect("set_len");
1906
1907        let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") };
1908
1909        let mmap = mmap.make_read_only().expect("make_read_only");
1910        let mut mmap = mmap.make_mut().expect("make_mut");
1911
1912        let write = b"abc123";
1913        let mut read = [0u8; 6];
1914
1915        (&mut mmap[..]).write_all(write).unwrap();
1916        mmap.flush().unwrap();
1917
1918        // The mmap contains the write
1919        (&mmap[..]).read_exact(&mut read).unwrap();
1920        assert_eq!(write, &read);
1921
1922        // The file should contain the write
1923        file.read_exact(&mut read).unwrap();
1924        assert_eq!(write, &read);
1925
1926        // another mmap should contain the write
1927        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
1928        (&mmap2[..]).read_exact(&mut read).unwrap();
1929        assert_eq!(write, &read);
1930
1931        let mmap = mmap.make_exec().expect("make_exec");
1932
1933        drop(mmap);
1934    }
1935
1936    #[test]
1937    fn mprotect_copy() {
1938        let tempdir = tempfile::tempdir().unwrap();
1939        let path = tempdir.path().join("mmap");
1940
1941        let mut options = OpenOptions::new();
1942        #[cfg(windows)]
1943        options.access_mode(GENERIC_ALL);
1944
1945        let mut file = options
1946            .read(true)
1947            .write(true)
1948            .create(true)
1949            .truncate(true)
1950            .open(path)
1951            .expect("open");
1952        file.set_len(256_u64).expect("set_len");
1953
1954        let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") };
1955
1956        let mmap = mmap.make_read_only().expect("make_read_only");
1957        let mut mmap = mmap.make_mut().expect("make_mut");
1958
1959        let nulls = b"\0\0\0\0\0\0";
1960        let write = b"abc123";
1961        let mut read = [0u8; 6];
1962
1963        (&mut mmap[..]).write_all(write).unwrap();
1964        mmap.flush().unwrap();
1965
1966        // The mmap contains the write
1967        (&mmap[..]).read_exact(&mut read).unwrap();
1968        assert_eq!(write, &read);
1969
1970        // The file does not contain the write
1971        file.read_exact(&mut read).unwrap();
1972        assert_eq!(nulls, &read);
1973
1974        // another mmap does not contain the write
1975        let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() };
1976        (&mmap2[..]).read_exact(&mut read).unwrap();
1977        assert_eq!(nulls, &read);
1978
1979        let mmap = mmap.make_exec().expect("make_exec");
1980
1981        drop(mmap);
1982    }
1983
1984    #[test]
1985    fn mprotect_anon() {
1986        let mmap = MmapMut::map_anon(256).expect("map_mut");
1987
1988        let mmap = mmap.make_read_only().expect("make_read_only");
1989        let mmap = mmap.make_mut().expect("make_mut");
1990        let mmap = mmap.make_exec().expect("make_exec");
1991        drop(mmap);
1992    }
1993
1994    #[test]
1995    fn raw() {
1996        let tempdir = tempfile::tempdir().unwrap();
1997        let path = tempdir.path().join("mmapraw");
1998
1999        let mut options = OpenOptions::new();
2000        let mut file = options
2001            .read(true)
2002            .write(true)
2003            .create(true)
2004            .truncate(true)
2005            .open(path)
2006            .expect("open");
2007        file.write_all(b"abc123").unwrap();
2008        let mmap = MmapOptions::new().map_raw(&file).unwrap();
2009        assert_eq!(mmap.len(), 6);
2010        assert!(!mmap.as_ptr().is_null());
2011        assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
2012    }
2013
2014    #[test]
2015    fn raw_read_only() {
2016        let tempdir = tempfile::tempdir().unwrap();
2017        let path = tempdir.path().join("mmaprawro");
2018
2019        File::create(&path).unwrap().write_all(b"abc123").unwrap();
2020
2021        let mmap = MmapOptions::new()
2022            .map_raw_read_only(&File::open(&path).unwrap())
2023            .unwrap();
2024
2025        assert_eq!(mmap.len(), 6);
2026        assert!(!mmap.as_ptr().is_null());
2027        assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
2028    }
2029
2030    /// Something that relies on StableDeref
2031    #[test]
2032    #[cfg(feature = "stable_deref_trait")]
2033    fn owning_ref() {
2034        let mut map = MmapMut::map_anon(128).unwrap();
2035        map[10] = 42;
2036        let owning = owning_ref::OwningRef::new(map);
2037        let sliced = owning.map(|map| &map[10..20]);
2038        assert_eq!(42, sliced[0]);
2039
2040        let map = sliced.into_owner().make_read_only().unwrap();
2041        let owning = owning_ref::OwningRef::new(map);
2042        let sliced = owning.map(|map| &map[10..20]);
2043        assert_eq!(42, sliced[0]);
2044    }
2045
2046    #[test]
2047    #[cfg(unix)]
2048    fn advise() {
2049        let expected_len = 128;
2050        let tempdir = tempfile::tempdir().unwrap();
2051        let path = tempdir.path().join("mmap_advise");
2052
2053        let file = OpenOptions::new()
2054            .read(true)
2055            .write(true)
2056            .create(true)
2057            .truncate(true)
2058            .open(path)
2059            .unwrap();
2060
2061        file.set_len(expected_len as u64).unwrap();
2062
2063        // Test MmapMut::advise
2064        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
2065        mmap.advise(Advice::Random)
2066            .expect("mmap advising should be supported on unix");
2067
2068        let len = mmap.len();
2069        assert_eq!(expected_len, len);
2070
2071        let zeros = vec![0; len];
2072        let incr: Vec<u8> = (0..len as u8).collect();
2073
2074        // check that the mmap is empty
2075        assert_eq!(&zeros[..], &mmap[..]);
2076
2077        mmap.advise_range(Advice::Sequential, 0, mmap.len())
2078            .expect("mmap advising should be supported on unix");
2079
2080        // write values into the mmap
2081        (&mut mmap[..]).write_all(&incr[..]).unwrap();
2082
2083        // read values back
2084        assert_eq!(&incr[..], &mmap[..]);
2085
2086        // Set advice and Read from the read-only map
2087        let mmap = unsafe { Mmap::map(&file).unwrap() };
2088
2089        mmap.advise(Advice::Random)
2090            .expect("mmap advising should be supported on unix");
2091
2092        // read values back
2093        assert_eq!(&incr[..], &mmap[..]);
2094    }
2095
2096    #[test]
2097    #[cfg(target_os = "linux")]
2098    fn advise_writes_unsafely() {
2099        let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
2100
2101        let mut mmap = MmapMut::map_anon(page_size).unwrap();
2102        mmap.as_mut().fill(255);
2103        let mmap = mmap.make_read_only().unwrap();
2104
2105        let a = mmap.as_ref()[0];
2106        unsafe {
2107            mmap.unchecked_advise(crate::UncheckedAdvice::DontNeed)
2108                .unwrap();
2109        }
2110        let b = mmap.as_ref()[0];
2111
2112        assert_eq!(a, 255);
2113        assert_eq!(b, 0);
2114    }
2115
2116    #[test]
2117    #[cfg(target_os = "linux")]
2118    fn advise_writes_unsafely_to_part_of_map() {
2119        let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
2120
2121        let mut mmap = MmapMut::map_anon(2 * page_size).unwrap();
2122        mmap.as_mut().fill(255);
2123        let mmap = mmap.make_read_only().unwrap();
2124
2125        let a = mmap.as_ref()[0];
2126        let b = mmap.as_ref()[page_size];
2127        unsafe {
2128            mmap.unchecked_advise_range(crate::UncheckedAdvice::DontNeed, page_size, page_size)
2129                .unwrap();
2130        }
2131        let c = mmap.as_ref()[0];
2132        let d = mmap.as_ref()[page_size];
2133
2134        assert_eq!(a, 255);
2135        assert_eq!(b, 255);
2136        assert_eq!(c, 255);
2137        assert_eq!(d, 0);
2138    }
2139
2140    /// Returns true if a non-zero amount of memory is locked.
2141    #[cfg(target_os = "linux")]
2142    fn is_locked() -> bool {
2143        let status = &std::fs::read_to_string("/proc/self/status")
2144            .expect("/proc/self/status should be available");
2145        for line in status.lines() {
2146            if line.starts_with("VmLck:") {
2147                let numbers = line.replace(|c: char| !c.is_ascii_digit(), "");
2148                return numbers != "0";
2149            }
2150        }
2151        panic!("cannot get VmLck information")
2152    }
2153
2154    #[test]
2155    #[cfg(unix)]
2156    fn lock() {
2157        let tempdir = tempfile::tempdir().unwrap();
2158        let path = tempdir.path().join("mmap_lock");
2159
2160        let file = OpenOptions::new()
2161            .read(true)
2162            .write(true)
2163            .create(true)
2164            .truncate(true)
2165            .open(path)
2166            .unwrap();
2167        file.set_len(128).unwrap();
2168
2169        let mmap = unsafe { Mmap::map(&file).unwrap() };
2170        #[cfg(target_os = "linux")]
2171        assert!(!is_locked());
2172
2173        mmap.lock().expect("mmap lock should be supported on unix");
2174        #[cfg(target_os = "linux")]
2175        assert!(is_locked());
2176
2177        mmap.lock()
2178            .expect("mmap lock again should not cause problems");
2179        #[cfg(target_os = "linux")]
2180        assert!(is_locked());
2181
2182        mmap.unlock()
2183            .expect("mmap unlock should be supported on unix");
2184        #[cfg(target_os = "linux")]
2185        assert!(!is_locked());
2186
2187        mmap.unlock()
2188            .expect("mmap unlock again should not cause problems");
2189        #[cfg(target_os = "linux")]
2190        assert!(!is_locked());
2191    }
2192
2193    #[test]
2194    #[cfg(target_os = "linux")]
2195    fn remap_grow() {
2196        use crate::RemapOptions;
2197
2198        let initial_len = 128;
2199        let final_len = 2000;
2200
2201        let zeros = vec![0u8; final_len];
2202        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
2203
2204        let file = tempfile::tempfile().unwrap();
2205        file.set_len(final_len as u64).unwrap();
2206
2207        let mut mmap = unsafe { MmapOptions::new().len(initial_len).map_mut(&file).unwrap() };
2208        assert_eq!(mmap.len(), initial_len);
2209        assert_eq!(&mmap[..], &zeros[..initial_len]);
2210
2211        unsafe {
2212            mmap.remap(final_len, RemapOptions::new().may_move(true))
2213                .unwrap();
2214        }
2215
2216        // The size should have been updated
2217        assert_eq!(mmap.len(), final_len);
2218
2219        // Should still be all zeros
2220        assert_eq!(&mmap[..], &zeros);
2221
2222        // Write out to the whole expanded slice.
2223        mmap.copy_from_slice(&incr);
2224    }
2225
2226    #[test]
2227    #[cfg(target_os = "linux")]
2228    fn remap_shrink() {
2229        use crate::RemapOptions;
2230
2231        let initial_len = 20000;
2232        let final_len = 400;
2233
2234        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
2235
2236        let file = tempfile::tempfile().unwrap();
2237        file.set_len(initial_len as u64).unwrap();
2238
2239        let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
2240        assert_eq!(mmap.len(), initial_len);
2241
2242        unsafe { mmap.remap(final_len, RemapOptions::new()).unwrap() };
2243        assert_eq!(mmap.len(), final_len);
2244
2245        // Check that the mmap is still writable along the slice length
2246        mmap.copy_from_slice(&incr);
2247    }
2248
2249    #[test]
2250    #[cfg(target_os = "linux")]
2251    #[cfg(target_pointer_width = "32")]
2252    fn remap_len_overflow() {
2253        use crate::RemapOptions;
2254
2255        let file = tempfile::tempfile().unwrap();
2256        file.set_len(1024).unwrap();
2257        let mut mmap = unsafe { MmapOptions::new().len(1024).map(&file).unwrap() };
2258
2259        let res = unsafe { mmap.remap(0x80000000, RemapOptions::new().may_move(true)) };
2260        assert_eq!(
2261            res.unwrap_err().to_string(),
2262            "memory map length overflows isize"
2263        );
2264
2265        assert_eq!(mmap.len(), 1024);
2266    }
2267
2268    #[test]
2269    #[cfg(target_os = "linux")]
2270    fn remap_with_offset() {
2271        use crate::RemapOptions;
2272
2273        let offset = 77;
2274        let initial_len = 128;
2275        let final_len = 2000;
2276
2277        let zeros = vec![0u8; final_len];
2278        let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
2279
2280        let file = tempfile::tempfile().unwrap();
2281        file.set_len(final_len as u64 + offset).unwrap();
2282
2283        let mut mmap = unsafe {
2284            MmapOptions::new()
2285                .len(initial_len)
2286                .offset(offset)
2287                .map_mut(&file)
2288                .unwrap()
2289        };
2290        assert_eq!(mmap.len(), initial_len);
2291        assert_eq!(&mmap[..], &zeros[..initial_len]);
2292
2293        unsafe {
2294            mmap.remap(final_len, RemapOptions::new().may_move(true))
2295                .unwrap();
2296        }
2297
2298        // The size should have been updated
2299        assert_eq!(mmap.len(), final_len);
2300
2301        // Should still be all zeros
2302        assert_eq!(&mmap[..], &zeros);
2303
2304        // Write out to the whole expanded slice.
2305        mmap.copy_from_slice(&incr);
2306    }
2307}