1 use anyhow::bail; 2 use std::fs::{self, OpenOptions}; 3 use wasmtime::*; 4 5 fn serialize(engine: &Engine, wat: &str) -> Result<Vec<u8>> { 6 let module = Module::new(&engine, wat)?; 7 Ok(module.serialize()?) 8 } 9 10 unsafe fn deserialize_and_instantiate(store: &mut Store<()>, buffer: &[u8]) -> Result<Instance> { 11 let module = Module::deserialize(store.engine(), buffer)?; 12 Ok(Instance::new(store, &module, &[])?) 13 } 14 15 #[test] 16 fn test_version_mismatch() -> Result<()> { 17 let engine = Engine::default(); 18 let buffer = serialize(&engine, "(module)")?; 19 20 let mut config = Config::new(); 21 config 22 .module_version(ModuleVersionStrategy::Custom("custom!".to_owned())) 23 .unwrap(); 24 let custom_version_engine = Engine::new(&config).unwrap(); 25 match unsafe { Module::deserialize(&custom_version_engine, &buffer) } { 26 Ok(_) => bail!("expected deserialization to fail"), 27 Err(e) => assert!(e 28 .to_string() 29 .starts_with("Module was compiled with incompatible version")), 30 } 31 32 let mut config = Config::new(); 33 config.module_version(ModuleVersionStrategy::None).unwrap(); 34 let none_version_engine = Engine::new(&config).unwrap(); 35 unsafe { Module::deserialize(&none_version_engine, &buffer) } 36 .expect("accepts the wasmtime versioned module"); 37 38 let buffer = serialize(&custom_version_engine, "(module)")?; 39 unsafe { Module::deserialize(&none_version_engine, &buffer) } 40 .expect("accepts the custom versioned module"); 41 42 Ok(()) 43 } 44 45 #[test] 46 #[cfg_attr(miri, ignore)] 47 fn test_module_serialize_simple() -> Result<()> { 48 let buffer = serialize( 49 &Engine::default(), 50 "(module (func (export \"run\") (result i32) i32.const 42))", 51 )?; 52 53 let mut store = Store::default(); 54 let instance = unsafe { deserialize_and_instantiate(&mut store, &buffer)? }; 55 let run = instance.get_typed_func::<(), i32>(&mut store, "run")?; 56 let result = run.call(&mut store, ())?; 57 58 assert_eq!(42, result); 59 Ok(()) 60 } 61 62 #[test] 63 #[cfg_attr(miri, ignore)] 64 fn test_module_serialize_fail() -> Result<()> { 65 let buffer = serialize( 66 &Engine::default(), 67 "(module (func (export \"run\") (result i32) i32.const 42))", 68 )?; 69 70 let mut config = Config::new(); 71 config.memory_reservation(0); 72 let mut store = Store::new(&Engine::new(&config)?, ()); 73 match unsafe { deserialize_and_instantiate(&mut store, &buffer) } { 74 Ok(_) => bail!("expected failure at deserialization"), 75 Err(_) => (), 76 } 77 Ok(()) 78 } 79 80 #[test] 81 #[cfg_attr(miri, ignore)] 82 fn test_deserialize_from_file() -> Result<()> { 83 serialize_and_call("(module (func (export \"run\") (result i32) i32.const 42))")?; 84 serialize_and_call( 85 "(module 86 (func (export \"run\") (result i32) 87 call $answer) 88 89 (func $answer (result i32) 90 i32.const 42)) 91 ", 92 )?; 93 return Ok(()); 94 95 fn serialize_and_call(wat: &str) -> Result<()> { 96 let mut store = Store::<()>::default(); 97 let td = tempfile::TempDir::new()?; 98 let buffer = serialize(store.engine(), wat)?; 99 100 let path = td.path().join("module.bin"); 101 fs::write(&path, &buffer)?; 102 let module = unsafe { Module::deserialize_file(store.engine(), &path)? }; 103 let instance = Instance::new(&mut store, &module, &[])?; 104 let func = instance.get_typed_func::<(), i32>(&mut store, "run")?; 105 assert_eq!(func.call(&mut store, ())?, 42); 106 107 // Try an already opened file as well. 108 let mut open_options = OpenOptions::new(); 109 open_options.read(true); 110 #[cfg(target_os = "windows")] 111 { 112 use std::os::windows::prelude::*; 113 use windows_sys::Win32::Storage::FileSystem::*; 114 open_options.access_mode(FILE_GENERIC_READ | FILE_GENERIC_EXECUTE); 115 } 116 117 let file = open_options.open(&path)?; 118 let module = unsafe { Module::deserialize_open_file(store.engine(), file)? }; 119 let instance = Instance::new(&mut store, &module, &[])?; 120 let func = instance.get_typed_func::<(), i32>(&mut store, "run")?; 121 assert_eq!(func.call(&mut store, ())?, 42); 122 123 Ok(()) 124 } 125 } 126 127 #[test] 128 #[cfg_attr(miri, ignore)] 129 fn deserialize_from_serialized() -> Result<()> { 130 let engine = Engine::default(); 131 let buffer1 = serialize( 132 &engine, 133 "(module (func (export \"run\") (result i32) i32.const 42))", 134 )?; 135 let buffer2 = unsafe { Module::deserialize(&engine, &buffer1)?.serialize()? }; 136 assert!(buffer1 == buffer2); 137 Ok(()) 138 } 139 140 #[test] 141 #[cfg_attr(miri, ignore)] 142 fn detect_precompiled() -> Result<()> { 143 let engine = Engine::default(); 144 let buffer = serialize( 145 &engine, 146 "(module (func (export \"run\") (result i32) i32.const 42))", 147 )?; 148 assert_eq!(Engine::detect_precompiled(&[]), None); 149 assert_eq!(Engine::detect_precompiled(&buffer[..5]), None); 150 assert_eq!( 151 Engine::detect_precompiled(&buffer), 152 Some(Precompiled::Module) 153 ); 154 Ok(()) 155 } 156