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