1 //! Generate Wasm modules that contain a single instruction.
2 
3 use super::ModuleConfig;
4 use arbitrary::Unstructured;
5 use wasm_encoder::{
6     CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, Module,
7     TypeSection, ValType,
8 };
9 
10 /// The name of the function generated by this module.
11 const FUNCTION_NAME: &'static str = "test";
12 
13 /// Configure a single instruction module.
14 ///
15 /// By explicitly defining the parameter and result types (versus generating the
16 /// module directly), we can more easily generate values of the right type.
17 #[derive(Clone)]
18 pub struct SingleInstModule<'a> {
19     instruction: Instruction<'a>,
20     parameters: &'a [ValType],
21     results: &'a [ValType],
22     feature: fn(&ModuleConfig) -> bool,
23 }
24 
25 impl<'a> SingleInstModule<'a> {
26     /// Choose a single-instruction module that matches `config`.
27     pub fn new(u: &mut Unstructured<'a>, config: &mut ModuleConfig) -> arbitrary::Result<&'a Self> {
28         // To avoid skipping modules unnecessarily during fuzzing, fix up the
29         // `ModuleConfig` to match the inherent limits of a single-instruction
30         // module.
31         config.config.min_funcs = 1;
32         config.config.max_funcs = 1;
33         config.config.min_tables = 0;
34         config.config.max_tables = 0;
35         config.config.min_memories = 0;
36         config.config.max_memories = 0;
37 
38         // Only select instructions that match the `ModuleConfig`.
39         let instructions = &INSTRUCTIONS
40             .iter()
41             .filter(|i| (i.feature)(config))
42             .collect::<Vec<_>>();
43         u.choose(&instructions[..]).copied()
44     }
45 
46     /// Encode a binary Wasm module with a single exported function, `test`,
47     /// that executes the single instruction.
48     pub fn to_bytes(&self) -> Vec<u8> {
49         let mut module = Module::new();
50 
51         // Encode the type section.
52         let mut types = TypeSection::new();
53         types.function(
54             self.parameters.iter().cloned(),
55             self.results.iter().cloned(),
56         );
57         module.section(&types);
58 
59         // Encode the function section.
60         let mut functions = FunctionSection::new();
61         let type_index = 0;
62         functions.function(type_index);
63         module.section(&functions);
64 
65         // Encode the export section.
66         let mut exports = ExportSection::new();
67         exports.export(FUNCTION_NAME, ExportKind::Func, 0);
68         module.section(&exports);
69 
70         // Encode the code section.
71         let mut codes = CodeSection::new();
72         let mut f = Function::new([]);
73         for (index, _) in self.parameters.iter().enumerate() {
74             f.instruction(&Instruction::LocalGet(index as u32));
75         }
76         f.instruction(&self.instruction);
77         f.instruction(&Instruction::End);
78         codes.function(&f);
79         module.section(&codes);
80 
81         // Extract the encoded Wasm bytes for this module.
82         module.finish()
83     }
84 }
85 
86 // MACROS
87 //
88 // These macros make it a bit easier to define the instructions available for
89 // generation. The idea is that, with these macros, we can define the list of
90 // instructions compactly and allow for easier changes to the Rust code (e.g.,
91 // `SingleInstModule`).
92 
93 macro_rules! valtype {
94     (i32) => {
95         ValType::I32
96     };
97     (i64) => {
98         ValType::I64
99     };
100     (f32) => {
101         ValType::F32
102     };
103     (f64) => {
104         ValType::F64
105     };
106 }
107 
108 macro_rules! inst {
109     ($inst:ident, ($($arguments_ty:tt),*) -> $result_ty:tt) => {
110         inst! { $inst, ($($arguments_ty),*) -> $result_ty, |_| true }
111     };
112     ($inst:ident, ($($arguments_ty:tt),*) -> $result_ty:tt, $feature:expr) => {
113         SingleInstModule {
114             instruction: Instruction::$inst,
115             parameters: &[$(valtype!($arguments_ty)),*],
116             results: &[valtype!($result_ty)],
117             feature: $feature,
118         }
119     };
120 }
121 
122 static INSTRUCTIONS: &[SingleInstModule] = &[
123     // Integer arithmetic.
124     // I32Const
125     // I64Const
126     // F32Const
127     // F64Const
128     inst!(I32Clz, (i32) -> i32),
129     inst!(I64Clz, (i64) -> i64),
130     inst!(I32Ctz, (i32) -> i32),
131     inst!(I64Ctz, (i64) -> i64),
132     inst!(I32Popcnt, (i32) -> i32),
133     inst!(I64Popcnt, (i64) -> i64),
134     inst!(I32Add, (i32, i32) -> i32),
135     inst!(I64Add, (i64, i64) -> i64),
136     inst!(I32Sub, (i32, i32) -> i32),
137     inst!(I64Sub, (i64, i64) -> i64),
138     inst!(I32Mul, (i32, i32) -> i32),
139     inst!(I64Mul, (i64, i64) -> i64),
140     inst!(I32DivS, (i32, i32) -> i32),
141     inst!(I64DivS, (i64, i64) -> i64),
142     inst!(I32DivU, (i32, i32) -> i32),
143     inst!(I64DivU, (i64, i64) -> i64),
144     inst!(I32RemS, (i32, i32) -> i32),
145     inst!(I64RemS, (i64, i64) -> i64),
146     inst!(I32RemU, (i32, i32) -> i32),
147     inst!(I64RemU, (i64, i64) -> i64),
148     // Integer bitwise.
149     inst!(I32And, (i32, i32) -> i32),
150     inst!(I64And, (i64, i64) -> i64),
151     inst!(I32Or, (i32, i32) -> i32),
152     inst!(I64Or, (i64, i64) -> i64),
153     inst!(I32Xor, (i32, i32) -> i32),
154     inst!(I64Xor, (i64, i64) -> i64),
155     inst!(I32Shl, (i32, i32) -> i32),
156     inst!(I64Shl, (i64, i64) -> i64),
157     inst!(I32ShrS, (i32, i32) -> i32),
158     inst!(I64ShrS, (i64, i64) -> i64),
159     inst!(I32ShrU, (i32, i32) -> i32),
160     inst!(I64ShrU, (i64, i64) -> i64),
161     inst!(I32Rotl, (i32, i32) -> i32),
162     inst!(I64Rotl, (i64, i64) -> i64),
163     inst!(I32Rotr, (i32, i32) -> i32),
164     inst!(I64Rotr, (i64, i64) -> i64),
165     // Integer comparison.
166     inst!(I32Eqz, (i32) -> i32),
167     inst!(I64Eqz, (i64) -> i32),
168     inst!(I32Eq, (i32, i32) -> i32),
169     inst!(I64Eq, (i64, i64) -> i32),
170     inst!(I32Ne, (i32, i32) -> i32),
171     inst!(I64Ne, (i64, i64) -> i32),
172     inst!(I32LtS, (i32, i32) -> i32),
173     inst!(I64LtS, (i64, i64) -> i32),
174     inst!(I32LtU, (i32, i32) -> i32),
175     inst!(I64LtU, (i64, i64) -> i32),
176     inst!(I32GtS, (i32, i32) -> i32),
177     inst!(I64GtS, (i64, i64) -> i32),
178     inst!(I32GtU, (i32, i32) -> i32),
179     inst!(I64GtU, (i64, i64) -> i32),
180     inst!(I32LeS, (i32, i32) -> i32),
181     inst!(I64LeS, (i64, i64) -> i32),
182     inst!(I32LeU, (i32, i32) -> i32),
183     inst!(I64LeU, (i64, i64) -> i32),
184     inst!(I32GeS, (i32, i32) -> i32),
185     inst!(I64GeS, (i64, i64) -> i32),
186     inst!(I32GeU, (i32, i32) -> i32),
187     inst!(I64GeU, (i64, i64) -> i32),
188     // Floating-point arithmetic.
189     inst!(F32Abs, (f32) -> f32),
190     inst!(F64Abs, (f64) -> f64),
191     inst!(F32Sqrt, (f32) -> f32),
192     inst!(F64Sqrt, (f64) -> f64),
193     inst!(F32Ceil, (f32) -> f32),
194     inst!(F64Ceil, (f64) -> f64),
195     inst!(F32Floor, (f32) -> f32),
196     inst!(F64Floor, (f64) -> f64),
197     inst!(F32Trunc, (f32) -> f32),
198     inst!(F64Trunc, (f64) -> f64),
199     inst!(F32Nearest, (f32) -> f32),
200     inst!(F64Nearest, (f64) -> f64),
201     inst!(F32Neg, (f32) -> f32),
202     inst!(F64Neg, (f64) -> f64),
203     inst!(F32Add, (f32, f32) -> f32),
204     inst!(F64Add, (f64, f64) -> f64),
205     inst!(F32Sub, (f32, f32) -> f32),
206     inst!(F64Sub, (f64, f64) -> f64),
207     inst!(F32Mul, (f32, f32) -> f32),
208     inst!(F64Mul, (f64, f64) -> f64),
209     inst!(F32Div, (f32, f32) -> f32),
210     inst!(F64Div, (f64, f64) -> f64),
211     inst!(F32Min, (f32, f32) -> f32),
212     inst!(F64Min, (f64, f64) -> f64),
213     inst!(F32Max, (f32, f32) -> f32),
214     inst!(F64Max, (f64, f64) -> f64),
215     inst!(F32Copysign, (f32, f32) -> f32),
216     inst!(F64Copysign, (f64, f64) -> f64),
217     // Floating-point comparison.
218     inst!(F32Eq, (f32, f32) -> i32),
219     inst!(F64Eq, (f64, f64) -> i32),
220     inst!(F32Ne, (f32, f32) -> i32),
221     inst!(F64Ne, (f64, f64) -> i32),
222     inst!(F32Lt, (f32, f32) -> i32),
223     inst!(F64Lt, (f64, f64) -> i32),
224     inst!(F32Gt, (f32, f32) -> i32),
225     inst!(F64Gt, (f64, f64) -> i32),
226     inst!(F32Le, (f32, f32) -> i32),
227     inst!(F64Le, (f64, f64) -> i32),
228     inst!(F32Ge, (f32, f32) -> i32),
229     inst!(F64Ge, (f64, f64) -> i32),
230     // Integer conversions ("to integer").
231     inst!(I32Extend8S, (i32) -> i32, |c| c.config.sign_extension_enabled),
232     inst!(I32Extend16S, (i32) -> i32, |c| c.config.sign_extension_enabled),
233     inst!(I64Extend8S, (i64) -> i64, |c| c.config.sign_extension_enabled),
234     inst!(I64Extend16S, (i64) -> i64, |c| c.config.sign_extension_enabled),
235     inst!(I64Extend32S, (i64) -> i64, |c| c.config.sign_extension_enabled),
236     inst!(I32WrapI64, (i64) -> i32),
237     inst!(I64ExtendI32S, (i32) -> i64),
238     inst!(I64ExtendI32U, (i32) -> i64),
239     inst!(I32TruncF32S, (f32) -> i32),
240     inst!(I32TruncF32U, (f32) -> i32),
241     inst!(I32TruncF64S, (f64) -> i32),
242     inst!(I32TruncF64U, (f64) -> i32),
243     inst!(I64TruncF32S, (f32) -> i64),
244     inst!(I64TruncF32U, (f32) -> i64),
245     inst!(I64TruncF64S, (f64) -> i64),
246     inst!(I64TruncF64U, (f64) -> i64),
247     inst!(I32TruncSatF32S, (f32) -> i32, |c| c.config.saturating_float_to_int_enabled),
248     inst!(I32TruncSatF32U, (f32) -> i32, |c| c.config.saturating_float_to_int_enabled),
249     inst!(I32TruncSatF64S, (f64) -> i32, |c| c.config.saturating_float_to_int_enabled),
250     inst!(I32TruncSatF64U, (f64) -> i32, |c| c.config.saturating_float_to_int_enabled),
251     inst!(I64TruncSatF32S, (f32) -> i64, |c| c.config.saturating_float_to_int_enabled),
252     inst!(I64TruncSatF32U, (f32) -> i64, |c| c.config.saturating_float_to_int_enabled),
253     inst!(I64TruncSatF64S, (f64) -> i64, |c| c.config.saturating_float_to_int_enabled),
254     inst!(I64TruncSatF64U, (f64) -> i64, |c| c.config.saturating_float_to_int_enabled),
255     inst!(I32ReinterpretF32, (f32) -> i32),
256     inst!(I64ReinterpretF64, (f64) -> i64),
257     // Floating-point conversions ("to float").
258     inst!(F32DemoteF64, (f64) -> f32),
259     inst!(F64PromoteF32, (f32) -> f64),
260     inst!(F32ConvertI32S, (i32) -> f32),
261     inst!(F32ConvertI32U, (i32) -> f32),
262     inst!(F32ConvertI64S, (i64) -> f32),
263     inst!(F32ConvertI64U, (i64) -> f32),
264     inst!(F64ConvertI32S, (i32) -> f64),
265     inst!(F64ConvertI32U, (i32) -> f64),
266     inst!(F64ConvertI64S, (i64) -> f64),
267     inst!(F64ConvertI64U, (i64) -> f64),
268     inst!(F32ReinterpretI32, (i32) -> f32),
269     inst!(F64ReinterpretI64, (i64) -> f64),
270 ];
271 
272 #[cfg(test)]
273 mod test {
274     use super::*;
275 
276     #[test]
277     fn sanity() {
278         let sut = SingleInstModule {
279             instruction: Instruction::I32Add,
280             parameters: &[ValType::I32, ValType::I32],
281             results: &[ValType::I32],
282             feature: |_| true,
283         };
284         let wasm = sut.to_bytes();
285         let wat = wasmprinter::print_bytes(wasm).unwrap();
286         assert_eq!(
287             wat,
288             r#"(module
289   (type (;0;) (func (param i32 i32) (result i32)))
290   (func (;0;) (type 0) (param i32 i32) (result i32)
291     local.get 0
292     local.get 1
293     i32.add
294   )
295   (export "test" (func 0))
296 )"#
297         )
298     }
299 
300     #[test]
301     fn instructions_encode_to_valid_modules() {
302         for inst in INSTRUCTIONS {
303             assert!(wat::parse_bytes(&inst.to_bytes()).is_ok());
304         }
305     }
306 }
307