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