diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index f8f1d93..32210ad 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -270,12 +270,13 @@ impl MemoryRoot { // Get the number of bytes available let mem_left = self_length - self_position - core::mem::size_of::() as u64; + let length_with_block = length + core::mem::size_of::() as u64; // When the allocation is larger than the number of bytes available // we will need to try to grow the memory - if length >= mem_left { + if length_with_block >= mem_left { // Calculate the number of pages needed to cover the remaining bytes - let npages = num_pages(length - mem_left); + let npages = num_pages(length_with_block - mem_left); let x = core::arch::wasm32::memory_grow(0, npages); if x == usize::MAX { return None; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 9fb85dd..9b567ed 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -37,6 +37,8 @@ cbindgen = { version = "0.26", default-features = false } [dev-dependencies] criterion = "0.5.1" +quickcheck = "1" +rand = "0.8.5" [[bench]] name = "bench" diff --git a/runtime/src/extism-runtime.wasm b/runtime/src/extism-runtime.wasm index 27b3220..fe52a5a 100755 Binary files a/runtime/src/extism-runtime.wasm and b/runtime/src/extism-runtime.wasm differ diff --git a/runtime/src/tests/kernel.rs b/runtime/src/tests/kernel.rs index 213df30..5480553 100644 --- a/runtime/src/tests/kernel.rs +++ b/runtime/src/tests/kernel.rs @@ -1,4 +1,5 @@ use crate::*; +use quickcheck::*; const KERNEL: &[u8] = include_bytes!("../extism-runtime.wasm"); @@ -319,3 +320,141 @@ fn test_load_input() { // Out of bounds should return 0 assert_eq!(extism_input_load_u64(&mut store, instance, 123457), 0); } + +#[test] +fn test_failed_quickcheck1() { + let (mut store, mut instance) = init_kernel_test(); + let allocs = [ + 20622, 23162, 58594, 32421, 25928, 44611, 26318, 24455, 5798, 60202, 42126, 64928, 57832, + 50888, 63256, 37562, 46334, 47985, 60836, 28132, 65535, 37800, 33150, 48768, 38457, 57249, + 5734, 58587, 26294, 26653, 24519, 1, + ]; + + extism_reset(&mut store, &mut instance); + for a in allocs { + println!("Alloc: {a}"); + let n = extism_alloc(&mut store, &mut instance, a); + if n == 0 { + continue; + } + assert_eq!(a, extism_length(&mut store, &mut instance, n)); + } +} + +quickcheck! { + fn check_alloc(amounts: Vec) -> bool { + let (mut store, mut instance) = init_kernel_test(); + let instance = &mut instance; + for a in amounts { + let ptr = extism_alloc(&mut store, instance, a as u64); + if ptr == 0 || ptr == u64::MAX { + continue + } + if extism_length(&mut store, instance, ptr) != a as u64 { + return false + } + } + + true + } +} + +quickcheck! { + fn check_large_alloc(amounts: Vec) -> bool { + let (mut store, mut instance) = init_kernel_test(); + let instance = &mut instance; + for a in amounts { + let ptr = extism_alloc(&mut store, instance, a as u64); + if ptr == 0 || ptr == u64::MAX { + continue + } + if extism_length(&mut store, instance, ptr) != a as u64 { + return false + } + } + + true + } +} + +quickcheck! { + fn check_alloc_with_frees(amounts: Vec) -> bool { + let (mut store, mut instance) = init_kernel_test(); + let instance = &mut instance; + let mut prev = 0; + for a in amounts { + let ptr = extism_alloc(&mut store, instance, a as u64); + if ptr == 0 { + continue + } + if extism_length(&mut store, instance, ptr) != a as u64 { + return false + } + + if a % 2 == 0 { + extism_free(&mut store, instance, ptr); + } else if a % 3 == 0 { + extism_free(&mut store, instance, prev); + } + + prev = ptr; + } + + true + } +} + +quickcheck! { + fn check_large_alloc_with_frees(amounts: Vec) -> bool { + let (mut store, mut instance) = init_kernel_test(); + let instance = &mut instance; + let mut prev = 0; + for a in amounts { + let ptr = extism_alloc(&mut store, instance, a as u64); + if ptr == 0 || ptr == u64::MAX { + continue + } + if extism_length(&mut store, instance, ptr) != a as u64 { + return false + } + if a % 2 == 0 { + extism_free(&mut store, instance, ptr); + } else if a % 3 == 0 { + extism_free(&mut store, instance, prev); + } + + prev = ptr; + + } + + true + } +} + +quickcheck! { + fn check_alloc_with_load_and_store(amounts: Vec) -> bool { + use rand::Rng; + let mut rng = rand::thread_rng(); + let (mut store, mut instance) = init_kernel_test(); + let instance = &mut instance; + for a in amounts { + let ptr = extism_alloc(&mut store, instance, a as u64); + if ptr == 0 || ptr == u64::MAX { + continue + } + if extism_length(&mut store, instance, ptr) != a as u64 { + return false + } + + for _ in 0..16 { + let i = rng.gen_range(ptr..ptr+a as u64); + extism_store_u8(&mut store, instance, i, i as u8); + if extism_load_u8(&mut store, instance, i as u64) != i as u8 { + return false + } + } + } + + true + } +} diff --git a/runtime/src/tests/runtime.rs b/runtime/src/tests/runtime.rs index ff5692a..c70f7e6 100644 --- a/runtime/src/tests/runtime.rs +++ b/runtime/src/tests/runtime.rs @@ -39,11 +39,12 @@ pub struct Count { #[test] fn it_works() { - tracing_subscriber::fmt() + let log = tracing_subscriber::fmt() .with_ansi(false) .with_env_filter("extism=debug") .with_writer(std::fs::File::create("test.log").unwrap()) - .init(); + .try_init() + .is_ok(); let wasm_start = Instant::now(); @@ -143,8 +144,10 @@ fn it_works() { println!("wasm function call (avg, N = {}): {:?}", num_tests, avg); // Check that log file was written to - let meta = std::fs::metadata("test.log").unwrap(); - assert!(meta.len() > 0); + if log { + let meta = std::fs::metadata("test.log").unwrap(); + assert!(meta.len() > 0); + } } #[test]