1#[macro_export]
2macro_rules! alloc_tests {
3 ( $TestRegion:path ) => {
4 use libc::c_void;
5 use std::sync::Arc;
6 use $TestRegion as TestRegion;
7 use $crate::alloc::{host_page_size, Limits, MINSIGSTKSZ};
8 use $crate::context::{Context, ContextHandle};
9 use $crate::error::Error;
10 use $crate::instance::InstanceInternal;
11 use $crate::module::{GlobalValue, HeapSpec, MockModuleBuilder};
12 use $crate::region::Region;
13 use $crate::val::Val;
14
15 const LIMITS_HEAP_MEM_SIZE: usize = 16 * 64 * 1024;
16 const LIMITS_HEAP_ADDRSPACE_SIZE: usize = 8 * 1024 * 1024;
17 const LIMITS_STACK_SIZE: usize = 64 * 1024;
18 const LIMITS_GLOBALS_SIZE: usize = 4 * 1024;
19
20 const LIMITS: Limits = Limits {
21 heap_memory_size: LIMITS_HEAP_MEM_SIZE,
22 heap_address_space_size: LIMITS_HEAP_ADDRSPACE_SIZE,
23 stack_size: LIMITS_STACK_SIZE,
24 globals_size: LIMITS_GLOBALS_SIZE,
25 ..Limits::default()
26 };
27
28 const SPEC_HEAP_RESERVED_SIZE: u64 = LIMITS_HEAP_ADDRSPACE_SIZE as u64 / 2;
29 const SPEC_HEAP_GUARD_SIZE: u64 = LIMITS_HEAP_ADDRSPACE_SIZE as u64 / 2;
30
31 const ONEPAGE_INITIAL_SIZE: u64 = 64 * 1024;
33 const ONEPAGE_MAX_SIZE: u64 = 64 * 1024;
34
35 const ONE_PAGE_HEAP: HeapSpec = HeapSpec {
36 reserved_size: SPEC_HEAP_RESERVED_SIZE,
37 guard_size: SPEC_HEAP_GUARD_SIZE,
38 initial_size: ONEPAGE_INITIAL_SIZE,
39 max_size: Some(ONEPAGE_MAX_SIZE),
40 };
41
42 const THREEPAGE_INITIAL_SIZE: u64 = 64 * 1024;
43 const THREEPAGE_MAX_SIZE: u64 = 3 * 64 * 1024;
44
45 const THREE_PAGE_MAX_HEAP: HeapSpec = HeapSpec {
46 reserved_size: SPEC_HEAP_RESERVED_SIZE,
47 guard_size: 0,
48 initial_size: THREEPAGE_INITIAL_SIZE,
49 max_size: Some(THREEPAGE_MAX_SIZE),
50 };
51
52 #[test]
55 fn allocate_runtime_works() {
56 let region = TestRegion::create(1, &LIMITS).expect("region created");
57 let mut inst = region
58 .new_instance(
59 MockModuleBuilder::new()
60 .with_heap_spec(ONE_PAGE_HEAP)
61 .build(),
62 )
63 .expect("new_instance succeeds");
64
65 let heap_len = inst.alloc().heap_len();
66 assert_eq!(heap_len, ONEPAGE_INITIAL_SIZE as usize);
67
68 let heap = unsafe { inst.alloc_mut().heap_mut() };
69
70 assert_eq!(heap[0], 0);
71 heap[0] = 0xFF;
72 assert_eq!(heap[0], 0xFF);
73
74 assert_eq!(heap[heap_len - 1], 0);
75 heap[heap_len - 1] = 0xFF;
76 assert_eq!(heap[heap_len - 1], 0xFF);
77
78 let stack = unsafe { inst.alloc_mut().stack_mut() };
79 assert_eq!(stack.len(), LIMITS_STACK_SIZE);
80
81 assert_eq!(stack[0], 0);
82 stack[0] = 0xFF;
83 assert_eq!(stack[0], 0xFF);
84
85 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0);
86 stack[LIMITS_STACK_SIZE - 1] = 0xFF;
87 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0xFF);
88 }
89
90 #[test]
92 fn expand_heap_once() {
93 expand_heap_once_template(THREE_PAGE_MAX_HEAP)
94 }
95
96 fn expand_heap_once_template(heap_spec: HeapSpec) {
97 let region = TestRegion::create(1, &LIMITS).expect("region created");
98 let module = MockModuleBuilder::new()
99 .with_heap_spec(heap_spec.clone())
100 .build();
101 let mut inst = region
102 .new_instance(module.clone())
103 .expect("new_instance succeeds");
104
105 let heap_len = inst.alloc().heap_len();
106 assert_eq!(heap_len, heap_spec.initial_size as usize);
107
108 let new_heap_area = inst
109 .alloc_mut()
110 .expand_heap(64 * 1024, module.as_ref())
111 .expect("expand_heap succeeds");
112 assert_eq!(heap_len, new_heap_area as usize);
113
114 let new_heap_len = inst.alloc().heap_len();
115 assert_eq!(new_heap_len, heap_len + (64 * 1024));
116
117 let heap = unsafe { inst.alloc_mut().heap_mut() };
118 assert_eq!(heap[new_heap_len - 1], 0);
119 heap[new_heap_len - 1] = 0xFF;
120 assert_eq!(heap[new_heap_len - 1], 0xFF);
121 }
122
123 #[test]
125 fn expand_heap_twice() {
126 let region = TestRegion::create(1, &LIMITS).expect("region created");
127 let module = MockModuleBuilder::new()
128 .with_heap_spec(THREE_PAGE_MAX_HEAP)
129 .build();
130 let mut inst = region
131 .new_instance(module.clone())
132 .expect("new_instance succeeds");
133
134 let heap_len = inst.alloc().heap_len();
135 assert_eq!(heap_len, THREEPAGE_INITIAL_SIZE as usize);
136
137 let new_heap_area = inst
138 .alloc_mut()
139 .expand_heap(64 * 1024, module.as_ref())
140 .expect("expand_heap succeeds");
141 assert_eq!(heap_len, new_heap_area as usize);
142
143 let new_heap_len = inst.alloc().heap_len();
144 assert_eq!(new_heap_len, heap_len + (64 * 1024));
145
146 let second_new_heap_area = inst
147 .alloc_mut()
148 .expand_heap(64 * 1024, module.as_ref())
149 .expect("expand_heap succeeds");
150 assert_eq!(new_heap_len, second_new_heap_area as usize);
151
152 let second_new_heap_len = inst.alloc().heap_len();
153 assert_eq!(second_new_heap_len as u64, THREEPAGE_MAX_SIZE);
154
155 let heap = unsafe { inst.alloc_mut().heap_mut() };
156 assert_eq!(heap[new_heap_len - 1], 0);
157 heap[new_heap_len - 1] = 0xFF;
158 assert_eq!(heap[new_heap_len - 1], 0xFF);
159 }
160
161 #[test]
165 fn expand_past_spec_max() {
166 let region = TestRegion::create(10, &LIMITS).expect("region created");
167 let module = MockModuleBuilder::new()
168 .with_heap_spec(THREE_PAGE_MAX_HEAP)
169 .build();
170 let mut inst = region
171 .new_instance(module.clone())
172 .expect("new_instance succeeds");
173
174 let heap_len = inst.alloc().heap_len();
175 assert_eq!(heap_len, THREEPAGE_INITIAL_SIZE as usize);
176
177 let new_heap_area = inst
178 .alloc_mut()
179 .expand_heap(THREEPAGE_MAX_SIZE as u32, module.as_ref());
180 assert!(new_heap_area.is_err(), "heap expansion past spec fails");
181
182 let new_heap_len = inst.alloc().heap_len();
183 assert_eq!(new_heap_len, heap_len);
184
185 let heap = unsafe { inst.alloc_mut().heap_mut() };
186 assert_eq!(heap[new_heap_len - 1], 0);
187 heap[new_heap_len - 1] = 0xFF;
188 assert_eq!(heap[new_heap_len - 1], 0xFF);
189 }
190
191 const EXPANDPASTLIMIT_INITIAL_SIZE: u64 = LIMITS_HEAP_MEM_SIZE as u64 - (64 * 1024);
192 const EXPANDPASTLIMIT_MAX_SIZE: u64 = LIMITS_HEAP_MEM_SIZE as u64 + (64 * 1024);
193 const EXPAND_PAST_LIMIT_SPEC: HeapSpec = HeapSpec {
194 reserved_size: SPEC_HEAP_RESERVED_SIZE,
195 guard_size: SPEC_HEAP_GUARD_SIZE,
196 initial_size: EXPANDPASTLIMIT_INITIAL_SIZE,
197 max_size: Some(EXPANDPASTLIMIT_MAX_SIZE),
198 };
199
200 #[test]
204 fn expand_past_heap_limit() {
205 let region = TestRegion::create(10, &LIMITS).expect("region created");
206 let module = MockModuleBuilder::new()
207 .with_heap_spec(EXPAND_PAST_LIMIT_SPEC)
208 .build();
209 let mut inst = region
210 .new_instance(module.clone())
211 .expect("new_instance succeeds");
212
213 let heap_len = inst.alloc().heap_len();
214 assert_eq!(heap_len, EXPANDPASTLIMIT_INITIAL_SIZE as usize);
215
216 let new_heap_area = inst
217 .alloc_mut()
218 .expand_heap(64 * 1024, module.as_ref())
219 .expect("expand_heap succeeds");
220 assert_eq!(heap_len, new_heap_area as usize);
221
222 let new_heap_len = inst.alloc().heap_len();
223 assert_eq!(new_heap_len, LIMITS_HEAP_MEM_SIZE);
224
225 let past_limit_heap_area = inst.alloc_mut().expand_heap(64 * 1024, module.as_ref());
226 assert!(
227 past_limit_heap_area.is_err(),
228 "heap expansion past limit fails"
229 );
230
231 let still_heap_len = inst.alloc().heap_len();
232 assert_eq!(still_heap_len, LIMITS_HEAP_MEM_SIZE);
233
234 let heap = unsafe { inst.alloc_mut().heap_mut() };
235 assert_eq!(heap[new_heap_len - 1], 0);
236 heap[new_heap_len - 1] = 0xFF;
237 assert_eq!(heap[new_heap_len - 1], 0xFF);
238 }
239
240 const INITIAL_OVERSIZE_HEAP: HeapSpec = HeapSpec {
241 reserved_size: SPEC_HEAP_RESERVED_SIZE,
242 guard_size: SPEC_HEAP_GUARD_SIZE,
243 initial_size: SPEC_HEAP_RESERVED_SIZE + (64 * 1024),
244 max_size: None,
245 };
246
247 #[test]
251 fn reject_initial_oversize_heap() {
252 let region = TestRegion::create(10, &LIMITS).expect("region created");
253 let res = region.new_instance(
254 MockModuleBuilder::new()
255 .with_heap_spec(INITIAL_OVERSIZE_HEAP)
256 .build(),
257 );
258 assert!(res.is_err(), "new_instance fails");
259 }
260
261 #[test]
263 fn reject_undersized_address_space() {
264 const LIMITS: Limits = Limits {
265 heap_memory_size: LIMITS_HEAP_ADDRSPACE_SIZE + 4096,
266 heap_address_space_size: LIMITS_HEAP_ADDRSPACE_SIZE,
267 stack_size: LIMITS_STACK_SIZE,
268 globals_size: LIMITS_GLOBALS_SIZE,
269 ..Limits::default()
270 };
271 let res = TestRegion::create(10, &LIMITS);
272 assert!(res.is_err(), "region creation fails");
273 }
274
275 const SMALL_GUARD_HEAP: HeapSpec = HeapSpec {
276 reserved_size: SPEC_HEAP_RESERVED_SIZE,
277 guard_size: SPEC_HEAP_GUARD_SIZE - 1,
278 initial_size: LIMITS_HEAP_MEM_SIZE as u64,
279 max_size: None,
280 };
281
282 #[test]
285 fn accept_small_guard_heap() {
286 let region = TestRegion::create(1, &LIMITS).expect("region created");
287 let _inst = region
288 .new_instance(
289 MockModuleBuilder::new()
290 .with_heap_spec(SMALL_GUARD_HEAP)
291 .build(),
292 )
293 .expect("new_instance succeeds");
294 }
295
296 const LARGE_GUARD_HEAP: HeapSpec = HeapSpec {
297 reserved_size: SPEC_HEAP_RESERVED_SIZE,
298 guard_size: SPEC_HEAP_GUARD_SIZE + 1,
299 initial_size: ONEPAGE_INITIAL_SIZE,
300 max_size: None,
301 };
302
303 #[test]
306 fn reject_large_guard_heap() {
307 let region = TestRegion::create(1, &LIMITS).expect("region created");
308 let res = region.new_instance(
309 MockModuleBuilder::new()
310 .with_heap_spec(LARGE_GUARD_HEAP)
311 .build(),
312 );
313 assert!(res.is_err(), "new_instance fails");
314 }
315
316 #[test]
319 fn reuse_slot_works() {
320 fn peek_n_poke(region: &Arc<TestRegion>) {
321 let mut inst = region
322 .new_instance(
323 MockModuleBuilder::new()
324 .with_heap_spec(ONE_PAGE_HEAP)
325 .build(),
326 )
327 .expect("new_instance succeeds");
328
329 let heap_len = inst.alloc().heap_len();
330 assert_eq!(heap_len, ONEPAGE_INITIAL_SIZE as usize);
331
332 let heap = unsafe { inst.alloc_mut().heap_mut() };
333
334 assert_eq!(heap[0], 0);
335 heap[0] = 0xFF;
336 assert_eq!(heap[0], 0xFF);
337
338 assert_eq!(heap[heap_len - 1], 0);
339 heap[heap_len - 1] = 0xFF;
340 assert_eq!(heap[heap_len - 1], 0xFF);
341
342 let stack = unsafe { inst.alloc_mut().stack_mut() };
343 assert_eq!(stack.len(), LIMITS_STACK_SIZE);
344
345 assert_eq!(stack[0], 0);
346 stack[0] = 0xFF;
347 assert_eq!(stack[0], 0xFF);
348
349 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0);
350 stack[LIMITS_STACK_SIZE - 1] = 0xFF;
351 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0xFF);
352
353 let globals = unsafe { inst.alloc_mut().globals_mut() };
354 assert_eq!(
355 globals.len(),
356 LIMITS_GLOBALS_SIZE / std::mem::size_of::<GlobalValue>()
357 );
358
359 unsafe {
360 assert_eq!(globals[0].i_64, 0);
361 globals[0].i_64 = 0xFF;
362 assert_eq!(globals[0].i_64, 0xFF);
363 }
364
365 unsafe {
366 assert_eq!(globals[globals.len() - 1].i_64, 0);
367 globals[globals.len() - 1].i_64 = 0xFF;
368 assert_eq!(globals[globals.len() - 1].i_64, 0xFF);
369 }
370
371 let sigstack = unsafe { inst.alloc_mut().sigstack_mut() };
372 assert_eq!(sigstack.len(), LIMITS.signal_stack_size);
373
374 assert_eq!(sigstack[0], 0);
375 sigstack[0] = 0xFF;
376 assert_eq!(sigstack[0], 0xFF);
377
378 assert_eq!(sigstack[sigstack.len() - 1], 0);
379 sigstack[sigstack.len() - 1] = 0xFF;
380 assert_eq!(sigstack[sigstack.len() - 1], 0xFF);
381 }
382
383 let region = TestRegion::create(1, &LIMITS).expect("region created");
385
386 peek_n_poke(®ion);
387 peek_n_poke(®ion);
388 }
389
390 #[test]
392 fn alloc_reset() {
393 let region = TestRegion::create(1, &LIMITS).expect("region created");
394 let module = MockModuleBuilder::new()
395 .with_heap_spec(THREE_PAGE_MAX_HEAP)
396 .build();
397 let mut inst = region
398 .new_instance(module.clone())
399 .expect("new_instance succeeds");
400
401 let heap_len = inst.alloc().heap_len();
402 assert_eq!(heap_len, THREEPAGE_INITIAL_SIZE as usize);
403
404 let heap = unsafe { inst.alloc_mut().heap_mut() };
405
406 assert_eq!(heap[0], 0);
407 heap[0] = 0xFF;
408 assert_eq!(heap[0], 0xFF);
409
410 assert_eq!(heap[heap_len - 1], 0);
411 heap[heap_len - 1] = 0xFF;
412 assert_eq!(heap[heap_len - 1], 0xFF);
413
414 inst.alloc_mut()
418 .reset_heap(module.as_ref())
419 .expect("reset succeeds");
420
421 let reset_heap_len = inst.alloc().heap_len();
422 assert_eq!(reset_heap_len, THREEPAGE_INITIAL_SIZE as usize);
423
424 let heap = unsafe { inst.alloc_mut().heap_mut() };
425
426 assert_eq!(heap[0], 0);
427 heap[0] = 0xFF;
428 assert_eq!(heap[0], 0xFF);
429
430 assert_eq!(heap[reset_heap_len - 1], 0);
431 heap[reset_heap_len - 1] = 0xFF;
432 assert_eq!(heap[reset_heap_len - 1], 0xFF);
433 }
434
435 #[test]
438 fn alloc_grow_reset() {
439 let region = TestRegion::create(1, &LIMITS).expect("region created");
440 let module = MockModuleBuilder::new()
441 .with_heap_spec(THREE_PAGE_MAX_HEAP)
442 .build();
443 let mut inst = region
444 .new_instance(module.clone())
445 .expect("new_instance succeeds");
446
447 let heap_len = inst.alloc().heap_len();
448 assert_eq!(heap_len, THREEPAGE_INITIAL_SIZE as usize);
449
450 let heap = unsafe { inst.alloc_mut().heap_mut() };
451
452 assert_eq!(heap[0], 0);
453 heap[0] = 0xFF;
454 assert_eq!(heap[0], 0xFF);
455
456 assert_eq!(heap[heap_len - 1], 0);
457 heap[heap_len - 1] = 0xFF;
458 assert_eq!(heap[heap_len - 1], 0xFF);
459
460 let new_heap_area = inst
461 .alloc_mut()
462 .expand_heap(
463 (THREEPAGE_MAX_SIZE - THREEPAGE_INITIAL_SIZE) as u32,
464 module.as_ref(),
465 )
466 .expect("expand_heap succeeds");
467 assert_eq!(heap_len, new_heap_area as usize);
468
469 let new_heap_len = inst.alloc().heap_len();
470 assert_eq!(new_heap_len, THREEPAGE_MAX_SIZE as usize);
471
472 inst.alloc_mut()
476 .reset_heap(module.as_ref())
477 .expect("reset succeeds");
478
479 let reset_heap_len = inst.alloc().heap_len();
480 assert_eq!(reset_heap_len, THREEPAGE_INITIAL_SIZE as usize);
481
482 let heap = unsafe { inst.alloc_mut().heap_mut() };
483
484 assert_eq!(heap[0], 0);
485 heap[0] = 0xFF;
486 assert_eq!(heap[0], 0xFF);
487
488 assert_eq!(heap[reset_heap_len - 1], 0);
489 heap[reset_heap_len - 1] = 0xFF;
490 assert_eq!(heap[reset_heap_len - 1], 0xFF);
491 }
492
493 const GUARDLESS_HEAP: HeapSpec = HeapSpec {
494 reserved_size: SPEC_HEAP_RESERVED_SIZE,
495 guard_size: 0,
496 initial_size: ONEPAGE_INITIAL_SIZE,
497 max_size: None,
498 };
499
500 #[test]
502 fn guardless_heap_create() {
503 let region = TestRegion::create(1, &LIMITS).expect("region created");
504 let mut inst = region
505 .new_instance(
506 MockModuleBuilder::new()
507 .with_heap_spec(GUARDLESS_HEAP)
508 .build(),
509 )
510 .expect("new_instance succeeds");
511
512 let heap_len = inst.alloc().heap_len();
513 assert_eq!(heap_len, ONEPAGE_INITIAL_SIZE as usize);
514
515 let heap = unsafe { inst.alloc_mut().heap_mut() };
516
517 assert_eq!(heap[0], 0);
518 heap[0] = 0xFF;
519 assert_eq!(heap[0], 0xFF);
520
521 assert_eq!(heap[heap_len - 1], 0);
522 heap[heap_len - 1] = 0xFF;
523 assert_eq!(heap[heap_len - 1], 0xFF);
524
525 let stack = unsafe { inst.alloc_mut().stack_mut() };
526 assert_eq!(stack.len(), LIMITS_STACK_SIZE);
527
528 assert_eq!(stack[0], 0);
529 stack[0] = 0xFF;
530 assert_eq!(stack[0], 0xFF);
531
532 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0);
533 stack[LIMITS_STACK_SIZE - 1] = 0xFF;
534 assert_eq!(stack[LIMITS_STACK_SIZE - 1], 0xFF);
535 }
536
537 #[test]
539 fn guardless_expand_heap_once() {
540 expand_heap_once_template(GUARDLESS_HEAP)
541 }
542
543 const INITIAL_EMPTY_HEAP: HeapSpec = HeapSpec {
544 reserved_size: SPEC_HEAP_RESERVED_SIZE,
545 guard_size: SPEC_HEAP_GUARD_SIZE,
546 initial_size: 0,
547 max_size: None,
548 };
549
550 #[test]
552 fn initial_empty_expand_heap_once() {
553 expand_heap_once_template(INITIAL_EMPTY_HEAP)
554 }
555
556 const INITIAL_EMPTY_GUARDLESS_HEAP: HeapSpec = HeapSpec {
557 reserved_size: SPEC_HEAP_RESERVED_SIZE,
558 guard_size: 0,
559 initial_size: 0,
560 max_size: None,
561 };
562
563 #[test]
566 fn initial_empty_guardless_expand_heap_once() {
567 expand_heap_once_template(INITIAL_EMPTY_GUARDLESS_HEAP)
568 }
569
570 const CONTEXT_TEST_LIMITS: Limits = Limits {
571 heap_memory_size: 4096,
572 heap_address_space_size: 2 * 4096,
573 stack_size: 4096,
574 globals_size: 4096,
575 ..Limits::default()
576 };
577 const CONTEXT_TEST_INITIAL_SIZE: u64 = 4096;
578 const CONTEXT_TEST_HEAP: HeapSpec = HeapSpec {
579 reserved_size: 4096,
580 guard_size: 4096,
581 initial_size: CONTEXT_TEST_INITIAL_SIZE,
582 max_size: Some(4096),
583 };
584
585 #[test]
588 fn context_alloc_child() {
589 extern "C" fn heap_touching_child(heap: *mut u8) {
590 let heap = unsafe {
591 std::slice::from_raw_parts_mut(heap, CONTEXT_TEST_INITIAL_SIZE as usize)
592 };
593 heap[0] = 123;
594 heap[4095] = 45;
595 }
596
597 let region = TestRegion::create(1, &CONTEXT_TEST_LIMITS).expect("region created");
598 let mut inst = region
599 .new_instance(
600 MockModuleBuilder::new()
601 .with_heap_spec(CONTEXT_TEST_HEAP)
602 .build(),
603 )
604 .expect("new_instance succeeds");
605
606 let mut parent = ContextHandle::new();
607 unsafe {
608 let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void;
609 let mut child = ContextHandle::create_and_init(
610 inst.alloc_mut().stack_u64_mut(),
611 heap_touching_child as usize,
612 &[Val::CPtr(heap_ptr)],
613 )
614 .expect("context init succeeds");
615 Context::swap(&mut parent, &mut child);
616 assert_eq!(inst.alloc().heap()[0], 123);
617 assert_eq!(inst.alloc().heap()[4095], 45);
618 }
619 }
620
621 #[test]
625 fn context_stack_pattern() {
626 const STACK_PATTERN_LENGTH: usize = 1024;
627 extern "C" fn stack_pattern_child(heap: *mut u64) {
628 let heap = unsafe {
629 std::slice::from_raw_parts_mut(heap, CONTEXT_TEST_INITIAL_SIZE as usize / 8)
630 };
631 let mut onthestack = [0u8; STACK_PATTERN_LENGTH];
632 let mut ignored = [0u8; STACK_PATTERN_LENGTH];
639 for i in 0..STACK_PATTERN_LENGTH {
640 ignored[i] = (i % 256) as u8;
641 onthestack[i] = (i % 256) as u8;
642 }
643 heap[0] = onthestack.as_ptr() as u64;
644 }
645
646 let region = TestRegion::create(1, &CONTEXT_TEST_LIMITS).expect("region created");
647 let mut inst = region
648 .new_instance(
649 MockModuleBuilder::new()
650 .with_heap_spec(CONTEXT_TEST_HEAP)
651 .build(),
652 )
653 .expect("new_instance succeeds");
654
655 let mut parent = ContextHandle::new();
656 unsafe {
657 let heap_ptr = inst.alloc_mut().heap_mut().as_ptr() as *mut c_void;
658 let mut child = ContextHandle::create_and_init(
659 inst.alloc_mut().stack_u64_mut(),
660 stack_pattern_child as usize,
661 &[Val::CPtr(heap_ptr)],
662 )
663 .expect("context init succeeds");
664 Context::swap(&mut parent, &mut child);
665
666 let stack_pattern = inst.alloc().heap_u64()[0] as usize;
667 assert!(stack_pattern > inst.alloc().slot().stack as usize);
668 assert!(
669 stack_pattern + STACK_PATTERN_LENGTH < inst.alloc().slot().stack_top() as usize
670 );
671 let stack_pattern =
672 std::slice::from_raw_parts(stack_pattern as *const u8, STACK_PATTERN_LENGTH);
673 for i in 0..STACK_PATTERN_LENGTH {
674 assert_eq!(stack_pattern[i], (i % 256) as u8);
675 }
676 }
677 }
678
679 #[test]
680 fn drop_region_first() {
681 let region = TestRegion::create(1, &Limits::default()).expect("region can be created");
682 let inst = region
683 .new_instance(MockModuleBuilder::new().build())
684 .expect("new_instance succeeds");
685 drop(region);
686 drop(inst);
687 }
688
689 #[test]
690 fn slot_counts_work() {
691 let module = MockModuleBuilder::new()
692 .with_heap_spec(ONE_PAGE_HEAP)
693 .build();
694 let region = TestRegion::create(2, &LIMITS).expect("region created");
695 assert_eq!(region.capacity(), 2);
696 assert_eq!(region.free_slots(), 2);
697 assert_eq!(region.used_slots(), 0);
698 let inst1 = region
699 .new_instance(module.clone())
700 .expect("new_instance succeeds");
701 assert_eq!(region.capacity(), 2);
702 assert_eq!(region.free_slots(), 1);
703 assert_eq!(region.used_slots(), 1);
704 let inst2 = region.new_instance(module).expect("new_instance succeeds");
705 assert_eq!(region.capacity(), 2);
706 assert_eq!(region.free_slots(), 0);
707 assert_eq!(region.used_slots(), 2);
708 drop(inst1);
709 assert_eq!(region.capacity(), 2);
710 assert_eq!(region.free_slots(), 1);
711 assert_eq!(region.used_slots(), 1);
712 drop(inst2);
713 assert_eq!(region.capacity(), 2);
714 assert_eq!(region.free_slots(), 2);
715 assert_eq!(region.used_slots(), 0);
716 }
717
718 #[test]
719 fn reject_sigstack_smaller_than_min() {
720 if MINSIGSTKSZ == 0 {
721 return;
723 }
724 let limits = Limits {
725 signal_stack_size: (MINSIGSTKSZ.checked_sub(1).unwrap() / host_page_size())
727 * host_page_size(),
728 ..Limits::default()
729 };
730 let res = TestRegion::create(1, &limits);
731 match res {
732 Err(Error::InvalidArgument(
733 "signal stack size must be at least MINSIGSTKSZ (defined in <signal.h>)",
734 )) => (),
735 Err(e) => panic!("unexpected error: {}", e),
736 Ok(_) => panic!("unexpected success"),
737 }
738 }
739
740 #[test]
743 #[cfg(debug_assertions)]
744 fn reject_debug_sigstack_smaller_than_12kib() {
745 if 8192 < MINSIGSTKSZ {
746 return;
748 }
749 let limits = Limits {
750 signal_stack_size: 8192,
751 ..Limits::default()
752 };
753 let res = TestRegion::create(1, &limits);
754 match res {
755 Err(Error::InvalidArgument(
756 "signal stack size must be at least 12KiB for debug builds",
757 )) => (),
758 Err(e) => panic!("unexpected error: {}", e),
759 Ok(_) => panic!("unexpected success"),
760 }
761 }
762
763 #[test]
764 fn reject_unaligned_sigstack() {
765 let limits = Limits {
766 signal_stack_size: std::cmp::max(libc::SIGSTKSZ, 12 * 1024)
767 .checked_add(1)
768 .unwrap(),
769 ..Limits::default()
770 };
771 let res = TestRegion::create(1, &limits);
772 match res {
773 Err(Error::InvalidArgument(
774 "signal stack size must be a multiple of host page size",
775 )) => (),
776 Err(e) => panic!("unexpected error: {}", e),
777 Ok(_) => panic!("unexpected success"),
778 }
779 }
780 };
781}
782
783#[cfg(test)]
784alloc_tests!(crate::region::mmap::MmapRegion);