memmap2/
lib.rs

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