Skip to main content

memmap2/
lib.rs

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