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