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