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