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