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