memmap2/
lib.rs

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