1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#[macro_export]
macro_rules! strcmp_tests {
    ( $TestRegion:path ) => {
        use libc::{c_char, c_int, c_void, strcmp};
        use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
        use lucet_runtime::{lucet_hostcall, Error, Limits, Region, Val, WASM_PAGE_SIZE};
        use std::ffi::CString;
        use std::sync::Arc;
        use $TestRegion as TestRegion;
        use $crate::build::test_module_c;

        #[lucet_hostcall]
        #[no_mangle]
        pub fn hostcall_host_fault(_vmctx: &mut Vmctx) {
            let oob = (-1isize) as *mut c_char;
            unsafe {
                *oob = 'x' as c_char;
            }
        }

        fn strcmp_compare(s1: &str, s2: &str) {
            let s1 = CString::new(s1)
                .expect("s1 is a valid CString")
                .into_bytes_with_nul();
            let s2 = CString::new(s2)
                .expect("s2 is a valid CString")
                .into_bytes_with_nul();

            assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize);

            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds");
            let heap = inst.heap_mut();

            let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize;
            let s2_ptr = s1_ptr + s1.len();
            heap[s1_ptr..s2_ptr].copy_from_slice(&s1);
            heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2);

            let res = c_int::from(
                inst.run(
                    "run_strcmp",
                    &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)],
                )
                .expect("instance runs")
                .unwrap_returned(),
            );

            let host_strcmp_res =
                unsafe { strcmp(s1.as_ptr() as *const c_char, s2.as_ptr() as *const c_char) };
            assert_eq!(res, host_strcmp_res);
        }

        #[test]
        fn strcmp_abc_abc() {
            strcmp_compare("abc", "abc");
        }

        #[test]
        fn strcmp_def_abc() {
            strcmp_compare("def", "abc");
        }

        #[test]
        fn strcmp_abcd_abc() {
            strcmp_compare("abcd", "abc");
        }

        #[test]
        fn strcmp_abc_abcd() {
            strcmp_compare("abc", "abcd");
        }

        #[test]
        fn strcmp_fault_test() {
            let module = test_module_c("strcmp", "guest.c").expect("compile module");
            let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
            let mut inst = region
                .new_instance(module)
                .expect("instance can be created");

            match inst.run("wasm_fault", &[]) {
                Err(Error::RuntimeFault { .. }) => (),
                res => panic!("unexpected result: {:?}", res),
            }
        }
    };
}