1 use std::fs::{self, OpenOptions};
2 use wasmtime::bail;
3 use wasmtime::*;
4 
serialize(engine: &Engine, wat: &str) -> Result<Vec<u8>>5 fn serialize(engine: &Engine, wat: &str) -> Result<Vec<u8>> {
6     let module = Module::new(&engine, wat)?;
7     Ok(module.serialize()?)
8 }
9 
deserialize_and_instantiate(store: &mut Store<()>, buffer: &[u8]) -> Result<Instance>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]
test_version_mismatch() -> Result<()>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)]
test_module_serialize_simple() -> Result<()>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)]
test_module_serialize_fail() -> Result<()>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)]
test_deserialize_from_file() -> Result<()>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)]
deserialize_from_serialized() -> Result<()>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)]
detect_precompiled() -> Result<()>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