Skip to content

Commit b4cc26a

Browse files
authored
Run shared memory tests with Miri (#1174)
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 244b5e0 commit b4cc26a

4 files changed

Lines changed: 63 additions & 49 deletions

File tree

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@ test-doc target=default-target features="":
212212

213213
miri-tests:
214214
rustup +nightly component list | grep -q "miri.*installed" || rustup component add miri --toolchain nightly
215-
# For now only run miri tests on hyperlight-common with trace_guest feature
216215
# We can add more as needed
217216
cargo +nightly miri test -p hyperlight-common -F trace_guest
217+
cargo +nightly miri test -p hyperlight-host --lib -- mem::shared_mem::tests
218218

219219
################
220220
### LINTING ####

src/hyperlight_host/src/mem/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ pub mod ptr_offset;
3636
/// a memory region for a guest running in a sandbox.
3737
pub mod shared_mem;
3838
/// Utilities for writing shared memory tests
39-
#[cfg(test)]
39+
#[cfg(all(test, not(miri)))] // uses proptest which isn't miri-compatible
4040
pub(crate) mod shared_mem_tests;

src/hyperlight_host/src/mem/shared_mem.rs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,11 @@ use windows::Win32::System::Memory::{
3535
#[cfg(target_os = "windows")]
3636
use windows::core::PCSTR;
3737

38-
#[cfg(target_os = "windows")]
39-
use crate::HyperlightError::MemoryAllocationFailed;
4038
use crate::HyperlightError::SnapshotSizeMismatch;
4139
#[cfg(target_os = "windows")]
42-
use crate::HyperlightError::{MemoryRequestTooBig, WindowsAPIError};
40+
use crate::HyperlightError::WindowsAPIError;
4341
use crate::sandbox::snapshot::Snapshot;
44-
use crate::{Result, log_then_return, new_error};
42+
use crate::{HyperlightError, Result, log_then_return, new_error};
4543

4644
/// Makes sure that the given `offset` and `size` are within the bounds of the memory with size `mem_size`.
4745
macro_rules! bounds_check {
@@ -312,12 +310,11 @@ impl ExclusiveSharedMemory {
312310
#[cfg(target_os = "linux")]
313311
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
314312
pub fn new(min_size_bytes: usize) -> Result<Self> {
315-
use libc::{
316-
MAP_ANONYMOUS, MAP_FAILED, MAP_NORESERVE, MAP_SHARED, PROT_NONE, PROT_READ, PROT_WRITE,
317-
c_int, mmap, mprotect, off_t, size_t,
318-
};
319-
320-
use crate::error::HyperlightError::{MemoryRequestTooBig, MmapFailed, MprotectFailed};
313+
#[cfg(miri)]
314+
use libc::MAP_PRIVATE;
315+
use libc::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE, c_int, mmap, off_t, size_t};
316+
#[cfg(not(miri))]
317+
use libc::{MAP_NORESERVE, MAP_SHARED, PROT_NONE, mprotect};
321318

322319
if min_size_bytes == 0 {
323320
return Err(new_error!("Cannot create shared memory with size 0"));
@@ -337,39 +334,55 @@ impl ExclusiveSharedMemory {
337334
// usize and isize are guaranteed to be the same size, and
338335
// isize::MAX should be positive, so this cast should be safe.
339336
if total_size > isize::MAX as usize {
340-
return Err(MemoryRequestTooBig(total_size, isize::MAX as usize));
337+
return Err(HyperlightError::MemoryRequestTooBig(
338+
total_size,
339+
isize::MAX as usize,
340+
));
341341
}
342342

343343
// allocate the memory
344+
#[cfg(not(miri))]
345+
let flags = MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE;
346+
#[cfg(miri)]
347+
let flags = MAP_ANONYMOUS | MAP_PRIVATE;
348+
344349
let addr = unsafe {
345350
mmap(
346351
null_mut(),
347352
total_size as size_t,
348353
PROT_READ | PROT_WRITE,
349-
MAP_ANONYMOUS | MAP_SHARED | MAP_NORESERVE,
354+
flags,
350355
-1 as c_int,
351356
0 as off_t,
352357
)
353358
};
354359
if addr == MAP_FAILED {
355-
log_then_return!(MmapFailed(Error::last_os_error().raw_os_error()));
360+
log_then_return!(HyperlightError::MmapFailed(
361+
Error::last_os_error().raw_os_error()
362+
));
356363
}
357364

358365
// protect the guard pages
359-
360-
let res = unsafe { mprotect(addr, PAGE_SIZE_USIZE, PROT_NONE) };
361-
if res != 0 {
362-
return Err(MprotectFailed(Error::last_os_error().raw_os_error()));
363-
}
364-
let res = unsafe {
365-
mprotect(
366-
(addr as *const u8).add(total_size - PAGE_SIZE_USIZE) as *mut c_void,
367-
PAGE_SIZE_USIZE,
368-
PROT_NONE,
369-
)
370-
};
371-
if res != 0 {
372-
return Err(MprotectFailed(Error::last_os_error().raw_os_error()));
366+
#[cfg(not(miri))]
367+
{
368+
let res = unsafe { mprotect(addr, PAGE_SIZE_USIZE, PROT_NONE) };
369+
if res != 0 {
370+
return Err(HyperlightError::MprotectFailed(
371+
Error::last_os_error().raw_os_error(),
372+
));
373+
}
374+
let res = unsafe {
375+
mprotect(
376+
(addr as *const u8).add(total_size - PAGE_SIZE_USIZE) as *mut c_void,
377+
PAGE_SIZE_USIZE,
378+
PROT_NONE,
379+
)
380+
};
381+
if res != 0 {
382+
return Err(HyperlightError::MprotectFailed(
383+
Error::last_os_error().raw_os_error(),
384+
));
385+
}
373386
}
374387

375388
Ok(Self {
@@ -414,7 +427,10 @@ impl ExclusiveSharedMemory {
414427
// usize and isize are guaranteed to be the same size, and
415428
// isize::MAX should be positive, so this cast should be safe.
416429
if total_size > isize::MAX as usize {
417-
return Err(MemoryRequestTooBig(total_size, isize::MAX as usize));
430+
return Err(HyperlightError::MemoryRequestTooBig(
431+
total_size,
432+
isize::MAX as usize,
433+
));
418434
}
419435

420436
let mut dwmaximumsizehigh = 0;
@@ -442,7 +458,7 @@ impl ExclusiveSharedMemory {
442458
};
443459

444460
if handle.is_invalid() {
445-
log_then_return!(MemoryAllocationFailed(
461+
log_then_return!(HyperlightError::MemoryAllocationFailed(
446462
Error::last_os_error().raw_os_error()
447463
));
448464
}
@@ -451,7 +467,7 @@ impl ExclusiveSharedMemory {
451467
let addr = unsafe { MapViewOfFile(handle, file_map, 0, 0, 0) };
452468

453469
if addr.Value.is_null() {
454-
log_then_return!(MemoryAllocationFailed(
470+
log_then_return!(HyperlightError::MemoryAllocationFailed(
455471
Error::last_os_error().raw_os_error()
456472
));
457473
}
@@ -646,7 +662,7 @@ pub trait SharedMemory {
646662
/// not need to be marked as `unsafe` because doing anything with
647663
/// this pointer itself requires `unsafe`.
648664
fn base_ptr(&self) -> *mut u8 {
649-
self.base_addr() as *mut u8
665+
self.region().ptr.wrapping_add(PAGE_SIZE_USIZE)
650666
}
651667

652668
/// Return the length of usable memory contained in `self`.
@@ -965,10 +981,14 @@ impl SharedMemory for HostSharedMemory {
965981
#[cfg(test)]
966982
mod tests {
967983
use hyperlight_common::mem::PAGE_SIZE_USIZE;
984+
#[cfg(not(miri))]
968985
use proptest::prelude::*;
969986

970-
use super::{ExclusiveSharedMemory, HostSharedMemory, SharedMemory};
987+
#[cfg(not(miri))]
988+
use super::HostSharedMemory;
989+
use super::{ExclusiveSharedMemory, SharedMemory};
971990
use crate::Result;
991+
#[cfg(not(miri))]
972992
use crate::mem::shared_mem_tests::read_write_test_suite;
973993

974994
#[test]
@@ -1059,6 +1079,8 @@ mod tests {
10591079
Ok(())
10601080
}
10611081

1082+
// proptest uses file I/O (getcwd, open) which miri doesn't support
1083+
#[cfg(not(miri))]
10621084
proptest! {
10631085
#[test]
10641086
fn read_write_i32(val in -0x1000_i32..0x1000_i32) {
@@ -1238,6 +1260,7 @@ mod tests {
12381260

12391261
// provides a way for running the above tests in a separate process since they expect to crash
12401262
#[test]
1263+
#[cfg_attr(miri, ignore)] // miri can't spawn subprocesses
12411264
fn guard_page_testing_shim() {
12421265
let tests = vec!["read", "write", "exec"];
12431266
for test in tests {

src/tests/rust_guests/simpleguest/Cargo.lock

Lines changed: 6 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)