xref: /wasmtime-44.0.1/tests/all/module.rs (revision 72004aad)
1 use wasmtime::*;
2 
3 #[test]
4 fn checks_incompatible_target() -> Result<()> {
5     let mut target = target_lexicon::Triple::host();
6     target.operating_system = target_lexicon::OperatingSystem::Unknown;
7     match Module::new(
8         &Engine::new(Config::new().target(&target.to_string())?)?,
9         "(module)",
10     ) {
11         Ok(_) => unreachable!(),
12         Err(e) => assert!(
13             format!("{:?}", e).contains("configuration does not match the host"),
14             "bad error: {:?}",
15             e
16         ),
17     }
18 
19     Ok(())
20 }
21 
22 #[test]
23 fn caches_across_engines() {
24     let c = Config::new();
25 
26     let bytes = Module::new(&Engine::new(&c).unwrap(), "(module)")
27         .unwrap()
28         .serialize()
29         .unwrap();
30 
31     unsafe {
32         let res = Module::deserialize(&Engine::default(), &bytes);
33         assert!(res.is_ok());
34 
35         // differ in runtime settings
36         let res = Module::deserialize(
37             &Engine::new(Config::new().static_memory_maximum_size(0)).unwrap(),
38             &bytes,
39         );
40         assert!(res.is_err());
41 
42         // differ in wasm features enabled (which can affect
43         // runtime/compilation settings)
44         let res = Module::deserialize(
45             &Engine::new(Config::new().wasm_threads(false)).unwrap(),
46             &bytes,
47         );
48         assert!(res.is_err());
49     }
50 }
51 
52 #[test]
53 #[cfg_attr(miri, ignore)]
54 fn aot_compiles() -> Result<()> {
55     let engine = Engine::default();
56     let bytes = engine.precompile_module(
57         "(module (func (export \"f\") (param i32) (result i32) local.get 0))".as_bytes(),
58     )?;
59 
60     let module = unsafe { Module::deserialize(&engine, &bytes)? };
61 
62     let mut store = Store::new(&engine, ());
63     let instance = Instance::new(&mut store, &module, &[])?;
64 
65     let f = instance.get_typed_func::<i32, i32>(&mut store, "f")?;
66     assert_eq!(f.call(&mut store, 101)?, 101);
67 
68     Ok(())
69 }
70 
71 #[test]
72 #[cfg_attr(miri, ignore)]
73 fn serialize_deterministic() {
74     let engine = Engine::default();
75 
76     let assert_deterministic = |wasm: &str| {
77         let p1 = engine.precompile_module(wasm.as_bytes()).unwrap();
78         let p2 = engine.precompile_module(wasm.as_bytes()).unwrap();
79         if p1 != p2 {
80             panic!("precompile_module not deterministic for:\n{}", wasm);
81         }
82 
83         let module1 = Module::new(&engine, wasm).unwrap();
84         let a1 = module1.serialize().unwrap();
85         let a2 = module1.serialize().unwrap();
86         if a1 != a2 {
87             panic!("Module::serialize not deterministic for:\n{}", wasm);
88         }
89 
90         let module2 = Module::new(&engine, wasm).unwrap();
91         let b1 = module2.serialize().unwrap();
92         let b2 = module2.serialize().unwrap();
93         if b1 != b2 {
94             panic!("Module::serialize not deterministic for:\n{}", wasm);
95         }
96 
97         if a1 != b2 {
98             panic!("not matching across modules:\n{}", wasm);
99         }
100         if b1 != p2 {
101             panic!("not matching across engine/module:\n{}", wasm);
102         }
103     };
104 
105     assert_deterministic("(module)");
106     assert_deterministic("(module (func))");
107     assert_deterministic("(module (func nop))");
108     assert_deterministic("(module (func) (func (param i32)))");
109     assert_deterministic("(module (func (export \"f\")) (func (export \"y\")))");
110     assert_deterministic("(module (func $f) (func $g))");
111     assert_deterministic("(module (data \"\") (data \"\"))");
112     assert_deterministic("(module (elem func) (elem func))");
113 }
114 
115 // This test asserts that the optimization to transform separate data segments
116 // into an initialization image doesn't unnecessarily create a massive module by
117 // accident with a very large initialization image in it.
118 #[test]
119 fn serialize_not_overly_massive() -> Result<()> {
120     let mut config = Config::new();
121     config.memory_guaranteed_dense_image_size(1 << 20);
122     let engine = Engine::new(&config)?;
123 
124     let assert_smaller_than_1mb = |module: &str| -> Result<()> {
125         println!("{}", module);
126         let bytes = Module::new(&engine, module)?.serialize()?;
127         assert!(bytes.len() < (1 << 20));
128         Ok(())
129     };
130 
131     // Tons of space between data segments should use sparse initialization,
132     // along with various permutations of empty and nonempty segments.
133     assert_smaller_than_1mb(
134         r#"(module
135             (memory 20000)
136             (data (i32.const 0) "a")
137             (data (i32.const 0x200000) "b")
138         )"#,
139     )?;
140     assert_smaller_than_1mb(
141         r#"(module
142             (memory 20000)
143             (data (i32.const 0) "a")
144             (data (i32.const 0x200000) "")
145         )"#,
146     )?;
147     assert_smaller_than_1mb(
148         r#"(module
149             (memory 20000)
150             (data (i32.const 0) "")
151             (data (i32.const 0x200000) "b")
152         )"#,
153     )?;
154     assert_smaller_than_1mb(
155         r#"(module
156             (memory 20000)
157             (data (i32.const 0) "")
158             (data (i32.const 0x200000) "")
159         )"#,
160     )?;
161 
162     // lone data segment
163     assert_smaller_than_1mb(
164         r#"(module
165             (memory 20000)
166             (data (i32.const 0x200000) "b")
167         )"#,
168     )?;
169 
170     Ok(())
171 }
172 
173 // This test specifically disables SSE4.1 in Cranelift which force wasm
174 // instructions like `f32.ceil` to go through libcalls instead of using native
175 // instructions. Note that SIMD is also disabled here because SIMD otherwise
176 // requires SSE4.1 to be enabled.
177 //
178 // This test then also tests that loading modules through various means, e.g.
179 // through precompiled artifacts, all works.
180 #[test]
181 #[cfg_attr(any(not(target_arch = "x86_64"), miri), ignore)]
182 fn missing_sse_and_floats_still_works() -> Result<()> {
183     let mut config = Config::new();
184     config.wasm_simd(false).wasm_relaxed_simd(false);
185     unsafe {
186         config.cranelift_flag_set("has_sse41", "false");
187     }
188     let engine = Engine::new(&config)?;
189     let module = Module::new(
190         &engine,
191         r#"
192             (module
193                 (func (export "f32.ceil") (param f32) (result f32)
194                     local.get 0
195                     f32.ceil)
196             )
197         "#,
198     )?;
199     let bytes = module.serialize()?;
200     let module2 = unsafe { Module::deserialize(&engine, &bytes)? };
201     let tmpdir = tempfile::TempDir::new()?;
202     let path = tmpdir.path().join("module.cwasm");
203     std::fs::write(&path, &bytes)?;
204     let module3 = unsafe { Module::deserialize_file(&engine, &path)? };
205 
206     for module in [module, module2, module3] {
207         let mut store = Store::new(&engine, ());
208         let instance = Instance::new(&mut store, &module, &[])?;
209         let ceil = instance.get_typed_func::<f32, f32>(&mut store, "f32.ceil")?;
210 
211         for f in [1.0, 2.3, -1.3] {
212             assert_eq!(ceil.call(&mut store, f)?, f.ceil());
213         }
214     }
215 
216     Ok(())
217 }
218 
219 #[test]
220 #[cfg_attr(miri, ignore)]
221 fn large_add_chain_no_stack_overflow() -> Result<()> {
222     let mut config = Config::new();
223     config.cranelift_opt_level(OptLevel::None);
224     let engine = Engine::new(&config)?;
225     let mut wat = String::from(
226         "
227         (module
228             (func (result i64)
229                 (i64.const 1)
230         ",
231     );
232     for _ in 0..20_000 {
233         wat.push_str("(i64.add (i64.const 1))\n");
234     }
235 
236     wat.push_str(")\n)");
237     Module::new(&engine, &wat)?;
238 
239     Ok(())
240 }
241 
242 #[test]
243 fn compile_a_component() -> Result<()> {
244     let engine = Engine::default();
245     let err = Module::new(&engine, "(component)").unwrap_err();
246     let err = format!("{err:?}");
247     assert!(
248         err.contains("expected a WebAssembly module but was given a WebAssembly component"),
249         "bad error: {err}"
250     );
251     Ok(())
252 }
253