Skip to content
This repository was archived by the owner on Mar 24, 2022. It is now read-only.

Commit b102f48

Browse files
acfoltzertyler
authored andcommitted
enable alloc tests for UffdRegion, add new test, fix some things
- Instantiates the suite in `lucet_runtime_internals::alloc::tests` for `UffdRegion - Fixes early return issues in `UffdRegion` similar to #455 - Adds a test to show that the per-instance heap limit applies to runtime expansions, not just initial instantiation - Refactors `validate_runtime_spec` to take the per-instance heap limit as an additional argument. This centralizes the logic for rejecting initially-oversized heap limits, and makes it clearer what's happening in each region's instantiation logic. - Removes the `UffdRegion`'s assertion that signal stack size is a multiple of page size. Since the user can now control this as a parameter, we reject it gracefully when validating `Limits` rather than panicking.
1 parent f869681 commit b102f48

File tree

4 files changed

+69
-41
lines changed

4 files changed

+69
-41
lines changed

lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs

+60-4
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ macro_rules! alloc_tests {
242242
max_size: Some(EXPANDPASTLIMIT_MAX_SIZE),
243243
};
244244

245-
/// This test shows that a heap refuses to grow past the alloc limits, even if the runtime
246-
/// spec says it can grow bigger. This test uses a region with multiple slots in order to
247-
/// exercise more edge cases with adjacent managed memory.
245+
/// This test shows that a heap refuses to grow past the region's limits, even if the
246+
/// runtime spec says it can grow bigger. This test uses a region with multiple slots in
247+
/// order to exercise more edge cases with adjacent managed memory.
248248
#[test]
249249
fn expand_past_heap_limit() {
250250
let region = TestRegion::create(10, &LIMITS).expect("region created");
@@ -282,6 +282,55 @@ macro_rules! alloc_tests {
282282
assert_eq!(heap[new_heap_len - 1], 0xFF);
283283
}
284284

285+
/// This test shows that a heap refuses to grow past the instance-specific heap limit, even
286+
/// if both the region's limits and the runtime spec says it can grow bigger. This test uses
287+
/// a region with multiple slots in order to exercise more edge cases with adjacent managed
288+
/// memory.
289+
#[test]
290+
fn expand_past_instance_heap_limit() {
291+
const INSTANCE_LIMIT: usize = LIMITS.heap_memory_size / 2;
292+
const SPEC: HeapSpec = HeapSpec {
293+
initial_size: INSTANCE_LIMIT as u64 - 64 * 1024,
294+
..EXPAND_PAST_LIMIT_SPEC
295+
};
296+
assert_eq!(INSTANCE_LIMIT % host_page_size(), 0);
297+
298+
let region = TestRegion::create(10, &LIMITS).expect("region created");
299+
let module = MockModuleBuilder::new().with_heap_spec(SPEC).build();
300+
let mut inst = region
301+
.new_instance_builder(module.clone())
302+
.with_heap_size_limit(INSTANCE_LIMIT)
303+
.build()
304+
.expect("instantiation succeeds");
305+
306+
let heap_len = inst.alloc().heap_len();
307+
assert_eq!(heap_len, SPEC.initial_size as usize);
308+
309+
// fill up the rest of the per-instance limit area
310+
let new_heap_area = inst
311+
.alloc_mut()
312+
.expand_heap(64 * 1024, module.as_ref())
313+
.expect("expand_heap succeeds");
314+
assert_eq!(heap_len, new_heap_area as usize);
315+
316+
let new_heap_len = inst.alloc().heap_len();
317+
assert_eq!(new_heap_len, INSTANCE_LIMIT);
318+
319+
let past_limit_heap_area = inst.alloc_mut().expand_heap(64 * 1024, module.as_ref());
320+
assert!(
321+
past_limit_heap_area.is_err(),
322+
"heap expansion past limit fails"
323+
);
324+
325+
let still_heap_len = inst.alloc().heap_len();
326+
assert_eq!(still_heap_len, INSTANCE_LIMIT);
327+
328+
let heap = unsafe { inst.alloc_mut().heap_mut() };
329+
assert_eq!(heap[new_heap_len - 1], 0);
330+
heap[new_heap_len - 1] = 0xFF;
331+
assert_eq!(heap[new_heap_len - 1], 0xFF);
332+
}
333+
285334
const INITIAL_OVERSIZE_HEAP: HeapSpec = HeapSpec {
286335
reserved_size: SPEC_HEAP_RESERVED_SIZE,
287336
guard_size: SPEC_HEAP_GUARD_SIZE,
@@ -1133,4 +1182,11 @@ macro_rules! alloc_tests {
11331182
}
11341183

11351184
#[cfg(test)]
1136-
alloc_tests!(crate::region::mmap::MmapRegion);
1185+
mod mmap {
1186+
alloc_tests!(crate::region::mmap::MmapRegion);
1187+
}
1188+
1189+
#[cfg(all(test, feature = "uffd"))]
1190+
mod uffd {
1191+
alloc_tests!(crate::region::uffd::UffdRegion);
1192+
}

lucet-runtime/lucet-runtime-internals/src/module.rs

-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ pub trait ModuleInternal: Send + Sync {
118118
));
119119
}
120120
let heap_memory_size = std::cmp::min(limits.heap_memory_size, instance_heap_limit);
121-
122121
// Modules without heap specs will not access the heap
123122
if let Some(heap) = self.heap_spec() {
124123
// Assure that the total reserved + guard regions fit in the address space.

lucet-runtime/lucet-runtime-internals/src/region/mmap.rs

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl RegionInternal for MmapRegion {
8282
mut alloc_strategy: AllocStrategy,
8383
) -> Result<InstanceHandle, Error> {
8484
let limits = self.get_limits();
85+
8586
module.validate_runtime_spec(&limits, heap_memory_size_limit)?;
8687

8788
// Use the supplied alloc_strategy to get the next available slot

lucet-runtime/lucet-runtime-internals/src/region/uffd.rs

100755100644
+8-36
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::{lucet_bail, lucet_ensure, lucet_format_err};
1212
use libc::c_void;
1313
use nix::poll;
1414
use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags};
15-
use std::cmp::Ordering;
1615
use std::os::unix::io::{AsRawFd, RawFd};
1716
use std::ptr;
1817
use std::sync::{Arc, Mutex, Weak};
@@ -217,30 +216,8 @@ impl RegionInternal for UffdRegion {
217216
embed_ctx: CtxMap,
218217
heap_memory_size_limit: usize,
219218
) -> Result<InstanceHandle, Error> {
220-
let custom_limits;
221-
let mut limits = self.get_limits();
222-
223-
// Affirm that the module, if instantiated, would not violate
224-
// any runtime memory limits.
225-
match heap_memory_size_limit.cmp(&limits.heap_memory_size) {
226-
Ordering::Less => {
227-
// The supplied heap_memory_size is smaller than
228-
// default. Augment the limits with this custom value
229-
// so that it may be validated.
230-
custom_limits = Limits {
231-
heap_memory_size: heap_memory_size_limit,
232-
..*limits
233-
};
234-
limits = &custom_limits;
235-
}
236-
Ordering::Equal => (),
237-
Ordering::Greater => {
238-
return Err(Error::InvalidArgument(
239-
"heap memory size requested for instance is larger than slot allows",
240-
))
241-
}
242-
}
243-
module.validate_runtime_spec(&limits)?;
219+
let limits = self.get_limits();
220+
module.validate_runtime_spec(&limits, heap_memory_size_limit)?;
244221

245222
let slot = self
246223
.freelist
@@ -249,12 +226,11 @@ impl RegionInternal for UffdRegion {
249226
.pop()
250227
.ok_or(Error::RegionFull(self.instance_capacity))?;
251228

252-
if slot.heap as usize % host_page_size() != 0 {
253-
lucet_bail!("heap is not page-aligned; this is a bug");
254-
}
255-
256-
let limits = &slot.limits;
257-
module.validate_runtime_spec(limits)?;
229+
assert_eq!(
230+
slot.heap as usize % host_page_size(),
231+
0,
232+
"heap must be page-aligned"
233+
);
258234

259235
for (ptr, len) in [
260236
// zero the globals
@@ -270,7 +246,7 @@ impl RegionInternal for UffdRegion {
270246
unsafe {
271247
self.uffd
272248
.zeropage(*ptr, *len, true)
273-
.map_err(|e| Error::InternalError(e.into()))?;
249+
.expect("uffd.zeropage succeeds");
274250
}
275251
}
276252
}
@@ -410,10 +386,6 @@ impl UffdRegion {
410386
/// This also creates and starts a separate thread that is responsible for handling page faults
411387
/// that occur within the memory region.
412388
pub fn create(instance_capacity: usize, limits: &Limits) -> Result<Arc<Self>, Error> {
413-
assert!(
414-
limits.signal_stack_size % host_page_size() == 0,
415-
"signal stack size is a multiple of host page size"
416-
);
417389
if instance_capacity == 0 {
418390
return Err(Error::InvalidArgument(
419391
"region must be able to hold at least one instance",

0 commit comments

Comments
 (0)