Use std::alloc::alloc instead of libc::posix_memalign.

This makes Cranelift use the Rust `alloc` API its allocations,
rather than directly calling into `libc`, which makes it respect
the `#[global_allocator]` configuration.

Also, use `region::page::ceil` instead of having our own copies of
that logic.
This commit is contained in:
Dan Gohman
2021-08-31 15:28:52 -07:00
parent 197aec9a08
commit 05d113148d
2 changed files with 17 additions and 61 deletions

View File

@@ -1,20 +1,13 @@
#[cfg(not(any(feature = "selinux-fix", windows)))]
use libc;
#[cfg(feature = "selinux-fix")] #[cfg(feature = "selinux-fix")]
use memmap2::MmapMut; use memmap2::MmapMut;
use region; #[cfg(not(any(feature = "selinux-fix", windows)))]
use std::alloc;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::io; use std::io;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
/// Round `size` up to the nearest multiple of `page_size`.
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
(size + (page_size - 1)) & !(page_size - 1)
}
/// A simple struct consisting of a pointer and length. /// A simple struct consisting of a pointer and length.
struct PtrLen { struct PtrLen {
#[cfg(feature = "selinux-fix")] #[cfg(feature = "selinux-fix")]
@@ -40,8 +33,7 @@ impl PtrLen {
/// suitably sized and aligned for memory protection. /// suitably sized and aligned for memory protection.
#[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))] #[cfg(all(not(target_os = "windows"), feature = "selinux-fix"))]
fn with_size(size: usize) -> io::Result<Self> { fn with_size(size: usize) -> io::Result<Self> {
let page_size = region::page::size(); let alloc_size = region::page::ceil(size);
let alloc_size = round_up_to_page_size(size, page_size);
MmapMut::map_anon(alloc_size).map(|mut mmap| { MmapMut::map_anon(alloc_size).map(|mut mmap| {
// The order here is important; we assign the pointer first to get // The order here is important; we assign the pointer first to get
// around compile time borrow errors. // around compile time borrow errors.
@@ -55,21 +47,17 @@ impl PtrLen {
#[cfg(all(not(target_os = "windows"), not(feature = "selinux-fix")))] #[cfg(all(not(target_os = "windows"), not(feature = "selinux-fix")))]
fn with_size(size: usize) -> io::Result<Self> { fn with_size(size: usize) -> io::Result<Self> {
let mut ptr = ptr::null_mut(); assert_ne!(size, 0);
let page_size = region::page::size(); let page_size = region::page::size();
let alloc_size = round_up_to_page_size(size, page_size); let alloc_size = region::page::ceil(size);
unsafe { let layout = alloc::Layout::from_size_align(alloc_size, page_size).unwrap();
let err = libc::posix_memalign(&mut ptr, page_size, alloc_size); // Safety: We assert that the size is non-zero above.
let ptr = unsafe { alloc::alloc(layout) };
if err == 0 {
Ok(Self { Ok(Self {
ptr: ptr as *mut u8, ptr,
len: alloc_size, len: alloc_size,
}) })
} else {
Err(io::Error::from_raw_os_error(err))
}
}
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@@ -77,8 +65,6 @@ impl PtrLen {
use winapi::um::memoryapi::VirtualAlloc; use winapi::um::memoryapi::VirtualAlloc;
use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE}; use winapi::um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE};
let page_size = region::page::size();
// VirtualAlloc always rounds up to the next multiple of the page size // VirtualAlloc always rounds up to the next multiple of the page size
let ptr = unsafe { let ptr = unsafe {
VirtualAlloc( VirtualAlloc(
@@ -91,7 +77,7 @@ impl PtrLen {
if !ptr.is_null() { if !ptr.is_null() {
Ok(Self { Ok(Self {
ptr: ptr as *mut u8, ptr: ptr as *mut u8,
len: round_up_to_page_size(size, page_size), len: region::page::ceil(size),
}) })
} else { } else {
Err(io::Error::last_os_error()) Err(io::Error::last_os_error())
@@ -104,10 +90,12 @@ impl PtrLen {
impl Drop for PtrLen { impl Drop for PtrLen {
fn drop(&mut self) { fn drop(&mut self) {
if !self.ptr.is_null() { if !self.ptr.is_null() {
let page_size = region::page::size();
let layout = alloc::Layout::from_size_align(self.len, page_size).unwrap();
unsafe { unsafe {
region::protect(self.ptr, self.len, region::Protection::READ_WRITE) region::protect(self.ptr, self.len, region::Protection::READ_WRITE)
.expect("unable to unprotect memory"); .expect("unable to unprotect memory");
libc::free(self.ptr as _); alloc::dealloc(self.ptr, layout)
} }
} }
} }
@@ -237,16 +225,3 @@ impl Drop for Memory {
.for_each(mem::forget); .for_each(mem::forget);
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_round_up_to_page_size() {
assert_eq!(round_up_to_page_size(0, 4096), 0);
assert_eq!(round_up_to_page_size(1, 4096), 4096);
assert_eq!(round_up_to_page_size(4096, 4096), 4096);
assert_eq!(round_up_to_page_size(4097, 4096), 8192);
}
}

View File

@@ -12,11 +12,6 @@ use std::path::Path;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
/// Round `size` up to the nearest multiple of `page_size`.
fn round_up_to_page_size(size: usize, page_size: usize) -> usize {
(size + (page_size - 1)) & !(page_size - 1)
}
/// A simple struct consisting of a page-aligned pointer to page-aligned /// A simple struct consisting of a page-aligned pointer to page-aligned
/// and initially-zeroed memory and a length. /// and initially-zeroed memory and a length.
#[derive(Debug)] #[derive(Debug)]
@@ -46,8 +41,7 @@ impl Mmap {
/// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory. /// Create a new `Mmap` pointing to at least `size` bytes of page-aligned accessible memory.
pub fn with_at_least(size: usize) -> Result<Self> { pub fn with_at_least(size: usize) -> Result<Self> {
let page_size = region::page::size(); let rounded_size = region::page::ceil(size);
let rounded_size = round_up_to_page_size(size, page_size);
Self::accessible_reserved(rounded_size, rounded_size) Self::accessible_reserved(rounded_size, rounded_size)
} }
@@ -472,16 +466,3 @@ fn _assert() {
fn _assert_send_sync<T: Send + Sync>() {} fn _assert_send_sync<T: Send + Sync>() {}
_assert_send_sync::<Mmap>(); _assert_send_sync::<Mmap>();
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_round_up_to_page_size() {
assert_eq!(round_up_to_page_size(0, 4096), 0);
assert_eq!(round_up_to_page_size(1, 4096), 4096);
assert_eq!(round_up_to_page_size(4096, 4096), 4096);
assert_eq!(round_up_to_page_size(4097, 4096), 8192);
}
}