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