Coverage Report

Created: 2026-03-31 07:35

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