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