Coverage Report

Created: 2026-03-26 07:41

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