Coverage Report

Created: 2026-07-14 07:20

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