Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::fmt;
use std::fs::File;
use std::io::{Error, ErrorKind, Result};
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;
use std::usize;

Expand All @@ -40,13 +41,25 @@ use std::usize;
/// [`map_mut()`]: MmapOptions::map_mut()
/// [`map_exec()`]: MmapOptions::map_exec()
/// [`map_copy()`]: MmapOptions::map_copy()
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct MmapOptions {
address: *mut u8,
offset: u64,
len: Option<usize>,
stack: bool,
}

impl Default for MmapOptions {
fn default() -> Self {
MmapOptions {
address: ptr::null_mut(),
offset: u64::default(),
len: Option::default(),
stack: bool::default(),
}
}
}

impl MmapOptions {
/// Creates a new set of options for configuring and creating a memory map.
///
Expand Down Expand Up @@ -143,6 +156,12 @@ impl MmapOptions {
})
}

/// Configures the starting address of the created memory mapped buffer.
pub fn address(&mut self, address: *mut u8) -> &mut Self {
self.address = address;
self
}

/// Configures the anonymous memory map to be suitable for a process or thread stack.
///
/// This option corresponds to the `MAP_STACK` flag on Linux.
Expand Down Expand Up @@ -193,7 +212,7 @@ impl MmapOptions {
/// # }
/// ```
pub unsafe fn map(&self, file: &File) -> Result<Mmap> {
MmapInner::map(self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner })
MmapInner::map(self.address, self.get_len(file)?, file, self.offset).map(|inner| Mmap { inner: inner })
}

/// Creates a readable and executable memory map backed by a file.
Expand All @@ -203,7 +222,7 @@ impl MmapOptions {
/// This method returns an error when the underlying system call fails, which can happen for a
/// variety of reasons, such as when the file is not open with read permissions.
pub unsafe fn map_exec(&self, file: &File) -> Result<Mmap> {
MmapInner::map_exec(self.get_len(file)?, file, self.offset)
MmapInner::map_exec(self.address, self.get_len(file)?, file, self.offset)
.map(|inner| Mmap { inner: inner })
}

Expand Down Expand Up @@ -241,7 +260,7 @@ impl MmapOptions {
/// # }
/// ```
pub unsafe fn map_mut(&self, file: &File) -> Result<MmapMut> {
MmapInner::map_mut(self.get_len(file)?, file, self.offset)
MmapInner::map_mut(self.address, self.get_len(file)?, file, self.offset)
.map(|inner| MmapMut { inner: inner })
}

Expand Down Expand Up @@ -270,7 +289,7 @@ impl MmapOptions {
/// # }
/// ```
pub unsafe fn map_copy(&self, file: &File) -> Result<MmapMut> {
MmapInner::map_copy(self.get_len(file)?, file, self.offset)
MmapInner::map_copy(self.address, self.get_len(file)?, file, self.offset)
.map(|inner| MmapMut { inner: inner })
}

Expand All @@ -283,7 +302,7 @@ impl MmapOptions {
///
/// This method returns an error when the underlying system call fails.
pub fn map_anon(&self) -> Result<MmapMut> {
MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner })
MmapInner::map_anon(self.address, self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner: inner })
}
}

Expand Down
24 changes: 17 additions & 7 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ impl MmapInner {
///
/// This is a thin wrapper around the `mmap` sytem call.
fn new(
address: *mut u8,
len: usize,
prot: libc::c_int,
flags: libc::c_int,
mut flags: libc::c_int,
file: RawFd,
offset: u64,
) -> io::Result<MmapInner> {
Expand All @@ -45,9 +46,13 @@ impl MmapInner {
));
}

if address != ptr::null_mut() {
flags |= libc::MAP_FIXED
}

unsafe {
let ptr = libc::mmap(
ptr::null_mut(),
address as *mut libc::c_void,
aligned_len as libc::size_t,
prot,
flags,
Expand All @@ -66,8 +71,9 @@ impl MmapInner {
}
}

pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
MmapInner::new(
address,
len,
libc::PROT_READ,
libc::MAP_SHARED,
Expand All @@ -76,8 +82,9 @@ impl MmapInner {
)
}

pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_exec(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
MmapInner::new(
address,
len,
libc::PROT_READ | libc::PROT_EXEC,
libc::MAP_SHARED,
Expand All @@ -86,8 +93,9 @@ impl MmapInner {
)
}

pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_mut(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
MmapInner::new(
address,
len,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED,
Expand All @@ -96,8 +104,9 @@ impl MmapInner {
)
}

pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_copy(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
MmapInner::new(
address,
len,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_PRIVATE,
Expand All @@ -107,9 +116,10 @@ impl MmapInner {
}

/// Open an anonymous memory map.
pub fn map_anon(len: usize, stack: bool) -> io::Result<MmapInner> {
pub fn map_anon(address: *mut u8, len: usize, stack: bool) -> io::Result<MmapInner> {
let stack = if stack { MAP_STACK } else { 0 };
MmapInner::new(
address,
len,
libc::PROT_READ | libc::PROT_WRITE,
libc::MAP_SHARED | libc::MAP_ANON | stack,
Expand Down
28 changes: 15 additions & 13 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use winapi::shared::basetsd::SIZE_T;
use winapi::shared::minwindef::DWORD;
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::memoryapi::{
CreateFileMappingW, FlushViewOfFile, MapViewOfFile, UnmapViewOfFile, VirtualProtect,
CreateFileMappingW, FlushViewOfFile, MapViewOfFileEx, UnmapViewOfFile, VirtualProtect,
FILE_MAP_ALL_ACCESS, FILE_MAP_COPY, FILE_MAP_EXECUTE, FILE_MAP_READ, FILE_MAP_WRITE,
};
use winapi::um::sysinfoapi::GetSystemInfo;
Expand All @@ -26,8 +26,9 @@ pub struct MmapInner {
impl MmapInner {
/// Creates a new `MmapInner`.
///
/// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFile` system calls.
/// This is a thin wrapper around the `CreateFileMappingW` and `MapViewOfFileEx` system calls.
pub fn new(
address: *mut u8,
file: &File,
protect: DWORD,
access: DWORD,
Expand All @@ -52,12 +53,13 @@ impl MmapInner {
return Err(io::Error::last_os_error());
}

let ptr = MapViewOfFile(
let ptr = MapViewOfFileEx(
handle,
access,
(aligned_offset >> 16 >> 16) as DWORD,
(aligned_offset & 0xffffffff) as DWORD,
aligned_len as SIZE_T,
address as *mut c_void,
);
CloseHandle(handle);

Expand All @@ -74,7 +76,7 @@ impl MmapInner {
}
}

pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
let mut access = FILE_MAP_READ;
Expand All @@ -94,14 +96,14 @@ impl MmapInner {
(false, false) => PAGE_READONLY,
};

let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?;
if write || exec {
inner.make_read_only()?;
}
Ok(inner)
}

pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_exec(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
let write = protection_supported(file.as_raw_handle(), PAGE_READWRITE);
let mut access = FILE_MAP_READ | FILE_MAP_EXECUTE;
let protection = if write {
Expand All @@ -111,14 +113,14 @@ impl MmapInner {
PAGE_EXECUTE_READ
};

let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?;
if write {
inner.make_exec()?;
}
Ok(inner)
}

pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_mut(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READ);
let mut access = FILE_MAP_READ | FILE_MAP_WRITE;
let protection = if exec {
Expand All @@ -128,14 +130,14 @@ impl MmapInner {
PAGE_READWRITE
};

let mut inner = MmapInner::new(file, protection, access, offset, len, false)?;
let mut inner = MmapInner::new(address, file, protection, access, offset, len, false)?;
if exec {
inner.make_mut()?;
}
Ok(inner)
}

pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
pub fn map_copy(address: *mut u8, len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
let exec = protection_supported(file.as_raw_handle(), PAGE_EXECUTE_READWRITE);
let mut access = FILE_MAP_COPY;
let protection = if exec {
Expand All @@ -145,14 +147,14 @@ impl MmapInner {
PAGE_WRITECOPY
};

let mut inner = MmapInner::new(file, protection, access, offset, len, true)?;
let mut inner = MmapInner::new(address, file, protection, access, offset, len, true)?;
if exec {
inner.make_mut()?;
}
Ok(inner)
}

pub fn map_anon(len: usize, _stack: bool) -> io::Result<MmapInner> {
pub fn map_anon(address: *mut u8, len: usize, _stack: bool) -> io::Result<MmapInner> {
unsafe {
// Create a mapping and view with maximum access permissions, then use `VirtualProtect`
// to set the actual `Protection`. This way, we can set more permissive protection later
Expand All @@ -171,7 +173,7 @@ impl MmapInner {
return Err(io::Error::last_os_error());
}
let access = FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE;
let ptr = MapViewOfFile(handle, access, 0, 0, len as SIZE_T);
let ptr = MapViewOfFileEx(handle, access, 0, 0, len as SIZE_T, address as *mut c_void);
CloseHandle(handle);

if ptr == ptr::null_mut() {
Expand Down