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