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