|
7 | 7 |
|
8 | 8 | use std::fs::File;
|
9 | 9 | use std::io::{Read, Seek, SeekFrom, Write};
|
| 10 | +use std::os::fd::AsRawFd; |
| 11 | +use std::ptr::null_mut; |
10 | 12 | use std::sync::Arc;
|
11 | 13 |
|
12 | 14 | use serde::{Deserialize, Serialize};
|
@@ -51,6 +53,8 @@ pub enum MemoryError {
|
51 | 53 | MemfdSetLen(std::io::Error),
|
52 | 54 | /// Total sum of memory regions exceeds largest possible file offset
|
53 | 55 | OffsetTooLarge,
|
| 56 | + /// Error calling mmap: {0} |
| 57 | + Mmap(std::io::Error), |
54 | 58 | }
|
55 | 59 |
|
56 | 60 | /// Newtype that implements [`ReadVolatile`] and [`WriteVolatile`] if `T` implements `Read` or
|
@@ -203,16 +207,40 @@ pub fn create(
|
203 | 207 | let mut builder = MmapRegionBuilder::new_with_bitmap(
|
204 | 208 | size,
|
205 | 209 | track_dirty_pages.then(|| AtomicBitmap::with_len(size)),
|
206 |
| - ) |
207 |
| - .with_mmap_prot(libc::PROT_READ | libc::PROT_WRITE) |
208 |
| - .with_mmap_flags(libc::MAP_NORESERVE | mmap_flags); |
| 210 | + ); |
209 | 211 |
|
210 |
| - if let Some(ref file) = file { |
| 212 | + // when computing offset below we ensure it fits into i64 |
| 213 | + #[allow(clippy::cast_possible_wrap)] |
| 214 | + let (fd, fd_off) = if let Some(ref file) = file { |
211 | 215 | let file_offset = FileOffset::from_arc(Arc::clone(file), offset);
|
212 | 216 |
|
213 | 217 | builder = builder.with_file_offset(file_offset);
|
| 218 | + |
| 219 | + (file.as_raw_fd(), offset as libc::off_t) |
| 220 | + } else { |
| 221 | + (-1, 0) |
| 222 | + }; |
| 223 | + |
| 224 | + // SAFETY: the arguments to mmap cannot cause any memory unsafety in the rust sense |
| 225 | + let ptr = unsafe { |
| 226 | + libc::mmap( |
| 227 | + null_mut(), |
| 228 | + size, |
| 229 | + libc::PROT_READ | libc::PROT_WRITE, |
| 230 | + libc::MAP_NORESERVE | mmap_flags, |
| 231 | + fd, |
| 232 | + fd_off, |
| 233 | + ) |
| 234 | + }; |
| 235 | + |
| 236 | + if ptr == libc::MAP_FAILED { |
| 237 | + return Err(MemoryError::Mmap(std::io::Error::last_os_error())); |
214 | 238 | }
|
215 | 239 |
|
| 240 | + // SAFETY: we check above that mmap succeeded, and the size we passed to builder is the |
| 241 | + // same as the size of the mmap area. |
| 242 | + let builder = unsafe { builder.with_raw_mmap_pointer(ptr.cast()) }; |
| 243 | + |
216 | 244 | offset = match offset.checked_add(size as u64) {
|
217 | 245 | None => return Err(MemoryError::OffsetTooLarge),
|
218 | 246 | Some(new_off) if new_off >= i64::MAX as u64 => {
|
|
0 commit comments