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