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