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