1 use crate::info::{ 2 types_interner::{EntityType, InstanceType, Type, TypeId}, 3 Module, ModuleContext, 4 }; 5 use crate::stack_ext::StackExt; 6 use anyhow::{Context, Result}; 7 use std::convert::TryFrom; 8 use wasm_encoder::SectionId; 9 use wasmparser::{SectionReader, SectionWithLimitedItems}; 10 11 struct StackEntry { 12 parser: wasmparser::Parser, 13 module: Module, 14 } 15 16 /// Parse the given Wasm bytes into a `ModuleInfo` tree. 17 pub(crate) fn parse<'a>(full_wasm: &'a [u8]) -> anyhow::Result<ModuleContext<'a>> { 18 log::debug!("Parsing the input Wasm"); 19 20 let mut cx = ModuleContext::new(); 21 22 // The wasm we are currently parsing. This is advanced as the parser 23 // consumes input. 24 let mut wasm = full_wasm; 25 26 let mut stack = vec![StackEntry { 27 parser: wasmparser::Parser::new(0), 28 module: cx.root(), 29 }]; 30 31 loop { 32 let (payload, consumed) = match stack 33 .top_mut() 34 .parser 35 .parse(wasm, true) 36 .context("failed to parse Wasm")? 37 { 38 wasmparser::Chunk::NeedMoreData(_) => unreachable!(), 39 wasmparser::Chunk::Parsed { payload, consumed } => (payload, consumed), 40 }; 41 wasm = &wasm[consumed..]; 42 43 use wasmparser::Payload::*; 44 match payload { 45 Version { .. } => {} 46 TypeSection(types) => type_section(&mut cx, &mut stack, full_wasm, types)?, 47 ImportSection(imports) => import_section(&mut cx, &mut stack, full_wasm, imports)?, 48 AliasSection(aliases) => alias_section(&mut cx, &mut stack, full_wasm, aliases)?, 49 InstanceSection(instances) => { 50 instance_section(&mut cx, &mut stack, full_wasm, instances)? 51 } 52 ModuleSectionStart { 53 range, 54 size: _, 55 count: _, 56 } => { 57 stack.top_mut().module.add_raw_section( 58 &mut cx, 59 SectionId::Module, 60 range, 61 full_wasm, 62 ); 63 } 64 ModuleSectionEntry { parser, range: _ } => { 65 stack.push(StackEntry { 66 parser, 67 module: Module::new_defined(&mut cx), 68 }); 69 } 70 FunctionSection(funcs) => function_section(&mut cx, &mut stack, full_wasm, funcs)?, 71 TableSection(tables) => table_section(&mut cx, &mut stack, full_wasm, tables)?, 72 MemorySection(mems) => memory_section(&mut cx, &mut stack, full_wasm, mems)?, 73 GlobalSection(globals) => global_section(&mut cx, &mut stack, full_wasm, globals)?, 74 ExportSection(exports) => export_section(&mut cx, &mut stack, full_wasm, exports)?, 75 StartSection { func: _, range } => { 76 stack 77 .top_mut() 78 .module 79 .add_raw_section(&mut cx, SectionId::Start, range, full_wasm) 80 } 81 ElementSection(elems) => stack.top_mut().module.add_raw_section( 82 &mut cx, 83 SectionId::Element, 84 elems.range(), 85 full_wasm, 86 ), 87 DataCountSection { range, .. } => stack.top_mut().module.add_raw_section( 88 &mut cx, 89 SectionId::DataCount, 90 range, 91 full_wasm, 92 ), 93 DataSection(data) => stack.top_mut().module.add_raw_section( 94 &mut cx, 95 SectionId::Data, 96 data.range(), 97 full_wasm, 98 ), 99 CustomSection { range, .. } => { 100 stack 101 .top_mut() 102 .module 103 .add_raw_section(&mut cx, SectionId::Custom, range, full_wasm) 104 } 105 CodeSectionStart { 106 range, 107 count: _, 108 size, 109 } => { 110 wasm = &wasm[usize::try_from(size).unwrap()..]; 111 let entry = stack.top_mut(); 112 entry.parser.skip_section(); 113 entry 114 .module 115 .add_raw_section(&mut cx, SectionId::Code, range, full_wasm) 116 } 117 CodeSectionEntry(_) => unreachable!(), 118 UnknownSection { .. } => anyhow::bail!("unknown section"), 119 EventSection(_) => anyhow::bail!("exceptions are not supported yet"), 120 End => { 121 let entry = stack.pop().unwrap(); 122 123 // If we finished parsing the root Wasm module, then we're done. 124 if entry.module.is_root() { 125 assert!(stack.is_empty()); 126 return Ok(cx); 127 } 128 129 // Otherwise, we need to add this module to its parent's module 130 // section. 131 let parent = stack.top_mut(); 132 parent.module.push_child_module(&mut cx, entry.module); 133 } 134 } 135 } 136 } 137 138 fn type_section<'a>( 139 cx: &mut ModuleContext<'a>, 140 stack: &mut Vec<StackEntry>, 141 full_wasm: &'a [u8], 142 mut types: wasmparser::TypeSectionReader<'a>, 143 ) -> anyhow::Result<()> { 144 let module = stack.top().module; 145 module.add_raw_section(cx, SectionId::Type, types.range(), full_wasm); 146 147 // Parse out types, as we will need them later when processing 148 // instance imports. 149 let count = usize::try_from(types.get_count()).unwrap(); 150 for _ in 0..count { 151 let ty = types.read()?; 152 match ty { 153 wasmparser::TypeDef::Func(_) | wasmparser::TypeDef::Instance(_) => { 154 module.push_type(cx, ty); 155 } 156 157 // We need to disallow module imports, even within nested modules 158 // that only ever have other nested modules supplied as 159 // arguments. Two different modules could be supplied for two 160 // different instantiations of the module-importing module, but then 161 // after we export all modules' globals in our instrumentation 162 // phase, those two different module arguments could become 163 // type-incompatible with each other: 164 // 165 // ``` 166 // (module 167 // 168 // ;; Module A exports and `f` function. Internally it has 169 // ;; one global. 170 // (module $A 171 // (global $g ...) 172 // (func (export "f") ...)) 173 // 174 // ;; Module B has an identical interface as A. Internally 175 // ;; it has two globals. 176 // (module $B 177 // (global $g ...) 178 // (global $h ...) 179 // (func (export "f") ...)) 180 // 181 // ;; Module C imports any module that exports an `f` 182 // ;; function. It instantiates this imported module. 183 // (module $C 184 // (import "env" "module" 185 // (module (export "f" (func))) 186 // (instance 0))) 187 // 188 // ;; C is instantiated with both A and B. 189 // (instance $C (import "env" "module" $A)) 190 // (instance $C (import "env" "module" $B)) 191 // ) 192 // ``` 193 // 194 // After this instrumentation pass, we need to make module C 195 // transitively export all of the globals from its inner 196 // instances. Which means that the module type used in the module 197 // import needs to specify how many modules are in the imported 198 // module, but in our two instantiations, we have two different 199 // numbers of globals defined in each module! The only way to 200 // resolve this would be to duplicate and specialize module C for 201 // each instantiation, which we don't want to do for complexity and 202 // code size reasons. 203 // 204 // Since module types are only used with importing and exporting 205 // modules, which we don't intend to support as described above, we 206 // can disallow module types to reject all of them in one fell 207 // swoop. 208 wasmparser::TypeDef::Module(_) => Err(anyhow::anyhow!( 209 "wizer does not support importing or exporting modules" 210 ) 211 .context("module types are not supported"))?, 212 } 213 } 214 215 Ok(()) 216 } 217 218 fn import_section<'a>( 219 cx: &mut ModuleContext<'a>, 220 stack: &mut Vec<StackEntry>, 221 full_wasm: &'a [u8], 222 mut imports: wasmparser::ImportSectionReader<'a>, 223 ) -> anyhow::Result<()> { 224 let module = stack.top().module; 225 stack 226 .top_mut() 227 .module 228 .add_raw_section(cx, SectionId::Import, imports.range(), full_wasm); 229 230 let mut instance_import_count = 0; 231 232 // Two-level imports implicitly create an instance import. That is, this 233 // 234 // (import "env" "f" (func)) 235 // (import "env" "g" (func)) 236 // 237 // is implicitly translated into roughly 238 // 239 // (import "env" (instance (export "f" (func)) 240 // (export "g" (func)))) 241 // (alias 0 "f") 242 // (alias 0 "g") 243 // 244 // However not that this is _not_ a WAT-level desugaring where we only have 245 // to deal with the expanded form! We have to perform this translation 246 // ourselves as we parse the imports. 247 // 248 // This variable keeps track of the implicit instance import that we are 249 // currently building. Whenever we see a consecutive run of two-level 250 // imports for the same module, we coalesce them into an implicit instance 251 // import. 252 let mut implicit_instance_import: Option<(&str, InstanceType)> = None; 253 254 // Check that we can properly handle all imports. 255 let count = imports.get_count(); 256 for _ in 0..count { 257 let imp = imports.read()?; 258 259 if imp.module.starts_with("__wizer_") 260 || imp.field.map_or(false, |f| f.starts_with("__wizer_")) 261 { 262 anyhow::bail!( 263 "input Wasm module already imports entities named with the `__wizer_*` prefix" 264 ); 265 } 266 267 match (implicit_instance_import.as_mut(), imp.field) { 268 (Some((implicit_module, instance_ty)), Some(field)) 269 if *implicit_module == imp.module => 270 { 271 let ty = module.entity_type(cx, imp.ty); 272 let old = instance_ty.exports.insert(field.into(), ty); 273 debug_assert!(old.is_none(), "checked by validation"); 274 } 275 _ => { 276 if let Some((_, instance_ty)) = implicit_instance_import.take() { 277 module.push_implicit_instance(cx, instance_ty); 278 instance_import_count += 1; 279 } 280 if let Some(field) = imp.field { 281 let field_ty = module.entity_type(cx, imp.ty); 282 let instance_ty = InstanceType { 283 exports: Some((field.into(), field_ty)).into_iter().collect(), 284 }; 285 implicit_instance_import = Some((imp.module, instance_ty)); 286 } 287 } 288 } 289 290 check_import_type( 291 cx, 292 stack.top().module.types(cx), 293 stack.top().module.is_root(), 294 &module.entity_type(cx, imp.ty), 295 )?; 296 if let wasmparser::ImportSectionEntryType::Instance(_) = imp.ty { 297 instance_import_count += 1; 298 } 299 module.push_import(cx, imp); 300 } 301 302 if let Some((_, instance_ty)) = implicit_instance_import.take() { 303 module.push_implicit_instance(cx, instance_ty); 304 instance_import_count += 1; 305 } 306 307 module.push_instance_import_count(cx, instance_import_count); 308 Ok(()) 309 } 310 311 fn check_import_type( 312 cx: &ModuleContext, 313 types: &[TypeId], 314 is_root: bool, 315 ty: &EntityType, 316 ) -> Result<()> { 317 match ty { 318 EntityType::Function(_) => Ok(()), 319 EntityType::Instance(inst_ty) => { 320 // We allow importing instances that only export things that are 321 // acceptable imports. This is equivalent to a two-layer import. 322 match cx.types().get(*inst_ty) { 323 Type::Instance(inst_ty) => { 324 for ty in inst_ty.exports.values() { 325 check_import_type(cx, types, is_root, ty)?; 326 } 327 Ok(()) 328 } 329 _ => unreachable!(), 330 } 331 } 332 EntityType::Memory(mem_ty) => match mem_ty { 333 wasmparser::MemoryType::M32 { limits: _, shared } => { 334 anyhow::ensure!(!shared, "shared memories are not supported by Wizer yet"); 335 anyhow::ensure!( 336 !is_root, 337 "memory imports are not allowed in the root Wasm module" 338 ); 339 Ok(()) 340 } 341 wasmparser::MemoryType::M64 { .. } => { 342 anyhow::bail!("the memory64 proposal is not supported by Wizer yet") 343 } 344 }, 345 EntityType::Table(_) | EntityType::Global(_) => { 346 anyhow::ensure!( 347 !is_root, 348 "table and global imports are not allowed in the root Wasm module" 349 ); 350 Ok(()) 351 } 352 EntityType::Module(_) => { 353 unreachable!(); 354 } 355 } 356 } 357 358 fn alias_section<'a>( 359 cx: &mut ModuleContext<'a>, 360 stack: &mut Vec<StackEntry>, 361 full_wasm: &'a [u8], 362 mut aliases: wasmparser::AliasSectionReader<'a>, 363 ) -> anyhow::Result<()> { 364 let module = stack.top().module; 365 module.add_raw_section(cx, SectionId::Alias, aliases.range(), full_wasm); 366 367 // Clone any aliases over into this module's index spaces. 368 for _ in 0..aliases.get_count() { 369 let alias = aliases.read()?; 370 match &alias { 371 wasmparser::Alias::OuterType { 372 relative_depth, 373 index, 374 } => { 375 let relative_depth = usize::try_from(*relative_depth).unwrap(); 376 // NB: `- 2` rather than `- 1` because 377 // `relative_depth=0` means this module's immediate 378 // parent, not this module itself. 379 let ty = stack[stack.len() - 2 - relative_depth] 380 .module 381 .type_id_at(cx, *index); 382 module.push_aliased_type(cx, ty); 383 } 384 wasmparser::Alias::OuterModule { 385 relative_depth, 386 index, 387 } => { 388 let relative_depth = usize::try_from(*relative_depth).unwrap(); 389 // Ditto regarding `- 2`. 390 let alias_of = stack[stack.len() - 2 - relative_depth] 391 .module 392 .child_module_at(cx, *index); 393 let aliased = Module::new_aliased(cx, alias_of); 394 module.push_child_module(cx, aliased); 395 } 396 wasmparser::Alias::InstanceExport { 397 instance, 398 kind, 399 export, 400 } => match kind { 401 wasmparser::ExternalKind::Module => { 402 anyhow::bail!("exported modules are not supported yet") 403 } 404 wasmparser::ExternalKind::Instance => { 405 let inst_ty = match module.instance_export(cx, *instance, export) { 406 Some(EntityType::Instance(i)) => *i, 407 _ => unreachable!(), 408 }; 409 module.push_aliased_instance(cx, inst_ty); 410 } 411 wasmparser::ExternalKind::Function => { 412 let func_ty = match module.instance_export(cx, *instance, export) { 413 Some(EntityType::Function(ty)) => *ty, 414 _ => unreachable!(), 415 }; 416 module.push_function(cx, func_ty); 417 } 418 wasmparser::ExternalKind::Table => { 419 let table_ty = match module.instance_export(cx, *instance, export) { 420 Some(EntityType::Table(ty)) => *ty, 421 _ => unreachable!(), 422 }; 423 module.push_table(cx, table_ty); 424 } 425 wasmparser::ExternalKind::Memory => { 426 let ty = match module.instance_export(cx, *instance, export) { 427 Some(EntityType::Memory(ty)) => *ty, 428 _ => unreachable!(), 429 }; 430 module.push_imported_memory(cx, ty); 431 } 432 wasmparser::ExternalKind::Global => { 433 let ty = match module.instance_export(cx, *instance, export) { 434 Some(EntityType::Global(ty)) => *ty, 435 _ => unreachable!(), 436 }; 437 module.push_imported_global(cx, ty); 438 } 439 wasmparser::ExternalKind::Event => { 440 unreachable!("validation should reject the exceptions proposal") 441 } 442 wasmparser::ExternalKind::Type => unreachable!("can't export types"), 443 }, 444 } 445 module.push_alias(cx, alias); 446 } 447 448 Ok(()) 449 } 450 451 fn instance_section<'a>( 452 cx: &mut ModuleContext<'a>, 453 stack: &mut Vec<StackEntry>, 454 full_wasm: &'a [u8], 455 mut instances: wasmparser::InstanceSectionReader<'a>, 456 ) -> anyhow::Result<()> { 457 let module = stack.top().module; 458 module.add_raw_section(cx, SectionId::Instance, instances.range(), full_wasm); 459 460 // Record the instantiations made in this module, and which modules were 461 // instantiated. 462 for _ in 0..instances.get_count() { 463 let inst = instances.read()?; 464 let module_index = inst.module(); 465 let child_module = module.child_module_at(cx, module_index); 466 let inst_ty = child_module.define_instance_type(cx); 467 468 let mut instance_args_reader = inst.args()?; 469 let instance_args_count = usize::try_from(instance_args_reader.get_count()).unwrap(); 470 let mut instance_args = Vec::with_capacity(instance_args_count); 471 for _ in 0..instance_args_count { 472 instance_args.push(instance_args_reader.read()?); 473 } 474 475 module.push_defined_instance(cx, inst_ty, child_module, instance_args); 476 } 477 478 Ok(()) 479 } 480 481 fn function_section<'a>( 482 cx: &mut ModuleContext<'a>, 483 stack: &mut Vec<StackEntry>, 484 full_wasm: &'a [u8], 485 mut funcs: wasmparser::FunctionSectionReader<'a>, 486 ) -> anyhow::Result<()> { 487 let module = stack.top().module; 488 module.add_raw_section(cx, SectionId::Function, funcs.range(), full_wasm); 489 490 let count = usize::try_from(funcs.get_count()).unwrap(); 491 for _ in 0..count { 492 let ty_idx = funcs.read()?; 493 let ty = module.type_id_at(cx, ty_idx); 494 module.push_function(cx, ty); 495 } 496 Ok(()) 497 } 498 499 fn table_section<'a>( 500 cx: &mut ModuleContext<'a>, 501 stack: &mut Vec<StackEntry>, 502 full_wasm: &'a [u8], 503 mut tables: wasmparser::TableSectionReader<'a>, 504 ) -> anyhow::Result<()> { 505 let module = stack.top().module; 506 module.add_raw_section(cx, SectionId::Table, tables.range(), full_wasm); 507 508 let count = usize::try_from(tables.get_count()).unwrap(); 509 for _ in 0..count { 510 module.push_table(cx, tables.read()?); 511 } 512 Ok(()) 513 } 514 515 fn memory_section<'a>( 516 cx: &mut ModuleContext<'a>, 517 stack: &mut Vec<StackEntry>, 518 full_wasm: &'a [u8], 519 mut mems: wasmparser::MemorySectionReader<'a>, 520 ) -> anyhow::Result<()> { 521 let module = stack.top().module; 522 module.add_raw_section(cx, SectionId::Memory, mems.range(), full_wasm); 523 524 let count = usize::try_from(mems.get_count()).unwrap(); 525 for _ in 0..count { 526 let m = mems.read()?; 527 module.push_defined_memory(cx, m); 528 } 529 Ok(()) 530 } 531 532 fn global_section<'a>( 533 cx: &mut ModuleContext<'a>, 534 stack: &mut Vec<StackEntry>, 535 full_wasm: &'a [u8], 536 mut globals: wasmparser::GlobalSectionReader<'a>, 537 ) -> anyhow::Result<()> { 538 let module = stack.top().module; 539 module.add_raw_section(cx, SectionId::Global, globals.range(), full_wasm); 540 541 let count = usize::try_from(globals.get_count()).unwrap(); 542 for _ in 0..count { 543 let g = globals.read()?; 544 module.push_defined_global(cx, g.ty); 545 } 546 Ok(()) 547 } 548 549 fn export_section<'a>( 550 cx: &mut ModuleContext<'a>, 551 stack: &mut Vec<StackEntry>, 552 full_wasm: &'a [u8], 553 mut exports: wasmparser::ExportSectionReader<'a>, 554 ) -> anyhow::Result<()> { 555 let module = stack.top().module; 556 module.add_raw_section(cx, SectionId::Export, exports.range(), full_wasm); 557 558 for _ in 0..exports.get_count() { 559 let export = exports.read()?; 560 561 if export.field.starts_with("__wizer_") { 562 anyhow::bail!( 563 "input Wasm module already exports entities named with the `__wizer_*` prefix" 564 ); 565 } 566 567 match export.kind { 568 wasmparser::ExternalKind::Module => { 569 anyhow::bail!("Wizer does not support importing and exporting modules") 570 } 571 wasmparser::ExternalKind::Type | wasmparser::ExternalKind::Event => { 572 unreachable!("checked in validation") 573 } 574 wasmparser::ExternalKind::Function 575 | wasmparser::ExternalKind::Table 576 | wasmparser::ExternalKind::Memory 577 | wasmparser::ExternalKind::Global 578 | wasmparser::ExternalKind::Instance => { 579 module.push_export(cx, export); 580 } 581 } 582 } 583 Ok(()) 584 } 585