1// Copyright 2015 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/wasm/module-decoder.h" 6 7#include "src/base/functional.h" 8#include "src/base/platform/platform.h" 9#include "src/base/platform/wrappers.h" 10#include "src/flags/flags.h" 11#include "src/init/v8.h" 12#include "src/logging/counters.h" 13#include "src/logging/metrics.h" 14#include "src/objects/objects-inl.h" 15#include "src/utils/ostreams.h" 16#include "src/wasm/canonical-types.h" 17#include "src/wasm/decoder.h" 18#include "src/wasm/function-body-decoder-impl.h" 19#include "src/wasm/init-expr-interface.h" 20#include "src/wasm/struct-types.h" 21#include "src/wasm/wasm-constants.h" 22#include "src/wasm/wasm-engine.h" 23#include "src/wasm/wasm-limits.h" 24#include "src/wasm/wasm-opcodes-inl.h" 25 26namespace v8 { 27namespace internal { 28namespace wasm { 29 30#define TRACE(...) \ 31 do { \ 32 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 33 } while (false) 34 35namespace { 36 37constexpr char kNameString[] = "name"; 38constexpr char kSourceMappingURLString[] = "sourceMappingURL"; 39constexpr char kCompilationHintsString[] = "compilationHints"; 40constexpr char kBranchHintsString[] = "metadata.code.branch_hint"; 41constexpr char kDebugInfoString[] = ".debug_info"; 42constexpr char kExternalDebugInfoString[] = "external_debug_info"; 43 44const char* ExternalKindName(ImportExportKindCode kind) { 45 switch (kind) { 46 case kExternalFunction: 47 return "function"; 48 case kExternalTable: 49 return "table"; 50 case kExternalMemory: 51 return "memory"; 52 case kExternalGlobal: 53 return "global"; 54 case kExternalTag: 55 return "tag"; 56 } 57 return "unknown"; 58} 59 60} // namespace 61 62const char* SectionName(SectionCode code) { 63 switch (code) { 64 case kUnknownSectionCode: 65 return "Unknown"; 66 case kTypeSectionCode: 67 return "Type"; 68 case kImportSectionCode: 69 return "Import"; 70 case kFunctionSectionCode: 71 return "Function"; 72 case kTableSectionCode: 73 return "Table"; 74 case kMemorySectionCode: 75 return "Memory"; 76 case kGlobalSectionCode: 77 return "Global"; 78 case kExportSectionCode: 79 return "Export"; 80 case kStartSectionCode: 81 return "Start"; 82 case kCodeSectionCode: 83 return "Code"; 84 case kElementSectionCode: 85 return "Element"; 86 case kDataSectionCode: 87 return "Data"; 88 case kTagSectionCode: 89 return "Tag"; 90 case kDataCountSectionCode: 91 return "DataCount"; 92 case kNameSectionCode: 93 return kNameString; 94 case kSourceMappingURLSectionCode: 95 return kSourceMappingURLString; 96 case kDebugInfoSectionCode: 97 return kDebugInfoString; 98 case kExternalDebugInfoSectionCode: 99 return kExternalDebugInfoString; 100 case kCompilationHintsSectionCode: 101 return kCompilationHintsString; 102 case kBranchHintsSectionCode: 103 return kBranchHintsString; 104 default: 105 return "<unknown>"; 106 } 107} 108 109namespace { 110 111bool validate_utf8(Decoder* decoder, WireBytesRef string) { 112 return unibrow::Utf8::ValidateEncoding( 113 decoder->start() + decoder->GetBufferRelativeOffset(string.offset()), 114 string.length()); 115} 116 117// Reads a length-prefixed string, checking that it is within bounds. Returns 118// the offset of the string, and the length as an out parameter. 119WireBytesRef consume_string(Decoder* decoder, bool validate_utf8, 120 const char* name) { 121 uint32_t length = decoder->consume_u32v("string length"); 122 uint32_t offset = decoder->pc_offset(); 123 const byte* string_start = decoder->pc(); 124 // Consume bytes before validation to guarantee that the string is not oob. 125 if (length > 0) { 126 decoder->consume_bytes(length, name); 127 if (decoder->ok() && validate_utf8 && 128 !unibrow::Utf8::ValidateEncoding(string_start, length)) { 129 decoder->errorf(string_start, "%s: no valid UTF-8 string", name); 130 } 131 } 132 return {offset, decoder->failed() ? 0 : length}; 133} 134 135namespace { 136SectionCode IdentifyUnknownSectionInternal(Decoder* decoder) { 137 WireBytesRef string = consume_string(decoder, true, "section name"); 138 if (decoder->failed()) { 139 return kUnknownSectionCode; 140 } 141 const byte* section_name_start = 142 decoder->start() + decoder->GetBufferRelativeOffset(string.offset()); 143 144 TRACE(" +%d section name : \"%.*s\"\n", 145 static_cast<int>(section_name_start - decoder->start()), 146 string.length() < 20 ? string.length() : 20, section_name_start); 147 148 using SpecialSectionPair = std::pair<base::Vector<const char>, SectionCode>; 149 static constexpr SpecialSectionPair kSpecialSections[]{ 150 {base::StaticCharVector(kNameString), kNameSectionCode}, 151 {base::StaticCharVector(kSourceMappingURLString), 152 kSourceMappingURLSectionCode}, 153 {base::StaticCharVector(kCompilationHintsString), 154 kCompilationHintsSectionCode}, 155 {base::StaticCharVector(kBranchHintsString), kBranchHintsSectionCode}, 156 {base::StaticCharVector(kDebugInfoString), kDebugInfoSectionCode}, 157 {base::StaticCharVector(kExternalDebugInfoString), 158 kExternalDebugInfoSectionCode}}; 159 160 auto name_vec = base::Vector<const char>::cast( 161 base::VectorOf(section_name_start, string.length())); 162 for (auto& special_section : kSpecialSections) { 163 if (name_vec == special_section.first) return special_section.second; 164 } 165 166 return kUnknownSectionCode; 167} 168} // namespace 169 170// An iterator over the sections in a wasm binary module. 171// Automatically skips all unknown sections. 172class WasmSectionIterator { 173 public: 174 explicit WasmSectionIterator(Decoder* decoder) 175 : decoder_(decoder), 176 section_code_(kUnknownSectionCode), 177 section_start_(decoder->pc()), 178 section_end_(decoder->pc()) { 179 next(); 180 } 181 182 bool more() const { return decoder_->ok() && decoder_->more(); } 183 184 SectionCode section_code() const { return section_code_; } 185 186 const byte* section_start() const { return section_start_; } 187 188 uint32_t section_length() const { 189 return static_cast<uint32_t>(section_end_ - section_start_); 190 } 191 192 base::Vector<const uint8_t> payload() const { 193 return {payload_start_, payload_length()}; 194 } 195 196 const byte* payload_start() const { return payload_start_; } 197 198 uint32_t payload_length() const { 199 return static_cast<uint32_t>(section_end_ - payload_start_); 200 } 201 202 const byte* section_end() const { return section_end_; } 203 204 // Advances to the next section, checking that decoding the current section 205 // stopped at {section_end_}. 206 void advance(bool move_to_section_end = false) { 207 if (move_to_section_end && decoder_->pc() < section_end_) { 208 decoder_->consume_bytes( 209 static_cast<uint32_t>(section_end_ - decoder_->pc())); 210 } 211 if (decoder_->pc() != section_end_) { 212 const char* msg = decoder_->pc() < section_end_ ? "shorter" : "longer"; 213 decoder_->errorf(decoder_->pc(), 214 "section was %s than expected size " 215 "(%u bytes expected, %zu decoded)", 216 msg, section_length(), 217 static_cast<size_t>(decoder_->pc() - section_start_)); 218 } 219 next(); 220 } 221 222 private: 223 Decoder* decoder_; 224 SectionCode section_code_; 225 const byte* section_start_; 226 const byte* payload_start_; 227 const byte* section_end_; 228 229 // Reads the section code/name at the current position and sets up 230 // the embedder fields. 231 void next() { 232 if (!decoder_->more()) { 233 section_code_ = kUnknownSectionCode; 234 return; 235 } 236 section_start_ = decoder_->pc(); 237 uint8_t section_code = decoder_->consume_u8("section code"); 238 // Read and check the section size. 239 uint32_t section_length = decoder_->consume_u32v("section length"); 240 241 payload_start_ = decoder_->pc(); 242 if (decoder_->checkAvailable(section_length)) { 243 // Get the limit of the section within the module. 244 section_end_ = payload_start_ + section_length; 245 } else { 246 // The section would extend beyond the end of the module. 247 section_end_ = payload_start_; 248 } 249 250 if (section_code == kUnknownSectionCode) { 251 // Check for the known "name", "sourceMappingURL", or "compilationHints" 252 // section. 253 // To identify the unknown section we set the end of the decoder bytes to 254 // the end of the custom section, so that we do not read the section name 255 // beyond the end of the section. 256 const byte* module_end = decoder_->end(); 257 decoder_->set_end(section_end_); 258 section_code = IdentifyUnknownSectionInternal(decoder_); 259 if (decoder_->ok()) decoder_->set_end(module_end); 260 // As a side effect, the above function will forward the decoder to after 261 // the identifier string. 262 payload_start_ = decoder_->pc(); 263 } else if (!IsValidSectionCode(section_code)) { 264 decoder_->errorf(decoder_->pc(), "unknown section code #0x%02x", 265 section_code); 266 section_code = kUnknownSectionCode; 267 } 268 section_code_ = decoder_->failed() ? kUnknownSectionCode 269 : static_cast<SectionCode>(section_code); 270 271 if (section_code_ == kUnknownSectionCode && section_end_ > decoder_->pc()) { 272 // skip to the end of the unknown section. 273 uint32_t remaining = static_cast<uint32_t>(section_end_ - decoder_->pc()); 274 decoder_->consume_bytes(remaining, "section payload"); 275 } 276 } 277}; 278 279} // namespace 280 281// The main logic for decoding the bytes of a module. 282class ModuleDecoderImpl : public Decoder { 283 public: 284 explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin) 285 : Decoder(nullptr, nullptr), 286 enabled_features_(enabled), 287 origin_(origin) {} 288 289 ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start, 290 const byte* module_end, ModuleOrigin origin) 291 : Decoder(module_start, module_end), 292 enabled_features_(enabled), 293 module_start_(module_start), 294 module_end_(module_end), 295 origin_(origin) { 296 if (end_ < start_) { 297 error(start_, "end is less than start"); 298 end_ = start_; 299 } 300 } 301 302 void onFirstError() override { 303 pc_ = end_; // On error, terminate section decoding loop. 304 } 305 306 void DumpModule(const base::Vector<const byte> module_bytes) { 307 std::string path; 308 if (FLAG_dump_wasm_module_path) { 309 path = FLAG_dump_wasm_module_path; 310 if (path.size() && 311 !base::OS::isDirectorySeparator(path[path.size() - 1])) { 312 path += base::OS::DirectorySeparator(); 313 } 314 } 315 // File are named `HASH.{ok,failed}.wasm`. 316 size_t hash = base::hash_range(module_bytes.begin(), module_bytes.end()); 317 base::EmbeddedVector<char, 32> buf; 318 SNPrintF(buf, "%016zx.%s.wasm", hash, ok() ? "ok" : "failed"); 319 path += buf.begin(); 320 size_t rv = 0; 321 if (FILE* file = base::OS::FOpen(path.c_str(), "wb")) { 322 rv = fwrite(module_bytes.begin(), module_bytes.length(), 1, file); 323 base::Fclose(file); 324 } 325 if (rv != 1) { 326 OFStream os(stderr); 327 os << "Error while dumping wasm file to " << path << std::endl; 328 } 329 } 330 331 void StartDecoding(Counters* counters, AccountingAllocator* allocator) { 332 CHECK_NULL(module_); 333 SetCounters(counters); 334 module_.reset( 335 new WasmModule(std::make_unique<Zone>(allocator, "signatures"))); 336 module_->initial_pages = 0; 337 module_->maximum_pages = 0; 338 module_->mem_export = false; 339 module_->origin = origin_; 340 } 341 342 void DecodeModuleHeader(base::Vector<const uint8_t> bytes, uint8_t offset) { 343 if (failed()) return; 344 Reset(bytes, offset); 345 346 const byte* pos = pc_; 347 uint32_t magic_word = consume_u32("wasm magic"); 348#define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF 349 if (magic_word != kWasmMagic) { 350 errorf(pos, 351 "expected magic word %02x %02x %02x %02x, " 352 "found %02x %02x %02x %02x", 353 BYTES(kWasmMagic), BYTES(magic_word)); 354 } 355 356 pos = pc_; 357 { 358 uint32_t magic_version = consume_u32("wasm version"); 359 if (magic_version != kWasmVersion) { 360 errorf(pos, 361 "expected version %02x %02x %02x %02x, " 362 "found %02x %02x %02x %02x", 363 BYTES(kWasmVersion), BYTES(magic_version)); 364 } 365 } 366#undef BYTES 367 } 368 369 bool CheckSectionOrder(SectionCode section_code, 370 SectionCode prev_section_code, 371 SectionCode next_section_code) { 372 if (next_ordered_section_ > next_section_code) { 373 errorf(pc(), "The %s section must appear before the %s section", 374 SectionName(section_code), SectionName(next_section_code)); 375 return false; 376 } 377 if (next_ordered_section_ <= prev_section_code) { 378 next_ordered_section_ = prev_section_code + 1; 379 } 380 return true; 381 } 382 383 bool CheckUnorderedSection(SectionCode section_code) { 384 if (has_seen_unordered_section(section_code)) { 385 errorf(pc(), "Multiple %s sections not allowed", 386 SectionName(section_code)); 387 return false; 388 } 389 set_seen_unordered_section(section_code); 390 return true; 391 } 392 393 void DecodeSection(SectionCode section_code, 394 base::Vector<const uint8_t> bytes, uint32_t offset, 395 bool verify_functions = true) { 396 if (failed()) return; 397 Reset(bytes, offset); 398 TRACE("Section: %s\n", SectionName(section_code)); 399 TRACE("Decode Section %p - %p\n", bytes.begin(), bytes.end()); 400 401 // Check if the section is out-of-order. 402 if (section_code < next_ordered_section_ && 403 section_code < kFirstUnorderedSection) { 404 errorf(pc(), "unexpected section <%s>", SectionName(section_code)); 405 return; 406 } 407 408 switch (section_code) { 409 case kUnknownSectionCode: 410 break; 411 case kDataCountSectionCode: 412 if (!CheckUnorderedSection(section_code)) return; 413 // If wasm-gc is enabled, we allow the data cound section anywhere in 414 // the module. 415 if (!enabled_features_.has_gc() && 416 !CheckSectionOrder(section_code, kElementSectionCode, 417 kCodeSectionCode)) { 418 return; 419 } 420 break; 421 case kTagSectionCode: 422 if (!CheckUnorderedSection(section_code)) return; 423 if (!CheckSectionOrder(section_code, kMemorySectionCode, 424 kGlobalSectionCode)) { 425 return; 426 } 427 break; 428 case kNameSectionCode: 429 // TODO(titzer): report out of place name section as a warning. 430 // Be lenient with placement of name section. All except first 431 // occurrence are ignored. 432 case kSourceMappingURLSectionCode: 433 // sourceMappingURL is a custom section and currently can occur anywhere 434 // in the module. In case of multiple sourceMappingURL sections, all 435 // except the first occurrence are ignored. 436 case kDebugInfoSectionCode: 437 // .debug_info is a custom section containing core DWARF information 438 // if produced by compiler. Its presence likely means that Wasm was 439 // built in a debug mode. 440 case kExternalDebugInfoSectionCode: 441 // external_debug_info is a custom section containing a reference to an 442 // external symbol file. 443 case kCompilationHintsSectionCode: 444 // TODO(frgossen): report out of place compilation hints section as a 445 // warning. 446 // Be lenient with placement of compilation hints section. All except 447 // first occurrence after function section and before code section are 448 // ignored. 449 break; 450 case kBranchHintsSectionCode: 451 // TODO(yuri): report out of place branch hints section as a 452 // warning. 453 // Be lenient with placement of compilation hints section. All except 454 // first occurrence after function section and before code section are 455 // ignored. 456 break; 457 default: 458 next_ordered_section_ = section_code + 1; 459 break; 460 } 461 462 switch (section_code) { 463 case kUnknownSectionCode: 464 break; 465 case kTypeSectionCode: 466 DecodeTypeSection(); 467 break; 468 case kImportSectionCode: 469 DecodeImportSection(); 470 break; 471 case kFunctionSectionCode: 472 DecodeFunctionSection(); 473 break; 474 case kTableSectionCode: 475 DecodeTableSection(); 476 break; 477 case kMemorySectionCode: 478 DecodeMemorySection(); 479 break; 480 case kGlobalSectionCode: 481 DecodeGlobalSection(); 482 break; 483 case kExportSectionCode: 484 DecodeExportSection(); 485 break; 486 case kStartSectionCode: 487 DecodeStartSection(); 488 break; 489 case kCodeSectionCode: 490 DecodeCodeSection(verify_functions); 491 break; 492 case kElementSectionCode: 493 DecodeElementSection(); 494 break; 495 case kDataSectionCode: 496 DecodeDataSection(); 497 break; 498 case kNameSectionCode: 499 DecodeNameSection(); 500 break; 501 case kSourceMappingURLSectionCode: 502 DecodeSourceMappingURLSection(); 503 break; 504 case kDebugInfoSectionCode: 505 // If there is an explicit source map, prefer it over DWARF info. 506 if (module_->debug_symbols.type == WasmDebugSymbols::Type::None) { 507 module_->debug_symbols = {WasmDebugSymbols::Type::EmbeddedDWARF, {}}; 508 } 509 consume_bytes(static_cast<uint32_t>(end_ - start_), ".debug_info"); 510 break; 511 case kExternalDebugInfoSectionCode: 512 DecodeExternalDebugInfoSection(); 513 break; 514 case kCompilationHintsSectionCode: 515 if (enabled_features_.has_compilation_hints()) { 516 DecodeCompilationHintsSection(); 517 } else { 518 // Ignore this section when feature was disabled. It is an optional 519 // custom section anyways. 520 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 521 } 522 break; 523 case kBranchHintsSectionCode: 524 if (enabled_features_.has_branch_hinting()) { 525 DecodeBranchHintsSection(); 526 } else { 527 // Ignore this section when feature was disabled. It is an optional 528 // custom section anyways. 529 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 530 } 531 break; 532 case kDataCountSectionCode: 533 DecodeDataCountSection(); 534 break; 535 case kTagSectionCode: 536 if (enabled_features_.has_eh()) { 537 DecodeTagSection(); 538 } else { 539 errorf(pc(), 540 "unexpected section <%s> (enable with --experimental-wasm-eh)", 541 SectionName(section_code)); 542 } 543 break; 544 default: 545 errorf(pc(), "unexpected section <%s>", SectionName(section_code)); 546 return; 547 } 548 549 if (pc() != bytes.end()) { 550 const char* msg = pc() < bytes.end() ? "shorter" : "longer"; 551 errorf(pc(), 552 "section was %s than expected size " 553 "(%zu bytes expected, %zu decoded)", 554 msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin())); 555 } 556 } 557 558 TypeDefinition consume_base_type_definition() { 559 DCHECK(enabled_features_.has_gc()); 560 uint8_t kind = consume_u8("type kind"); 561 switch (kind) { 562 case kWasmFunctionTypeCode: { 563 const FunctionSig* sig = consume_sig(module_->signature_zone.get()); 564 return {sig, kNoSuperType}; 565 } 566 case kWasmStructTypeCode: { 567 const StructType* type = consume_struct(module_->signature_zone.get()); 568 return {type, kNoSuperType}; 569 } 570 case kWasmArrayTypeCode: { 571 const ArrayType* type = consume_array(module_->signature_zone.get()); 572 return {type, kNoSuperType}; 573 } 574 case kWasmFunctionNominalCode: 575 case kWasmArrayNominalCode: 576 case kWasmStructNominalCode: 577 errorf(pc() - 1, 578 "mixing nominal and isorecursive types is not allowed"); 579 return {}; 580 default: 581 errorf(pc() - 1, "unknown type form: %d", kind); 582 return {}; 583 } 584 } 585 586 bool check_supertype(uint32_t supertype) { 587 if (V8_UNLIKELY(supertype >= module_->types.size())) { 588 errorf(pc(), "type %zu: forward-declared supertype %d", 589 module_->types.size(), supertype); 590 return false; 591 } 592 return true; 593 } 594 595 TypeDefinition consume_nominal_type_definition() { 596 DCHECK(enabled_features_.has_gc()); 597 size_t num_types = module_->types.size(); 598 uint8_t kind = consume_u8("type kind"); 599 switch (kind) { 600 case kWasmFunctionNominalCode: { 601 const FunctionSig* sig = consume_sig(module_->signature_zone.get()); 602 uint32_t super_index = kNoSuperType; 603 HeapType super_type = consume_super_type(); 604 if (super_type.is_index()) { 605 super_index = super_type.representation(); 606 } else if (V8_UNLIKELY(super_type != HeapType::kFunc)) { 607 errorf(pc() - 1, "type %zu: invalid supertype %d", num_types, 608 super_type.code()); 609 return {}; 610 } 611 return {sig, super_index}; 612 } 613 case kWasmStructNominalCode: { 614 const StructType* type = consume_struct(module_->signature_zone.get()); 615 uint32_t super_index = kNoSuperType; 616 HeapType super_type = consume_super_type(); 617 if (super_type.is_index()) { 618 super_index = super_type.representation(); 619 } else if (V8_UNLIKELY(super_type != HeapType::kData)) { 620 errorf(pc() - 1, "type %zu: invalid supertype %d", num_types, 621 super_type.code()); 622 return {}; 623 } 624 return {type, super_index}; 625 } 626 case kWasmArrayNominalCode: { 627 const ArrayType* type = consume_array(module_->signature_zone.get()); 628 uint32_t super_index = kNoSuperType; 629 HeapType super_type = consume_super_type(); 630 if (super_type.is_index()) { 631 super_index = super_type.representation(); 632 } else if (V8_UNLIKELY(super_type != HeapType::kData)) { 633 errorf(pc() - 1, "type %zu: invalid supertype %d", num_types, 634 super_type.code()); 635 return {}; 636 } 637 return {type, super_index}; 638 } 639 case kWasmFunctionTypeCode: 640 case kWasmArrayTypeCode: 641 case kWasmStructTypeCode: 642 case kWasmSubtypeCode: 643 case kWasmRecursiveTypeGroupCode: 644 errorf(pc() - 1, 645 "mixing nominal and isorecursive types is not allowed"); 646 return {}; 647 default: 648 errorf(pc() - 1, "unknown type form: %d", kind); 649 return {}; 650 } 651 } 652 653 TypeDefinition consume_subtype_definition() { 654 DCHECK(enabled_features_.has_gc()); 655 uint8_t kind = read_u8<Decoder::kFullValidation>(pc(), "type kind"); 656 if (kind == kWasmSubtypeCode) { 657 consume_bytes(1, "subtype definition"); 658 constexpr uint32_t kMaximumSupertypes = 1; 659 uint32_t supertype_count = 660 consume_count("supertype count", kMaximumSupertypes); 661 uint32_t supertype = 662 supertype_count == 1 ? consume_u32v("supertype") : kNoSuperType; 663 if (!check_supertype(supertype)) return {}; 664 TypeDefinition type = consume_base_type_definition(); 665 type.supertype = supertype; 666 return type; 667 } else { 668 return consume_base_type_definition(); 669 } 670 } 671 672 void DecodeTypeSection() { 673 TypeCanonicalizer* type_canon = GetTypeCanonicalizer(); 674 uint32_t types_count = consume_count("types count", kV8MaxWasmTypes); 675 676 // Non wasm-gc type section decoding. 677 if (!enabled_features_.has_gc()) { 678 module_->types.reserve(types_count); 679 for (uint32_t i = 0; i < types_count; ++i) { 680 TRACE("DecodeSignature[%d] module+%d\n", i, 681 static_cast<int>(pc_ - start_)); 682 expect_u8("signature definition", kWasmFunctionTypeCode); 683 const FunctionSig* sig = consume_sig(module_->signature_zone.get()); 684 if (!ok()) break; 685 module_->add_signature(sig, kNoSuperType); 686 if (FLAG_wasm_type_canonicalization) { 687 type_canon->AddRecursiveGroup(module_.get(), 1); 688 } 689 } 690 return; 691 } 692 693 if (types_count > 0) { 694 uint8_t first_type_opcode = this->read_u8<Decoder::kFullValidation>(pc()); 695 if (first_type_opcode == kWasmFunctionNominalCode || 696 first_type_opcode == kWasmStructNominalCode || 697 first_type_opcode == kWasmArrayNominalCode) { 698 // wasm-gc nominal type section decoding. 699 // In a nominal module, all types belong in the same recursive group. We 700 // use the type vector's capacity to mark the end of the current 701 // recursive group. 702 module_->types.reserve(types_count); 703 for (uint32_t i = 0; ok() && i < types_count; ++i) { 704 TRACE("DecodeType[%d] module+%d\n", i, 705 static_cast<int>(pc_ - start_)); 706 TypeDefinition type = consume_nominal_type_definition(); 707 if (ok()) module_->add_type(type); 708 } 709 if (ok() && FLAG_wasm_type_canonicalization) { 710 type_canon->AddRecursiveGroup(module_.get(), types_count); 711 } 712 } else { 713 // wasm-gc isorecursive type section decoding. 714 for (uint32_t i = 0; ok() && i < types_count; ++i) { 715 TRACE("DecodeType[%d] module+%d\n", i, 716 static_cast<int>(pc_ - start_)); 717 uint8_t kind = read_u8<Decoder::kFullValidation>(pc(), "type kind"); 718 if (kind == kWasmRecursiveTypeGroupCode) { 719 consume_bytes(1, "rec. group definition"); 720 uint32_t group_size = 721 consume_count("recursive group size", kV8MaxWasmTypes); 722 if (module_->types.size() + group_size > kV8MaxWasmTypes) { 723 errorf(pc(), "Type definition count exeeds maximum %zu", 724 kV8MaxWasmTypes); 725 return; 726 } 727 // Reserve space for the current recursive group, so we are 728 // allowed to reference its elements. 729 module_->types.reserve(module_->types.size() + group_size); 730 for (uint32_t i = 0; i < group_size; i++) { 731 TypeDefinition type = consume_subtype_definition(); 732 if (ok()) module_->add_type(type); 733 } 734 if (ok() && FLAG_wasm_type_canonicalization) { 735 type_canon->AddRecursiveGroup(module_.get(), group_size); 736 } 737 } else { 738 TypeDefinition type = consume_subtype_definition(); 739 if (ok()) { 740 module_->add_type(type); 741 if (FLAG_wasm_type_canonicalization) { 742 type_canon->AddRecursiveGroup(module_.get(), 1); 743 } 744 } 745 } 746 } 747 } 748 } 749 750 // Check validity of explicitly defined supertypes. 751 const WasmModule* module = module_.get(); 752 for (uint32_t i = 0; ok() && i < types_count; ++i) { 753 uint32_t explicit_super = module_->supertype(i); 754 if (explicit_super == kNoSuperType) continue; 755 DCHECK_LT(explicit_super, types_count); // {consume_super_type} checks. 756 int depth = GetSubtypingDepth(module, i); 757 if (depth > static_cast<int>(kV8MaxRttSubtypingDepth)) { 758 errorf("type %d: subtyping depth is greater than allowed", i); 759 continue; 760 } 761 // TODO(7748): Replace this with a DCHECK once we reject inheritance 762 // cycles for nominal modules. 763 if (depth == -1) { 764 errorf("type %d: cyclic inheritance", i); 765 continue; 766 } 767 if (!ValidSubtypeDefinition(i, explicit_super, module, module)) { 768 errorf("type %d has invalid explicit supertype %d", i, explicit_super); 769 continue; 770 } 771 } 772 module_->signature_map.Freeze(); 773 } 774 775 void DecodeImportSection() { 776 uint32_t import_table_count = 777 consume_count("imports count", kV8MaxWasmImports); 778 module_->import_table.reserve(import_table_count); 779 for (uint32_t i = 0; ok() && i < import_table_count; ++i) { 780 TRACE("DecodeImportTable[%d] module+%d\n", i, 781 static_cast<int>(pc_ - start_)); 782 783 module_->import_table.push_back({ 784 {0, 0}, // module_name 785 {0, 0}, // field_name 786 kExternalFunction, // kind 787 0 // index 788 }); 789 WasmImport* import = &module_->import_table.back(); 790 const byte* pos = pc_; 791 import->module_name = consume_string(this, true, "module name"); 792 import->field_name = consume_string(this, true, "field name"); 793 import->kind = 794 static_cast<ImportExportKindCode>(consume_u8("import kind")); 795 switch (import->kind) { 796 case kExternalFunction: { 797 // ===== Imported function =========================================== 798 import->index = static_cast<uint32_t>(module_->functions.size()); 799 module_->num_imported_functions++; 800 module_->functions.push_back({nullptr, // sig 801 import->index, // func_index 802 0, // sig_index 803 {0, 0}, // code 804 0, // feedback slots 805 true, // imported 806 false, // exported 807 false}); // declared 808 WasmFunction* function = &module_->functions.back(); 809 function->sig_index = 810 consume_sig_index(module_.get(), &function->sig); 811 break; 812 } 813 case kExternalTable: { 814 // ===== Imported table ============================================== 815 import->index = static_cast<uint32_t>(module_->tables.size()); 816 module_->num_imported_tables++; 817 module_->tables.emplace_back(); 818 WasmTable* table = &module_->tables.back(); 819 table->imported = true; 820 const byte* type_position = pc(); 821 ValueType type = consume_reference_type(); 822 if (!WasmTable::IsValidTableType(type, module_.get())) { 823 errorf(type_position, "Invalid table type %s", type.name().c_str()); 824 break; 825 } 826 table->type = type; 827 uint8_t flags = validate_table_flags("element count"); 828 consume_resizable_limits( 829 "element count", "elements", std::numeric_limits<uint32_t>::max(), 830 &table->initial_size, &table->has_maximum_size, 831 std::numeric_limits<uint32_t>::max(), &table->maximum_size, 832 flags); 833 break; 834 } 835 case kExternalMemory: { 836 // ===== Imported memory ============================================= 837 if (!AddMemory(module_.get())) break; 838 uint8_t flags = validate_memory_flags(&module_->has_shared_memory, 839 &module_->is_memory64); 840 consume_resizable_limits( 841 "memory", "pages", kSpecMaxMemoryPages, &module_->initial_pages, 842 &module_->has_maximum_pages, kSpecMaxMemoryPages, 843 &module_->maximum_pages, flags); 844 break; 845 } 846 case kExternalGlobal: { 847 // ===== Imported global ============================================= 848 import->index = static_cast<uint32_t>(module_->globals.size()); 849 module_->globals.push_back({kWasmVoid, false, {}, {0}, true, false}); 850 WasmGlobal* global = &module_->globals.back(); 851 global->type = consume_value_type(); 852 global->mutability = consume_mutability(); 853 if (global->mutability) { 854 module_->num_imported_mutable_globals++; 855 } 856 break; 857 } 858 case kExternalTag: { 859 // ===== Imported tag ================================================ 860 if (!enabled_features_.has_eh()) { 861 errorf(pos, "unknown import kind 0x%02x", import->kind); 862 break; 863 } 864 import->index = static_cast<uint32_t>(module_->tags.size()); 865 const WasmTagSig* tag_sig = nullptr; 866 consume_exception_attribute(); // Attribute ignored for now. 867 consume_tag_sig_index(module_.get(), &tag_sig); 868 module_->tags.emplace_back(tag_sig); 869 break; 870 } 871 default: 872 errorf(pos, "unknown import kind 0x%02x", import->kind); 873 break; 874 } 875 } 876 } 877 878 void DecodeFunctionSection() { 879 uint32_t functions_count = 880 consume_count("functions count", kV8MaxWasmFunctions); 881 auto counter = 882 SELECT_WASM_COUNTER(GetCounters(), origin_, wasm_functions_per, module); 883 counter->AddSample(static_cast<int>(functions_count)); 884 DCHECK_EQ(module_->functions.size(), module_->num_imported_functions); 885 uint32_t total_function_count = 886 module_->num_imported_functions + functions_count; 887 module_->functions.reserve(total_function_count); 888 module_->num_declared_functions = functions_count; 889 for (uint32_t i = 0; i < functions_count; ++i) { 890 uint32_t func_index = static_cast<uint32_t>(module_->functions.size()); 891 module_->functions.push_back({nullptr, // sig 892 func_index, // func_index 893 0, // sig_index 894 {0, 0}, // code 895 0, // feedback slots 896 false, // imported 897 false, // exported 898 false}); // declared 899 WasmFunction* function = &module_->functions.back(); 900 function->sig_index = consume_sig_index(module_.get(), &function->sig); 901 if (!ok()) return; 902 } 903 DCHECK_EQ(module_->functions.size(), total_function_count); 904 } 905 906 void DecodeTableSection() { 907 uint32_t table_count = consume_count("table count", kV8MaxWasmTables); 908 909 for (uint32_t i = 0; ok() && i < table_count; i++) { 910 module_->tables.emplace_back(); 911 WasmTable* table = &module_->tables.back(); 912 const byte* type_position = pc(); 913 ValueType table_type = consume_reference_type(); 914 if (!WasmTable::IsValidTableType(table_type, module_.get())) { 915 error(type_position, 916 "Currently, only externref and function references are allowed " 917 "as table types"); 918 continue; 919 } 920 table->type = table_type; 921 uint8_t flags = validate_table_flags("table elements"); 922 consume_resizable_limits( 923 "table elements", "elements", std::numeric_limits<uint32_t>::max(), 924 &table->initial_size, &table->has_maximum_size, 925 std::numeric_limits<uint32_t>::max(), &table->maximum_size, flags); 926 if (!table_type.is_defaultable()) { 927 table->initial_value = consume_init_expr(module_.get(), table_type); 928 } 929 } 930 } 931 932 void DecodeMemorySection() { 933 uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories); 934 935 for (uint32_t i = 0; ok() && i < memory_count; i++) { 936 if (!AddMemory(module_.get())) break; 937 uint8_t flags = validate_memory_flags(&module_->has_shared_memory, 938 &module_->is_memory64); 939 consume_resizable_limits("memory", "pages", kSpecMaxMemoryPages, 940 &module_->initial_pages, 941 &module_->has_maximum_pages, kSpecMaxMemoryPages, 942 &module_->maximum_pages, flags); 943 } 944 } 945 946 void DecodeGlobalSection() { 947 uint32_t globals_count = consume_count("globals count", kV8MaxWasmGlobals); 948 uint32_t imported_globals = static_cast<uint32_t>(module_->globals.size()); 949 // It is important to not resize the globals vector from the beginning, 950 // because we use its current size when decoding the initializer. 951 module_->globals.reserve(imported_globals + globals_count); 952 for (uint32_t i = 0; ok() && i < globals_count; ++i) { 953 TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_)); 954 ValueType type = consume_value_type(); 955 bool mutability = consume_mutability(); 956 if (failed()) break; 957 ConstantExpression init = consume_init_expr(module_.get(), type); 958 module_->globals.push_back({type, mutability, init, {0}, false, false}); 959 } 960 if (ok()) CalculateGlobalOffsets(module_.get()); 961 } 962 963 void DecodeExportSection() { 964 uint32_t export_table_count = 965 consume_count("exports count", kV8MaxWasmExports); 966 module_->export_table.reserve(export_table_count); 967 for (uint32_t i = 0; ok() && i < export_table_count; ++i) { 968 TRACE("DecodeExportTable[%d] module+%d\n", i, 969 static_cast<int>(pc_ - start_)); 970 971 module_->export_table.push_back({ 972 {0, 0}, // name 973 kExternalFunction, // kind 974 0 // index 975 }); 976 WasmExport* exp = &module_->export_table.back(); 977 978 exp->name = consume_string(this, true, "field name"); 979 980 const byte* pos = pc(); 981 exp->kind = static_cast<ImportExportKindCode>(consume_u8("export kind")); 982 switch (exp->kind) { 983 case kExternalFunction: { 984 WasmFunction* func = nullptr; 985 exp->index = 986 consume_func_index(module_.get(), &func, "export function index"); 987 988 if (failed()) break; 989 DCHECK_NOT_NULL(func); 990 991 module_->num_exported_functions++; 992 func->exported = true; 993 // Exported functions are considered "declared". 994 func->declared = true; 995 break; 996 } 997 case kExternalTable: { 998 WasmTable* table = nullptr; 999 exp->index = consume_table_index(module_.get(), &table); 1000 if (table) table->exported = true; 1001 break; 1002 } 1003 case kExternalMemory: { 1004 uint32_t index = consume_u32v("memory index"); 1005 // TODO(titzer): This should become more regular 1006 // once we support multiple memories. 1007 if (!module_->has_memory || index != 0) { 1008 error("invalid memory index != 0"); 1009 } 1010 module_->mem_export = true; 1011 break; 1012 } 1013 case kExternalGlobal: { 1014 WasmGlobal* global = nullptr; 1015 exp->index = consume_global_index(module_.get(), &global); 1016 if (global) { 1017 global->exported = true; 1018 } 1019 break; 1020 } 1021 case kExternalTag: { 1022 if (!enabled_features_.has_eh()) { 1023 errorf(pos, "invalid export kind 0x%02x", exp->kind); 1024 break; 1025 } 1026 WasmTag* tag = nullptr; 1027 exp->index = consume_tag_index(module_.get(), &tag); 1028 break; 1029 } 1030 default: 1031 errorf(pos, "invalid export kind 0x%02x", exp->kind); 1032 break; 1033 } 1034 } 1035 // Check for duplicate exports (except for asm.js). 1036 if (ok() && origin_ == kWasmOrigin && module_->export_table.size() > 1) { 1037 std::vector<WasmExport> sorted_exports(module_->export_table); 1038 1039 auto cmp_less = [this](const WasmExport& a, const WasmExport& b) { 1040 // Return true if a < b. 1041 if (a.name.length() != b.name.length()) { 1042 return a.name.length() < b.name.length(); 1043 } 1044 const byte* left = start() + GetBufferRelativeOffset(a.name.offset()); 1045 const byte* right = start() + GetBufferRelativeOffset(b.name.offset()); 1046 return memcmp(left, right, a.name.length()) < 0; 1047 }; 1048 std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less); 1049 1050 auto it = sorted_exports.begin(); 1051 WasmExport* last = &*it++; 1052 for (auto end = sorted_exports.end(); it != end; last = &*it++) { 1053 DCHECK(!cmp_less(*it, *last)); // Vector must be sorted. 1054 if (!cmp_less(*last, *it)) { 1055 const byte* pc = start() + GetBufferRelativeOffset(it->name.offset()); 1056 TruncatedUserString<> name(pc, it->name.length()); 1057 errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d", 1058 name.length(), name.start(), ExternalKindName(last->kind), 1059 last->index, ExternalKindName(it->kind), it->index); 1060 break; 1061 } 1062 } 1063 } 1064 } 1065 1066 void DecodeStartSection() { 1067 WasmFunction* func; 1068 const byte* pos = pc_; 1069 module_->start_function_index = 1070 consume_func_index(module_.get(), &func, "start function index"); 1071 if (func && 1072 (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) { 1073 error(pos, "invalid start function: non-zero parameter or return count"); 1074 } 1075 } 1076 1077 void DecodeElementSection() { 1078 uint32_t element_count = 1079 consume_count("element count", FLAG_wasm_max_table_size); 1080 1081 for (uint32_t i = 0; i < element_count; ++i) { 1082 WasmElemSegment segment = consume_element_segment_header(); 1083 if (failed()) return; 1084 DCHECK_NE(segment.type, kWasmBottom); 1085 1086 uint32_t num_elem = 1087 consume_count("number of elements", max_table_init_entries()); 1088 1089 for (uint32_t j = 0; j < num_elem; j++) { 1090 ConstantExpression entry = 1091 segment.element_type == WasmElemSegment::kExpressionElements 1092 ? consume_init_expr(module_.get(), segment.type) 1093 : ConstantExpression::RefFunc( 1094 consume_element_func_index(segment.type)); 1095 if (failed()) return; 1096 segment.entries.push_back(entry); 1097 } 1098 module_->elem_segments.push_back(std::move(segment)); 1099 } 1100 } 1101 1102 void DecodeCodeSection(bool verify_functions) { 1103 StartCodeSection(); 1104 uint32_t code_section_start = pc_offset(); 1105 uint32_t functions_count = consume_u32v("functions count"); 1106 CheckFunctionsCount(functions_count, code_section_start); 1107 for (uint32_t i = 0; ok() && i < functions_count; ++i) { 1108 const byte* pos = pc(); 1109 uint32_t size = consume_u32v("body size"); 1110 if (size > kV8MaxWasmFunctionSize) { 1111 errorf(pos, "size %u > maximum function size %zu", size, 1112 kV8MaxWasmFunctionSize); 1113 return; 1114 } 1115 uint32_t offset = pc_offset(); 1116 consume_bytes(size, "function body"); 1117 if (failed()) break; 1118 DecodeFunctionBody(i, size, offset, verify_functions); 1119 } 1120 DCHECK_GE(pc_offset(), code_section_start); 1121 set_code_section(code_section_start, pc_offset() - code_section_start); 1122 } 1123 1124 void StartCodeSection() { 1125 if (ok()) { 1126 // Make sure global offset were calculated before they get accessed during 1127 // function compilation. 1128 CalculateGlobalOffsets(module_.get()); 1129 } 1130 } 1131 1132 bool CheckFunctionsCount(uint32_t functions_count, uint32_t error_offset) { 1133 if (functions_count != module_->num_declared_functions) { 1134 errorf(error_offset, "function body count %u mismatch (%u expected)", 1135 functions_count, module_->num_declared_functions); 1136 return false; 1137 } 1138 return true; 1139 } 1140 1141 void DecodeFunctionBody(uint32_t index, uint32_t length, uint32_t offset, 1142 bool verify_functions) { 1143 WasmFunction* function = 1144 &module_->functions[index + module_->num_imported_functions]; 1145 function->code = {offset, length}; 1146 if (verify_functions) { 1147 ModuleWireBytes bytes(module_start_, module_end_); 1148 VerifyFunctionBody(module_->signature_zone->allocator(), 1149 index + module_->num_imported_functions, bytes, 1150 module_.get(), function); 1151 } 1152 } 1153 1154 bool CheckDataSegmentsCount(uint32_t data_segments_count) { 1155 if (has_seen_unordered_section(kDataCountSectionCode) && 1156 data_segments_count != module_->num_declared_data_segments) { 1157 errorf(pc(), "data segments count %u mismatch (%u expected)", 1158 data_segments_count, module_->num_declared_data_segments); 1159 return false; 1160 } 1161 return true; 1162 } 1163 1164 void DecodeDataSection() { 1165 uint32_t data_segments_count = 1166 consume_count("data segments count", kV8MaxWasmDataSegments); 1167 if (!CheckDataSegmentsCount(data_segments_count)) return; 1168 1169 module_->data_segments.reserve(data_segments_count); 1170 for (uint32_t i = 0; ok() && i < data_segments_count; ++i) { 1171 const byte* pos = pc(); 1172 TRACE("DecodeDataSegment[%d] module+%d\n", i, 1173 static_cast<int>(pc_ - start_)); 1174 1175 bool is_active; 1176 uint32_t memory_index; 1177 ConstantExpression dest_addr; 1178 consume_data_segment_header(&is_active, &memory_index, &dest_addr); 1179 if (failed()) break; 1180 1181 if (is_active) { 1182 if (!module_->has_memory) { 1183 error("cannot load data without memory"); 1184 break; 1185 } 1186 if (memory_index != 0) { 1187 errorf(pos, "illegal memory index %u != 0", memory_index); 1188 break; 1189 } 1190 } 1191 1192 uint32_t source_length = consume_u32v("source size"); 1193 uint32_t source_offset = pc_offset(); 1194 1195 if (is_active) { 1196 module_->data_segments.emplace_back(std::move(dest_addr)); 1197 } else { 1198 module_->data_segments.emplace_back(); 1199 } 1200 1201 WasmDataSegment* segment = &module_->data_segments.back(); 1202 1203 consume_bytes(source_length, "segment data"); 1204 if (failed()) break; 1205 1206 segment->source = {source_offset, source_length}; 1207 } 1208 } 1209 1210 void DecodeNameSection() { 1211 // TODO(titzer): find a way to report name errors as warnings. 1212 // Ignore all but the first occurrence of name section. 1213 if (!has_seen_unordered_section(kNameSectionCode)) { 1214 set_seen_unordered_section(kNameSectionCode); 1215 // Use an inner decoder so that errors don't fail the outer decoder. 1216 Decoder inner(start_, pc_, end_, buffer_offset_); 1217 // Decode all name subsections. 1218 // Be lenient with their order. 1219 while (inner.ok() && inner.more()) { 1220 uint8_t name_type = inner.consume_u8("name type"); 1221 if (name_type & 0x80) inner.error("name type if not varuint7"); 1222 1223 uint32_t name_payload_len = inner.consume_u32v("name payload length"); 1224 if (!inner.checkAvailable(name_payload_len)) break; 1225 1226 // Decode module name, ignore the rest. 1227 // Function and local names will be decoded when needed. 1228 if (name_type == NameSectionKindCode::kModuleCode) { 1229 WireBytesRef name = consume_string(&inner, false, "module name"); 1230 if (inner.ok() && validate_utf8(&inner, name)) { 1231 module_->name = name; 1232 } 1233 } else { 1234 inner.consume_bytes(name_payload_len, "name subsection payload"); 1235 } 1236 } 1237 } 1238 // Skip the whole names section in the outer decoder. 1239 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 1240 } 1241 1242 void DecodeSourceMappingURLSection() { 1243 Decoder inner(start_, pc_, end_, buffer_offset_); 1244 WireBytesRef url = wasm::consume_string(&inner, true, "module name"); 1245 if (inner.ok() && 1246 module_->debug_symbols.type != WasmDebugSymbols::Type::SourceMap) { 1247 module_->debug_symbols = {WasmDebugSymbols::Type::SourceMap, url}; 1248 } 1249 set_seen_unordered_section(kSourceMappingURLSectionCode); 1250 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 1251 } 1252 1253 void DecodeExternalDebugInfoSection() { 1254 Decoder inner(start_, pc_, end_, buffer_offset_); 1255 WireBytesRef url = 1256 wasm::consume_string(&inner, true, "external symbol file"); 1257 // If there is an explicit source map, prefer it over DWARF info. 1258 if (inner.ok() && 1259 module_->debug_symbols.type != WasmDebugSymbols::Type::SourceMap) { 1260 module_->debug_symbols = {WasmDebugSymbols::Type::ExternalDWARF, url}; 1261 set_seen_unordered_section(kExternalDebugInfoSectionCode); 1262 } 1263 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 1264 } 1265 1266 void DecodeCompilationHintsSection() { 1267 TRACE("DecodeCompilationHints module+%d\n", static_cast<int>(pc_ - start_)); 1268 1269 // TODO(frgossen): Find a way to report compilation hint errors as warnings. 1270 // All except first occurrence after function section and before code 1271 // section are ignored. 1272 const bool before_function_section = 1273 next_ordered_section_ <= kFunctionSectionCode; 1274 const bool after_code_section = next_ordered_section_ > kCodeSectionCode; 1275 if (before_function_section || after_code_section || 1276 has_seen_unordered_section(kCompilationHintsSectionCode)) { 1277 return; 1278 } 1279 set_seen_unordered_section(kCompilationHintsSectionCode); 1280 1281 // TODO(frgossen) Propagate errors to outer decoder in experimental phase. 1282 // We should use an inner decoder later and propagate its errors as 1283 // warnings. 1284 Decoder& decoder = *this; 1285 // Decoder decoder(start_, pc_, end_, buffer_offset_); 1286 1287 // Ensure exactly one compilation hint per function. 1288 uint32_t hint_count = decoder.consume_u32v("compilation hint count"); 1289 if (hint_count != module_->num_declared_functions) { 1290 decoder.errorf(decoder.pc(), "Expected %u compilation hints (%u found)", 1291 module_->num_declared_functions, hint_count); 1292 } 1293 1294 // Decode sequence of compilation hints. 1295 if (decoder.ok()) { 1296 module_->compilation_hints.reserve(hint_count); 1297 } 1298 for (uint32_t i = 0; decoder.ok() && i < hint_count; i++) { 1299 TRACE("DecodeCompilationHints[%d] module+%d\n", i, 1300 static_cast<int>(pc_ - start_)); 1301 1302 // Compilation hints are encoded in one byte each. 1303 // +-------+----------+---------------+----------+ 1304 // | 2 bit | 2 bit | 2 bit | 2 bit | 1305 // | ... | Top tier | Baseline tier | Strategy | 1306 // +-------+----------+---------------+----------+ 1307 uint8_t hint_byte = decoder.consume_u8("compilation hint"); 1308 if (!decoder.ok()) break; 1309 1310 // Validate the hint_byte. 1311 // For the compilation strategy, all 2-bit values are valid. For the tier, 1312 // only 0x0, 0x1, and 0x2 are allowed. 1313 static_assert( 1314 static_cast<int>(WasmCompilationHintTier::kDefault) == 0 && 1315 static_cast<int>(WasmCompilationHintTier::kBaseline) == 1 && 1316 static_cast<int>(WasmCompilationHintTier::kOptimized) == 2, 1317 "The check below assumes that 0x03 is the only invalid 2-bit number " 1318 "for a compilation tier"); 1319 if (((hint_byte >> 2) & 0x03) == 0x03 || 1320 ((hint_byte >> 4) & 0x03) == 0x03) { 1321 decoder.errorf(decoder.pc(), 1322 "Invalid compilation hint %#04x (invalid tier 0x03)", 1323 hint_byte); 1324 break; 1325 } 1326 1327 // Decode compilation hint. 1328 WasmCompilationHint hint; 1329 hint.strategy = 1330 static_cast<WasmCompilationHintStrategy>(hint_byte & 0x03); 1331 hint.baseline_tier = 1332 static_cast<WasmCompilationHintTier>((hint_byte >> 2) & 0x03); 1333 hint.top_tier = 1334 static_cast<WasmCompilationHintTier>((hint_byte >> 4) & 0x03); 1335 1336 // Ensure that the top tier never downgrades a compilation result. If 1337 // baseline and top tier are the same compilation will be invoked only 1338 // once. 1339 if (hint.top_tier < hint.baseline_tier && 1340 hint.top_tier != WasmCompilationHintTier::kDefault) { 1341 decoder.errorf(decoder.pc(), 1342 "Invalid compilation hint %#04x (forbidden downgrade)", 1343 hint_byte); 1344 } 1345 1346 // Happily accept compilation hint. 1347 if (decoder.ok()) { 1348 module_->compilation_hints.push_back(std::move(hint)); 1349 } 1350 } 1351 1352 // If section was invalid reset compilation hints. 1353 if (decoder.failed()) { 1354 module_->compilation_hints.clear(); 1355 } 1356 1357 // @TODO(frgossen) Skip the whole compilation hints section in the outer 1358 // decoder if inner decoder was used. 1359 // consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 1360 } 1361 1362 void DecodeBranchHintsSection() { 1363 TRACE("DecodeBranchHints module+%d\n", static_cast<int>(pc_ - start_)); 1364 if (!has_seen_unordered_section(kBranchHintsSectionCode)) { 1365 set_seen_unordered_section(kBranchHintsSectionCode); 1366 // Use an inner decoder so that errors don't fail the outer decoder. 1367 Decoder inner(start_, pc_, end_, buffer_offset_); 1368 BranchHintInfo branch_hints; 1369 1370 uint32_t func_count = inner.consume_u32v("number of functions"); 1371 // Keep track of the previous function index to validate the ordering 1372 int64_t last_func_idx = -1; 1373 for (uint32_t i = 0; i < func_count; i++) { 1374 uint32_t func_idx = inner.consume_u32v("function index"); 1375 if (int64_t(func_idx) <= last_func_idx) { 1376 inner.errorf("Invalid function index: %d", func_idx); 1377 break; 1378 } 1379 last_func_idx = func_idx; 1380 uint32_t num_hints = inner.consume_u32v("number of hints"); 1381 BranchHintMap func_branch_hints; 1382 TRACE("DecodeBranchHints[%d] module+%d\n", func_idx, 1383 static_cast<int>(inner.pc() - inner.start())); 1384 // Keep track of the previous branch offset to validate the ordering 1385 int64_t last_br_off = -1; 1386 for (uint32_t j = 0; j < num_hints; ++j) { 1387 uint32_t br_off = inner.consume_u32v("branch instruction offset"); 1388 if (int64_t(br_off) <= last_br_off) { 1389 inner.errorf("Invalid branch offset: %d", br_off); 1390 break; 1391 } 1392 last_br_off = br_off; 1393 uint32_t data_size = inner.consume_u32v("data size"); 1394 if (data_size != 1) { 1395 inner.errorf("Invalid data size: %#x. Expected 1.", data_size); 1396 break; 1397 } 1398 uint32_t br_dir = inner.consume_u8("branch direction"); 1399 TRACE("DecodeBranchHints[%d][%d] module+%d\n", func_idx, br_off, 1400 static_cast<int>(inner.pc() - inner.start())); 1401 WasmBranchHint hint; 1402 switch (br_dir) { 1403 case 0: 1404 hint = WasmBranchHint::kUnlikely; 1405 break; 1406 case 1: 1407 hint = WasmBranchHint::kLikely; 1408 break; 1409 default: 1410 hint = WasmBranchHint::kNoHint; 1411 inner.errorf(inner.pc(), "Invalid branch hint %#x", br_dir); 1412 break; 1413 } 1414 if (!inner.ok()) { 1415 break; 1416 } 1417 func_branch_hints.insert(br_off, hint); 1418 } 1419 if (!inner.ok()) { 1420 break; 1421 } 1422 branch_hints.emplace(func_idx, std::move(func_branch_hints)); 1423 } 1424 // Extra unexpected bytes are an error. 1425 if (inner.more()) { 1426 inner.errorf("Unexpected extra bytes: %d\n", 1427 static_cast<int>(inner.pc() - inner.start())); 1428 } 1429 // If everything went well, accept the hints for the module. 1430 if (inner.ok()) { 1431 module_->branch_hints = std::move(branch_hints); 1432 } 1433 } 1434 // Skip the whole branch hints section in the outer decoder. 1435 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr); 1436 } 1437 1438 void DecodeDataCountSection() { 1439 module_->num_declared_data_segments = 1440 consume_count("data segments count", kV8MaxWasmDataSegments); 1441 } 1442 1443 void DecodeTagSection() { 1444 uint32_t tag_count = consume_count("tag count", kV8MaxWasmTags); 1445 for (uint32_t i = 0; ok() && i < tag_count; ++i) { 1446 TRACE("DecodeTag[%d] module+%d\n", i, static_cast<int>(pc_ - start_)); 1447 const WasmTagSig* tag_sig = nullptr; 1448 consume_exception_attribute(); // Attribute ignored for now. 1449 consume_tag_sig_index(module_.get(), &tag_sig); 1450 module_->tags.emplace_back(tag_sig); 1451 } 1452 } 1453 1454 bool CheckMismatchedCounts() { 1455 // The declared vs. defined function count is normally checked when 1456 // decoding the code section, but we have to check it here too in case the 1457 // code section is absent. 1458 if (module_->num_declared_functions != 0) { 1459 DCHECK_LT(module_->num_imported_functions, module_->functions.size()); 1460 // We know that the code section has been decoded if the first 1461 // non-imported function has its code set. 1462 if (!module_->functions[module_->num_imported_functions].code.is_set()) { 1463 errorf(pc(), "function count is %u, but code section is absent", 1464 module_->num_declared_functions); 1465 return false; 1466 } 1467 } 1468 // Perform a similar check for the DataCount and Data sections, where data 1469 // segments are declared but the Data section is absent. 1470 if (!CheckDataSegmentsCount( 1471 static_cast<uint32_t>(module_->data_segments.size()))) { 1472 return false; 1473 } 1474 return true; 1475 } 1476 1477 ModuleResult FinishDecoding(bool verify_functions = true) { 1478 if (ok() && CheckMismatchedCounts()) { 1479 // We calculate the global offsets here, because there may not be a 1480 // global section and code section that would have triggered the 1481 // calculation before. Even without the globals section the calculation 1482 // is needed because globals can also be defined in the import section. 1483 CalculateGlobalOffsets(module_.get()); 1484 } 1485 1486 ModuleResult result = toResult(std::move(module_)); 1487 if (verify_functions && result.ok() && intermediate_error_.has_error()) { 1488 // Copy error message and location. 1489 return ModuleResult{std::move(intermediate_error_)}; 1490 } 1491 return result; 1492 } 1493 1494 void set_code_section(uint32_t offset, uint32_t size) { 1495 module_->code = {offset, size}; 1496 } 1497 1498 // Decodes an entire module. 1499 ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator, 1500 bool verify_functions = true) { 1501 StartDecoding(counters, allocator); 1502 uint32_t offset = 0; 1503 base::Vector<const byte> orig_bytes(start(), end() - start()); 1504 DecodeModuleHeader(base::VectorOf(start(), end() - start()), offset); 1505 if (failed()) { 1506 return FinishDecoding(verify_functions); 1507 } 1508 // Size of the module header. 1509 offset += 8; 1510 Decoder decoder(start_ + offset, end_, offset); 1511 1512 WasmSectionIterator section_iter(&decoder); 1513 1514 while (ok()) { 1515 // Shift the offset by the section header length 1516 offset += section_iter.payload_start() - section_iter.section_start(); 1517 if (section_iter.section_code() != SectionCode::kUnknownSectionCode) { 1518 DecodeSection(section_iter.section_code(), section_iter.payload(), 1519 offset, verify_functions); 1520 } 1521 // Shift the offset by the remaining section payload 1522 offset += section_iter.payload_length(); 1523 if (!section_iter.more()) break; 1524 section_iter.advance(true); 1525 } 1526 1527 if (FLAG_dump_wasm_module) DumpModule(orig_bytes); 1528 1529 if (decoder.failed()) { 1530 return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr); 1531 } 1532 1533 return FinishDecoding(verify_functions); 1534 } 1535 1536 // Decodes a single anonymous function starting at {start_}. 1537 FunctionResult DecodeSingleFunction(Zone* zone, 1538 const ModuleWireBytes& wire_bytes, 1539 const WasmModule* module, 1540 std::unique_ptr<WasmFunction> function) { 1541 pc_ = start_; 1542 expect_u8("type form", kWasmFunctionTypeCode); 1543 if (!ok()) return FunctionResult{std::move(intermediate_error_)}; 1544 function->sig = consume_sig(zone); 1545 function->code = {off(pc_), static_cast<uint32_t>(end_ - pc_)}; 1546 1547 if (ok()) 1548 VerifyFunctionBody(zone->allocator(), 0, wire_bytes, module, 1549 function.get()); 1550 1551 if (intermediate_error_.has_error()) { 1552 return FunctionResult{std::move(intermediate_error_)}; 1553 } 1554 1555 return FunctionResult(std::move(function)); 1556 } 1557 1558 // Decodes a single function signature at {start}. 1559 const FunctionSig* DecodeFunctionSignature(Zone* zone, const byte* start) { 1560 pc_ = start; 1561 if (!expect_u8("type form", kWasmFunctionTypeCode)) return nullptr; 1562 const FunctionSig* result = consume_sig(zone); 1563 return ok() ? result : nullptr; 1564 } 1565 1566 ConstantExpression DecodeInitExprForTesting(ValueType expected) { 1567 return consume_init_expr(module_.get(), expected); 1568 } 1569 1570 const std::shared_ptr<WasmModule>& shared_module() const { return module_; } 1571 1572 Counters* GetCounters() const { 1573 DCHECK_NOT_NULL(counters_); 1574 return counters_; 1575 } 1576 1577 void SetCounters(Counters* counters) { 1578 DCHECK_NULL(counters_); 1579 counters_ = counters; 1580 } 1581 1582 private: 1583 const WasmFeatures enabled_features_; 1584 std::shared_ptr<WasmModule> module_; 1585 const byte* module_start_ = nullptr; 1586 const byte* module_end_ = nullptr; 1587 Counters* counters_ = nullptr; 1588 // The type section is the first section in a module. 1589 uint8_t next_ordered_section_ = kFirstSectionInModule; 1590 // We store next_ordered_section_ as uint8_t instead of SectionCode so that 1591 // we can increment it. This static_assert should make sure that SectionCode 1592 // does not get bigger than uint8_t accidentially. 1593 static_assert(sizeof(ModuleDecoderImpl::next_ordered_section_) == 1594 sizeof(SectionCode), 1595 "type mismatch"); 1596 uint32_t seen_unordered_sections_ = 0; 1597 static_assert(kBitsPerByte * 1598 sizeof(ModuleDecoderImpl::seen_unordered_sections_) > 1599 kLastKnownModuleSection, 1600 "not enough bits"); 1601 WasmError intermediate_error_; 1602 ModuleOrigin origin_; 1603 AccountingAllocator allocator_; 1604 Zone init_expr_zone_{&allocator_, "initializer expression zone"}; 1605 1606 bool has_seen_unordered_section(SectionCode section_code) { 1607 return seen_unordered_sections_ & (1 << section_code); 1608 } 1609 1610 void set_seen_unordered_section(SectionCode section_code) { 1611 seen_unordered_sections_ |= 1 << section_code; 1612 } 1613 1614 uint32_t off(const byte* ptr) { 1615 return static_cast<uint32_t>(ptr - start_) + buffer_offset_; 1616 } 1617 1618 bool AddMemory(WasmModule* module) { 1619 if (module->has_memory) { 1620 error("At most one memory is supported"); 1621 return false; 1622 } else { 1623 module->has_memory = true; 1624 return true; 1625 } 1626 } 1627 1628 // Calculate individual global offsets and total size of globals table. This 1629 // function should be called after all globals have been defined, which is 1630 // after the import section and the global section, but before the global 1631 // offsets are accessed, e.g. by the function compilers. The moment when this 1632 // function should be called is not well-defined, as the global section may 1633 // not exist. Therefore this function is called multiple times. 1634 void CalculateGlobalOffsets(WasmModule* module) { 1635 if (module->globals.empty() || module->untagged_globals_buffer_size != 0 || 1636 module->tagged_globals_buffer_size != 0) { 1637 // This function has already been executed before, so we don't have to 1638 // execute it again. 1639 return; 1640 } 1641 uint32_t untagged_offset = 0; 1642 uint32_t tagged_offset = 0; 1643 uint32_t num_imported_mutable_globals = 0; 1644 for (WasmGlobal& global : module->globals) { 1645 if (global.mutability && global.imported) { 1646 global.index = num_imported_mutable_globals++; 1647 } else if (global.type.is_reference()) { 1648 global.offset = tagged_offset; 1649 // All entries in the tagged_globals_buffer have size 1. 1650 tagged_offset++; 1651 } else { 1652 int size = global.type.value_kind_size(); 1653 untagged_offset = (untagged_offset + size - 1) & ~(size - 1); // align 1654 global.offset = untagged_offset; 1655 untagged_offset += size; 1656 } 1657 } 1658 module->untagged_globals_buffer_size = untagged_offset; 1659 module->tagged_globals_buffer_size = tagged_offset; 1660 } 1661 1662 // Verifies the body (code) of a given function. 1663 void VerifyFunctionBody(AccountingAllocator* allocator, uint32_t func_num, 1664 const ModuleWireBytes& wire_bytes, 1665 const WasmModule* module, WasmFunction* function) { 1666 WasmFunctionName func_name(function, 1667 wire_bytes.GetNameOrNull(function, module)); 1668 if (FLAG_trace_wasm_decoder) { 1669 StdoutStream{} << "Verifying wasm function " << func_name << std::endl; 1670 } 1671 FunctionBody body = { 1672 function->sig, function->code.offset(), 1673 start_ + GetBufferRelativeOffset(function->code.offset()), 1674 start_ + GetBufferRelativeOffset(function->code.end_offset())}; 1675 1676 WasmFeatures unused_detected_features = WasmFeatures::None(); 1677 DecodeResult result = VerifyWasmCode(allocator, enabled_features_, module, 1678 &unused_detected_features, body); 1679 1680 // If the decode failed and this is the first error, set error code and 1681 // location. 1682 if (result.failed() && intermediate_error_.empty()) { 1683 // Wrap the error message from the function decoder. 1684 std::ostringstream error_msg; 1685 error_msg << "in function " << func_name << ": " 1686 << result.error().message(); 1687 intermediate_error_ = WasmError{result.error().offset(), error_msg.str()}; 1688 } 1689 } 1690 1691 uint32_t consume_sig_index(WasmModule* module, const FunctionSig** sig) { 1692 const byte* pos = pc_; 1693 uint32_t sig_index = consume_u32v("signature index"); 1694 if (!module->has_signature(sig_index)) { 1695 errorf(pos, "signature index %u out of bounds (%d signatures)", sig_index, 1696 static_cast<int>(module->types.size())); 1697 *sig = nullptr; 1698 return 0; 1699 } 1700 *sig = module->signature(sig_index); 1701 return sig_index; 1702 } 1703 1704 uint32_t consume_tag_sig_index(WasmModule* module, const FunctionSig** sig) { 1705 const byte* pos = pc_; 1706 uint32_t sig_index = consume_sig_index(module, sig); 1707 if (*sig && (*sig)->return_count() != 0) { 1708 errorf(pos, "tag signature %u has non-void return", sig_index); 1709 *sig = nullptr; 1710 return 0; 1711 } 1712 return sig_index; 1713 } 1714 1715 uint32_t consume_count(const char* name, size_t maximum) { 1716 const byte* p = pc_; 1717 uint32_t count = consume_u32v(name); 1718 if (count > maximum) { 1719 errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum); 1720 return static_cast<uint32_t>(maximum); 1721 } 1722 return count; 1723 } 1724 1725 uint32_t consume_func_index(WasmModule* module, WasmFunction** func, 1726 const char* name) { 1727 return consume_index(name, &module->functions, func); 1728 } 1729 1730 uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) { 1731 return consume_index("global index", &module->globals, global); 1732 } 1733 1734 uint32_t consume_table_index(WasmModule* module, WasmTable** table) { 1735 return consume_index("table index", &module->tables, table); 1736 } 1737 1738 uint32_t consume_tag_index(WasmModule* module, WasmTag** tag) { 1739 return consume_index("tag index", &module->tags, tag); 1740 } 1741 1742 template <typename T> 1743 uint32_t consume_index(const char* name, std::vector<T>* vector, T** ptr) { 1744 const byte* pos = pc_; 1745 uint32_t index = consume_u32v(name); 1746 if (index >= vector->size()) { 1747 errorf(pos, "%s %u out of bounds (%d entr%s)", name, index, 1748 static_cast<int>(vector->size()), 1749 vector->size() == 1 ? "y" : "ies"); 1750 *ptr = nullptr; 1751 return 0; 1752 } 1753 *ptr = &(*vector)[index]; 1754 return index; 1755 } 1756 1757 uint8_t validate_table_flags(const char* name) { 1758 uint8_t flags = consume_u8("table limits flags"); 1759 STATIC_ASSERT(kNoMaximum < kWithMaximum); 1760 if (V8_UNLIKELY(flags > kWithMaximum)) { 1761 errorf(pc() - 1, "invalid %s limits flags", name); 1762 } 1763 return flags; 1764 } 1765 1766 uint8_t validate_memory_flags(bool* has_shared_memory, bool* is_memory64) { 1767 uint8_t flags = consume_u8("memory limits flags"); 1768 *has_shared_memory = false; 1769 switch (flags) { 1770 case kNoMaximum: 1771 case kWithMaximum: 1772 break; 1773 case kSharedNoMaximum: 1774 case kSharedWithMaximum: 1775 if (!enabled_features_.has_threads()) { 1776 errorf(pc() - 1, 1777 "invalid memory limits flags 0x%x (enable via " 1778 "--experimental-wasm-threads)", 1779 flags); 1780 } 1781 *has_shared_memory = true; 1782 // V8 does not support shared memory without a maximum. 1783 if (flags == kSharedNoMaximum) { 1784 errorf(pc() - 1, 1785 "memory limits flags must have maximum defined if shared is " 1786 "true"); 1787 } 1788 break; 1789 case kMemory64NoMaximum: 1790 case kMemory64WithMaximum: 1791 if (!enabled_features_.has_memory64()) { 1792 errorf(pc() - 1, 1793 "invalid memory limits flags 0x%x (enable via " 1794 "--experimental-wasm-memory64)", 1795 flags); 1796 } 1797 *is_memory64 = true; 1798 break; 1799 default: 1800 errorf(pc() - 1, "invalid memory limits flags 0x%x", flags); 1801 break; 1802 } 1803 return flags; 1804 } 1805 1806 void consume_resizable_limits(const char* name, const char* units, 1807 uint32_t max_initial, uint32_t* initial, 1808 bool* has_max, uint32_t max_maximum, 1809 uint32_t* maximum, uint8_t flags) { 1810 const byte* pos = pc(); 1811 // For memory64 we need to read the numbers as LEB-encoded 64-bit unsigned 1812 // integer. All V8 limits are still within uint32_t range though. 1813 const bool is_memory64 = 1814 flags == kMemory64NoMaximum || flags == kMemory64WithMaximum; 1815 uint64_t initial_64 = is_memory64 ? consume_u64v("initial size") 1816 : consume_u32v("initial size"); 1817 if (initial_64 > max_initial) { 1818 errorf(pos, 1819 "initial %s size (%" PRIu64 1820 " %s) is larger than implementation limit (%u)", 1821 name, initial_64, units, max_initial); 1822 } 1823 *initial = static_cast<uint32_t>(initial_64); 1824 if (flags & 1) { 1825 *has_max = true; 1826 pos = pc(); 1827 uint64_t maximum_64 = is_memory64 ? consume_u64v("maximum size") 1828 : consume_u32v("maximum size"); 1829 if (maximum_64 > max_maximum) { 1830 errorf(pos, 1831 "maximum %s size (%" PRIu64 1832 " %s) is larger than implementation limit (%u)", 1833 name, maximum_64, units, max_maximum); 1834 } 1835 if (maximum_64 < *initial) { 1836 errorf(pos, 1837 "maximum %s size (%" PRIu64 " %s) is less than initial (%u %s)", 1838 name, maximum_64, units, *initial, units); 1839 } 1840 *maximum = static_cast<uint32_t>(maximum_64); 1841 } else { 1842 *has_max = false; 1843 *maximum = max_initial; 1844 } 1845 } 1846 1847 // Consumes a byte, and emits an error if it does not equal {expected}. 1848 bool expect_u8(const char* name, uint8_t expected) { 1849 const byte* pos = pc(); 1850 uint8_t value = consume_u8(name); 1851 if (value != expected) { 1852 errorf(pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); 1853 return false; 1854 } 1855 return true; 1856 } 1857 1858 ConstantExpression consume_init_expr(WasmModule* module, ValueType expected) { 1859 uint32_t length; 1860 1861 // The error message mimics the one generated by the {WasmFullDecoder}. 1862#define TYPE_CHECK(found) \ 1863 if (V8_UNLIKELY(!IsSubtypeOf(found, expected, module_.get()))) { \ 1864 errorf(pc() + 1, \ 1865 "type error in init. expression[0] (expected %s, got %s)", \ 1866 expected.name().c_str(), found.name().c_str()); \ 1867 return {}; \ 1868 } 1869 1870 // To avoid initializing a {WasmFullDecoder} for the most common 1871 // expressions, we replicate their decoding and validation here. The 1872 // manually handled cases correspond to {ConstantExpression}'s kinds. 1873 // We need to make sure to check that the expression ends in {kExprEnd}; 1874 // otherwise, it is just the first operand of a composite expression, and we 1875 // fall back to the default case. 1876 if (!more()) { 1877 error("Beyond end of code"); 1878 return {}; 1879 } 1880 switch (static_cast<WasmOpcode>(*pc())) { 1881 case kExprI32Const: { 1882 int32_t value = 1883 read_i32v<kFullValidation>(pc() + 1, &length, "i32.const"); 1884 if (V8_UNLIKELY(failed())) return {}; 1885 if (V8_LIKELY(lookahead(1 + length, kExprEnd))) { 1886 TYPE_CHECK(kWasmI32) 1887 consume_bytes(length + 2); 1888 return ConstantExpression::I32Const(value); 1889 } 1890 break; 1891 } 1892 case kExprRefFunc: { 1893 uint32_t index = 1894 read_u32v<kFullValidation>(pc() + 1, &length, "ref.func"); 1895 if (V8_UNLIKELY(failed())) return {}; 1896 if (V8_LIKELY(lookahead(1 + length, kExprEnd))) { 1897 if (V8_UNLIKELY(index >= module_->functions.size())) { 1898 errorf(pc() + 1, "function index %u out of bounds", index); 1899 return {}; 1900 } 1901 ValueType type = 1902 enabled_features_.has_typed_funcref() 1903 ? ValueType::Ref(module_->functions[index].sig_index, 1904 kNonNullable) 1905 : kWasmFuncRef; 1906 TYPE_CHECK(type) 1907 module_->functions[index].declared = true; 1908 consume_bytes(length + 2); 1909 return ConstantExpression::RefFunc(index); 1910 } 1911 break; 1912 } 1913 case kExprRefNull: { 1914 HeapType type = value_type_reader::read_heap_type<kFullValidation>( 1915 this, pc() + 1, &length, module_.get(), enabled_features_); 1916 if (V8_UNLIKELY(failed())) return {}; 1917 if (V8_LIKELY(lookahead(1 + length, kExprEnd))) { 1918 TYPE_CHECK(ValueType::Ref(type, kNullable)) 1919 consume_bytes(length + 2); 1920 return ConstantExpression::RefNull(type.representation()); 1921 } 1922 break; 1923 } 1924 default: 1925 break; 1926 } 1927#undef TYPE_CHECK 1928 1929 auto sig = FixedSizeSignature<ValueType>::Returns(expected); 1930 FunctionBody body(&sig, buffer_offset_, pc_, end_); 1931 WasmFeatures detected; 1932 WasmFullDecoder<Decoder::kFullValidation, InitExprInterface, 1933 kInitExpression> 1934 decoder(&init_expr_zone_, module, enabled_features_, &detected, body, 1935 module); 1936 1937 uint32_t offset = this->pc_offset(); 1938 1939 decoder.DecodeFunctionBody(); 1940 1941 this->pc_ = decoder.end(); 1942 1943 if (decoder.failed()) { 1944 error(decoder.error().offset(), decoder.error().message().c_str()); 1945 return {}; 1946 } 1947 1948 if (!decoder.interface().end_found()) { 1949 error("Initializer expression is missing 'end'"); 1950 return {}; 1951 } 1952 1953 return ConstantExpression::WireBytes( 1954 offset, static_cast<uint32_t>(decoder.end() - decoder.start())); 1955 } 1956 1957 // Read a mutability flag 1958 bool consume_mutability() { 1959 byte val = consume_u8("mutability"); 1960 if (val > 1) error(pc_ - 1, "invalid mutability"); 1961 return val != 0; 1962 } 1963 1964 ValueType consume_value_type() { 1965 uint32_t type_length; 1966 ValueType result = value_type_reader::read_value_type<kFullValidation>( 1967 this, this->pc(), &type_length, module_.get(), 1968 origin_ == kWasmOrigin ? enabled_features_ : WasmFeatures::None()); 1969 consume_bytes(type_length, "value type"); 1970 return result; 1971 } 1972 1973 HeapType consume_super_type() { 1974 return value_type_reader::consume_heap_type(this, module_.get(), 1975 enabled_features_); 1976 } 1977 1978 ValueType consume_storage_type() { 1979 uint8_t opcode = read_u8<kFullValidation>(this->pc()); 1980 switch (opcode) { 1981 case kI8Code: 1982 consume_bytes(1, "i8"); 1983 return kWasmI8; 1984 case kI16Code: 1985 consume_bytes(1, "i16"); 1986 return kWasmI16; 1987 default: 1988 // It is not a packed type, so it has to be a value type. 1989 return consume_value_type(); 1990 } 1991 } 1992 1993 // Reads a reference type for tables and element segment headers. 1994 ValueType consume_reference_type() { 1995 const byte* position = pc(); 1996 ValueType result = consume_value_type(); 1997 if (!result.is_reference()) { 1998 error(position, "expected reference type"); 1999 } 2000 return result; 2001 } 2002 2003 const FunctionSig* consume_sig(Zone* zone) { 2004 // Parse parameter types. 2005 uint32_t param_count = 2006 consume_count("param count", kV8MaxWasmFunctionParams); 2007 if (failed()) return nullptr; 2008 std::vector<ValueType> params; 2009 for (uint32_t i = 0; ok() && i < param_count; ++i) { 2010 params.push_back(consume_value_type()); 2011 } 2012 std::vector<ValueType> returns; 2013 2014 // Parse return types. 2015 uint32_t return_count = 2016 consume_count("return count", kV8MaxWasmFunctionReturns); 2017 if (failed()) return nullptr; 2018 for (uint32_t i = 0; ok() && i < return_count; ++i) { 2019 returns.push_back(consume_value_type()); 2020 } 2021 if (failed()) return nullptr; 2022 2023 // FunctionSig stores the return types first. 2024 ValueType* buffer = zone->NewArray<ValueType>(param_count + return_count); 2025 uint32_t b = 0; 2026 for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i]; 2027 for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i]; 2028 2029 return zone->New<FunctionSig>(return_count, param_count, buffer); 2030 } 2031 2032 const StructType* consume_struct(Zone* zone) { 2033 uint32_t field_count = consume_count("field count", kV8MaxWasmStructFields); 2034 if (failed()) return nullptr; 2035 ValueType* fields = zone->NewArray<ValueType>(field_count); 2036 bool* mutabilities = zone->NewArray<bool>(field_count); 2037 for (uint32_t i = 0; ok() && i < field_count; ++i) { 2038 fields[i] = consume_storage_type(); 2039 mutabilities[i] = consume_mutability(); 2040 } 2041 if (failed()) return nullptr; 2042 uint32_t* offsets = zone->NewArray<uint32_t>(field_count); 2043 return zone->New<StructType>(field_count, offsets, fields, mutabilities); 2044 } 2045 2046 const ArrayType* consume_array(Zone* zone) { 2047 ValueType element_type = consume_storage_type(); 2048 bool mutability = consume_mutability(); 2049 if (failed()) return nullptr; 2050 return zone->New<ArrayType>(element_type, mutability); 2051 } 2052 2053 // Consume the attribute field of an exception. 2054 uint32_t consume_exception_attribute() { 2055 const byte* pos = pc_; 2056 uint32_t attribute = consume_u32v("exception attribute"); 2057 if (attribute != kExceptionAttribute) { 2058 errorf(pos, "exception attribute %u not supported", attribute); 2059 return 0; 2060 } 2061 return attribute; 2062 } 2063 2064 WasmElemSegment consume_element_segment_header() { 2065 const byte* pos = pc(); 2066 2067 // The mask for the bit in the flag which indicates if the segment is 2068 // active or not (0 is active). 2069 constexpr uint8_t kNonActiveMask = 1 << 0; 2070 // The mask for the bit in the flag which indicates: 2071 // - for active tables, if the segment has an explicit table index field. 2072 // - for non-active tables, whether the table is declarative (vs. passive). 2073 constexpr uint8_t kHasTableIndexOrIsDeclarativeMask = 1 << 1; 2074 // The mask for the bit in the flag which indicates if the functions of this 2075 // segment are defined as function indices (0) or init. expressions (1). 2076 constexpr uint8_t kExpressionsAsElementsMask = 1 << 2; 2077 constexpr uint8_t kFullMask = kNonActiveMask | 2078 kHasTableIndexOrIsDeclarativeMask | 2079 kExpressionsAsElementsMask; 2080 2081 uint32_t flag = consume_u32v("flag"); 2082 if ((flag & kFullMask) != flag) { 2083 errorf(pos, "illegal flag value %u. Must be between 0 and 7", flag); 2084 return {}; 2085 } 2086 2087 const WasmElemSegment::Status status = 2088 (flag & kNonActiveMask) ? (flag & kHasTableIndexOrIsDeclarativeMask) 2089 ? WasmElemSegment::kStatusDeclarative 2090 : WasmElemSegment::kStatusPassive 2091 : WasmElemSegment::kStatusActive; 2092 const bool is_active = status == WasmElemSegment::kStatusActive; 2093 2094 WasmElemSegment::ElementType element_type = 2095 flag & kExpressionsAsElementsMask 2096 ? WasmElemSegment::kExpressionElements 2097 : WasmElemSegment::kFunctionIndexElements; 2098 2099 const bool has_table_index = 2100 is_active && (flag & kHasTableIndexOrIsDeclarativeMask); 2101 uint32_t table_index = has_table_index ? consume_u32v("table index") : 0; 2102 if (is_active && table_index >= module_->tables.size()) { 2103 errorf(pos, "out of bounds%s table index %u", 2104 has_table_index ? " implicit" : "", table_index); 2105 return {}; 2106 } 2107 ValueType table_type = 2108 is_active ? module_->tables[table_index].type : kWasmBottom; 2109 2110 ConstantExpression offset; 2111 if (is_active) { 2112 offset = consume_init_expr(module_.get(), kWasmI32); 2113 // Failed to parse offset initializer, return early. 2114 if (failed()) return {}; 2115 } 2116 2117 // Denotes an active segment without table index, type, or element kind. 2118 const bool backwards_compatible_mode = 2119 is_active && !(flag & kHasTableIndexOrIsDeclarativeMask); 2120 ValueType type; 2121 if (element_type == WasmElemSegment::kExpressionElements) { 2122 type = 2123 backwards_compatible_mode ? kWasmFuncRef : consume_reference_type(); 2124 if (is_active && !IsSubtypeOf(type, table_type, this->module_.get())) { 2125 errorf(pos, 2126 "Element segment of type %s is not a subtype of referenced " 2127 "table %u (of type %s)", 2128 type.name().c_str(), table_index, table_type.name().c_str()); 2129 return {}; 2130 } 2131 } else { 2132 if (!backwards_compatible_mode) { 2133 // We have to check that there is an element kind of type Function. All 2134 // other element kinds are not valid yet. 2135 uint8_t val = consume_u8("element kind"); 2136 if (static_cast<ImportExportKindCode>(val) != kExternalFunction) { 2137 errorf(pos, "illegal element kind 0x%x. Must be 0x%x", val, 2138 kExternalFunction); 2139 return {}; 2140 } 2141 } 2142 if (!is_active) { 2143 // Declarative and passive segments without explicit type are funcref. 2144 type = kWasmFuncRef; 2145 } else { 2146 type = table_type; 2147 // Active segments with function indices must reference a function 2148 // table. TODO(7748): Add support for anyref tables when we have them. 2149 if (!IsSubtypeOf(table_type, kWasmFuncRef, this->module_.get())) { 2150 errorf(pos, 2151 "An active element segment with function indices as elements " 2152 "must reference a table of %s. Instead, table %u of type %s " 2153 "is referenced.", 2154 enabled_features_.has_typed_funcref() 2155 ? "a subtype of type funcref" 2156 : "type funcref", 2157 table_index, table_type.name().c_str()); 2158 return {}; 2159 } 2160 } 2161 } 2162 2163 if (is_active) { 2164 return {type, table_index, std::move(offset), element_type}; 2165 } else { 2166 return {type, status, element_type}; 2167 } 2168 } 2169 2170 void consume_data_segment_header(bool* is_active, uint32_t* index, 2171 ConstantExpression* offset) { 2172 const byte* pos = pc(); 2173 uint32_t flag = consume_u32v("flag"); 2174 2175 // Some flag values are only valid for specific proposals. 2176 if (flag != SegmentFlags::kActiveNoIndex && 2177 flag != SegmentFlags::kPassive && 2178 flag != SegmentFlags::kActiveWithIndex) { 2179 errorf(pos, "illegal flag value %u. Must be 0, 1, or 2", flag); 2180 return; 2181 } 2182 2183 // We know now that the flag is valid. Time to read the rest. 2184 ValueType expected_type = module_->is_memory64 ? kWasmI64 : kWasmI32; 2185 if (flag == SegmentFlags::kActiveNoIndex) { 2186 *is_active = true; 2187 *index = 0; 2188 *offset = consume_init_expr(module_.get(), expected_type); 2189 return; 2190 } 2191 if (flag == SegmentFlags::kPassive) { 2192 *is_active = false; 2193 return; 2194 } 2195 if (flag == SegmentFlags::kActiveWithIndex) { 2196 *is_active = true; 2197 *index = consume_u32v("memory index"); 2198 *offset = consume_init_expr(module_.get(), expected_type); 2199 } 2200 } 2201 2202 uint32_t consume_element_func_index(ValueType expected) { 2203 WasmFunction* func = nullptr; 2204 const byte* initial_pc = pc(); 2205 uint32_t index = 2206 consume_func_index(module_.get(), &func, "element function index"); 2207 if (failed()) return index; 2208 DCHECK_NOT_NULL(func); 2209 DCHECK_EQ(index, func->func_index); 2210 ValueType entry_type = ValueType::Ref(func->sig_index, kNonNullable); 2211 if (V8_UNLIKELY(!IsSubtypeOf(entry_type, expected, module_.get()))) { 2212 errorf(initial_pc, 2213 "Invalid type in element entry: expected %s, got %s instead.", 2214 expected.name().c_str(), entry_type.name().c_str()); 2215 return index; 2216 } 2217 func->declared = true; 2218 return index; 2219 } 2220}; 2221 2222ModuleResult DecodeWasmModule( 2223 const WasmFeatures& enabled, const byte* module_start, 2224 const byte* module_end, bool verify_functions, ModuleOrigin origin, 2225 Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder, 2226 v8::metrics::Recorder::ContextId context_id, DecodingMethod decoding_method, 2227 AccountingAllocator* allocator) { 2228 size_t size = module_end - module_start; 2229 CHECK_LE(module_start, module_end); 2230 size_t max_size = max_module_size(); 2231 if (size > max_size) { 2232 return ModuleResult{ 2233 WasmError{0, "size > maximum module size (%zu): %zu", max_size, size}}; 2234 } 2235 // TODO(bradnelson): Improve histogram handling of size_t. 2236 auto size_counter = 2237 SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes); 2238 size_counter->AddSample(static_cast<int>(size)); 2239 // Signatures are stored in zone memory, which have the same lifetime 2240 // as the {module}. 2241 ModuleDecoderImpl decoder(enabled, module_start, module_end, origin); 2242 v8::metrics::WasmModuleDecoded metrics_event; 2243 base::ElapsedTimer timer; 2244 timer.Start(); 2245 base::ThreadTicks thread_ticks = base::ThreadTicks::IsSupported() 2246 ? base::ThreadTicks::Now() 2247 : base::ThreadTicks(); 2248 ModuleResult result = 2249 decoder.DecodeModule(counters, allocator, verify_functions); 2250 2251 // Record event metrics. 2252 metrics_event.wall_clock_duration_in_us = timer.Elapsed().InMicroseconds(); 2253 timer.Stop(); 2254 if (!thread_ticks.IsNull()) { 2255 metrics_event.cpu_duration_in_us = 2256 (base::ThreadTicks::Now() - thread_ticks).InMicroseconds(); 2257 } 2258 metrics_event.success = decoder.ok() && result.ok(); 2259 metrics_event.async = decoding_method == DecodingMethod::kAsync || 2260 decoding_method == DecodingMethod::kAsyncStream; 2261 metrics_event.streamed = decoding_method == DecodingMethod::kSyncStream || 2262 decoding_method == DecodingMethod::kAsyncStream; 2263 if (result.ok()) { 2264 metrics_event.function_count = result.value()->num_declared_functions; 2265 } else if (auto&& module = decoder.shared_module()) { 2266 metrics_event.function_count = module->num_declared_functions; 2267 } 2268 metrics_event.module_size_in_bytes = size; 2269 metrics_recorder->DelayMainThreadEvent(metrics_event, context_id); 2270 2271 return result; 2272} 2273 2274ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled) 2275 : enabled_features_(enabled) {} 2276 2277ModuleDecoder::~ModuleDecoder() = default; 2278 2279const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const { 2280 return impl_->shared_module(); 2281} 2282 2283void ModuleDecoder::StartDecoding( 2284 Counters* counters, std::shared_ptr<metrics::Recorder> metrics_recorder, 2285 v8::metrics::Recorder::ContextId context_id, AccountingAllocator* allocator, 2286 ModuleOrigin origin) { 2287 DCHECK_NULL(impl_); 2288 impl_.reset(new ModuleDecoderImpl(enabled_features_, origin)); 2289 impl_->StartDecoding(counters, allocator); 2290} 2291 2292void ModuleDecoder::DecodeModuleHeader(base::Vector<const uint8_t> bytes, 2293 uint32_t offset) { 2294 impl_->DecodeModuleHeader(bytes, offset); 2295} 2296 2297void ModuleDecoder::DecodeSection(SectionCode section_code, 2298 base::Vector<const uint8_t> bytes, 2299 uint32_t offset, bool verify_functions) { 2300 impl_->DecodeSection(section_code, bytes, offset, verify_functions); 2301} 2302 2303void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length, 2304 uint32_t offset, bool verify_functions) { 2305 impl_->DecodeFunctionBody(index, length, offset, verify_functions); 2306} 2307 2308void ModuleDecoder::StartCodeSection() { impl_->StartCodeSection(); } 2309 2310bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count, 2311 uint32_t error_offset) { 2312 return impl_->CheckFunctionsCount(functions_count, error_offset); 2313} 2314 2315ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) { 2316 return impl_->FinishDecoding(verify_functions); 2317} 2318 2319void ModuleDecoder::set_code_section(uint32_t offset, uint32_t size) { 2320 return impl_->set_code_section(offset, size); 2321} 2322 2323size_t ModuleDecoder::IdentifyUnknownSection(ModuleDecoder* decoder, 2324 base::Vector<const uint8_t> bytes, 2325 uint32_t offset, 2326 SectionCode* result) { 2327 if (!decoder->ok()) return 0; 2328 decoder->impl_->Reset(bytes, offset); 2329 *result = IdentifyUnknownSectionInternal(decoder->impl_.get()); 2330 return decoder->impl_->pc() - bytes.begin(); 2331} 2332 2333bool ModuleDecoder::ok() { return impl_->ok(); } 2334 2335const FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled, 2336 Zone* zone, const byte* start, 2337 const byte* end) { 2338 ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin); 2339 return decoder.DecodeFunctionSignature(zone, start); 2340} 2341 2342ConstantExpression DecodeWasmInitExprForTesting(const WasmFeatures& enabled, 2343 const byte* start, 2344 const byte* end, 2345 ValueType expected) { 2346 ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin); 2347 AccountingAllocator allocator; 2348 decoder.StartDecoding(nullptr, &allocator); 2349 return decoder.DecodeInitExprForTesting(expected); 2350} 2351 2352FunctionResult DecodeWasmFunctionForTesting( 2353 const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes, 2354 const WasmModule* module, const byte* function_start, 2355 const byte* function_end, Counters* counters) { 2356 size_t size = function_end - function_start; 2357 CHECK_LE(function_start, function_end); 2358 if (size > kV8MaxWasmFunctionSize) { 2359 return FunctionResult{WasmError{0, 2360 "size > maximum function size (%zu): %zu", 2361 kV8MaxWasmFunctionSize, size}}; 2362 } 2363 ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin); 2364 decoder.SetCounters(counters); 2365 return decoder.DecodeSingleFunction(zone, wire_bytes, module, 2366 std::make_unique<WasmFunction>()); 2367} 2368 2369AsmJsOffsetsResult DecodeAsmJsOffsets( 2370 base::Vector<const uint8_t> encoded_offsets) { 2371 std::vector<AsmJsOffsetFunctionEntries> functions; 2372 2373 Decoder decoder(encoded_offsets); 2374 uint32_t functions_count = decoder.consume_u32v("functions count"); 2375 // Consistency check. 2376 DCHECK_GE(encoded_offsets.size(), functions_count); 2377 functions.reserve(functions_count); 2378 2379 for (uint32_t i = 0; i < functions_count; ++i) { 2380 uint32_t size = decoder.consume_u32v("table size"); 2381 if (size == 0) { 2382 functions.emplace_back(); 2383 continue; 2384 } 2385 DCHECK(decoder.checkAvailable(size)); 2386 const byte* table_end = decoder.pc() + size; 2387 uint32_t locals_size = decoder.consume_u32v("locals size"); 2388 int function_start_position = decoder.consume_u32v("function start pos"); 2389 int function_end_position = function_start_position; 2390 int last_byte_offset = locals_size; 2391 int last_asm_position = function_start_position; 2392 std::vector<AsmJsOffsetEntry> func_asm_offsets; 2393 func_asm_offsets.reserve(size / 4); // conservative estimation 2394 // Add an entry for the stack check, associated with position 0. 2395 func_asm_offsets.push_back( 2396 {0, function_start_position, function_start_position}); 2397 while (decoder.pc() < table_end) { 2398 DCHECK(decoder.ok()); 2399 last_byte_offset += decoder.consume_u32v("byte offset delta"); 2400 int call_position = 2401 last_asm_position + decoder.consume_i32v("call position delta"); 2402 int to_number_position = 2403 call_position + decoder.consume_i32v("to_number position delta"); 2404 last_asm_position = to_number_position; 2405 if (decoder.pc() == table_end) { 2406 // The last entry is the function end marker. 2407 DCHECK_EQ(call_position, to_number_position); 2408 function_end_position = call_position; 2409 } else { 2410 func_asm_offsets.push_back( 2411 {last_byte_offset, call_position, to_number_position}); 2412 } 2413 } 2414 DCHECK_EQ(decoder.pc(), table_end); 2415 functions.emplace_back(AsmJsOffsetFunctionEntries{ 2416 function_start_position, function_end_position, 2417 std::move(func_asm_offsets)}); 2418 } 2419 DCHECK(decoder.ok()); 2420 DCHECK(!decoder.more()); 2421 2422 return decoder.toResult(AsmJsOffsets{std::move(functions)}); 2423} 2424 2425std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start, 2426 const byte* end) { 2427 Decoder decoder(start, end); 2428 decoder.consume_bytes(4, "wasm magic"); 2429 decoder.consume_bytes(4, "wasm version"); 2430 2431 std::vector<CustomSectionOffset> result; 2432 2433 while (decoder.more()) { 2434 byte section_code = decoder.consume_u8("section code"); 2435 uint32_t section_length = decoder.consume_u32v("section length"); 2436 uint32_t section_start = decoder.pc_offset(); 2437 if (section_code != 0) { 2438 // Skip known sections. 2439 decoder.consume_bytes(section_length, "section bytes"); 2440 continue; 2441 } 2442 uint32_t name_length = decoder.consume_u32v("name length"); 2443 uint32_t name_offset = decoder.pc_offset(); 2444 decoder.consume_bytes(name_length, "section name"); 2445 uint32_t payload_offset = decoder.pc_offset(); 2446 if (section_length < (payload_offset - section_start)) { 2447 decoder.error("invalid section length"); 2448 break; 2449 } 2450 uint32_t payload_length = section_length - (payload_offset - section_start); 2451 decoder.consume_bytes(payload_length); 2452 if (decoder.failed()) break; 2453 result.push_back({{section_start, section_length}, 2454 {name_offset, name_length}, 2455 {payload_offset, payload_length}}); 2456 } 2457 2458 return result; 2459} 2460 2461namespace { 2462 2463bool FindNameSection(Decoder* decoder) { 2464 static constexpr int kModuleHeaderSize = 8; 2465 decoder->consume_bytes(kModuleHeaderSize, "module header"); 2466 2467 WasmSectionIterator section_iter(decoder); 2468 2469 while (decoder->ok() && section_iter.more() && 2470 section_iter.section_code() != kNameSectionCode) { 2471 section_iter.advance(true); 2472 } 2473 if (!section_iter.more()) return false; 2474 2475 // Reset the decoder to not read beyond the name section end. 2476 decoder->Reset(section_iter.payload(), decoder->pc_offset()); 2477 return true; 2478} 2479 2480} // namespace 2481 2482void DecodeFunctionNames(const byte* module_start, const byte* module_end, 2483 std::unordered_map<uint32_t, WireBytesRef>* names) { 2484 DCHECK_NOT_NULL(names); 2485 DCHECK(names->empty()); 2486 2487 Decoder decoder(module_start, module_end); 2488 if (FindNameSection(&decoder)) { 2489 while (decoder.ok() && decoder.more()) { 2490 uint8_t name_type = decoder.consume_u8("name type"); 2491 if (name_type & 0x80) break; // no varuint7 2492 2493 uint32_t name_payload_len = decoder.consume_u32v("name payload length"); 2494 if (!decoder.checkAvailable(name_payload_len)) break; 2495 2496 if (name_type != NameSectionKindCode::kFunctionCode) { 2497 decoder.consume_bytes(name_payload_len, "name subsection payload"); 2498 continue; 2499 } 2500 uint32_t functions_count = decoder.consume_u32v("functions count"); 2501 2502 for (; decoder.ok() && functions_count > 0; --functions_count) { 2503 uint32_t function_index = decoder.consume_u32v("function index"); 2504 WireBytesRef name = consume_string(&decoder, false, "function name"); 2505 2506 // Be lenient with errors in the name section: Ignore non-UTF8 names. 2507 // You can even assign to the same function multiple times (last valid 2508 // one wins). 2509 if (decoder.ok() && validate_utf8(&decoder, name)) { 2510 names->insert(std::make_pair(function_index, name)); 2511 } 2512 } 2513 } 2514 } 2515} 2516 2517NameMap DecodeNameMap(base::Vector<const uint8_t> module_bytes, 2518 uint8_t name_section_kind) { 2519 Decoder decoder(module_bytes); 2520 if (!FindNameSection(&decoder)) return NameMap{{}}; 2521 2522 std::vector<NameAssoc> names; 2523 while (decoder.ok() && decoder.more()) { 2524 uint8_t name_type = decoder.consume_u8("name type"); 2525 if (name_type & 0x80) break; // no varuint7 2526 2527 uint32_t name_payload_len = decoder.consume_u32v("name payload length"); 2528 if (!decoder.checkAvailable(name_payload_len)) break; 2529 2530 if (name_type != name_section_kind) { 2531 decoder.consume_bytes(name_payload_len, "name subsection payload"); 2532 continue; 2533 } 2534 2535 uint32_t count = decoder.consume_u32v("names count"); 2536 for (uint32_t i = 0; i < count; i++) { 2537 uint32_t index = decoder.consume_u32v("index"); 2538 WireBytesRef name = consume_string(&decoder, false, "name"); 2539 if (!decoder.ok()) break; 2540 if (index > kMaxInt) continue; 2541 if (!validate_utf8(&decoder, name)) continue; 2542 names.emplace_back(static_cast<int>(index), name); 2543 } 2544 } 2545 std::stable_sort(names.begin(), names.end(), NameAssoc::IndexLess{}); 2546 return NameMap{std::move(names)}; 2547} 2548 2549IndirectNameMap DecodeIndirectNameMap(base::Vector<const uint8_t> module_bytes, 2550 uint8_t name_section_kind) { 2551 Decoder decoder(module_bytes); 2552 if (!FindNameSection(&decoder)) return IndirectNameMap{{}}; 2553 2554 std::vector<IndirectNameMapEntry> entries; 2555 while (decoder.ok() && decoder.more()) { 2556 uint8_t name_type = decoder.consume_u8("name type"); 2557 if (name_type & 0x80) break; // no varuint7 2558 2559 uint32_t name_payload_len = decoder.consume_u32v("name payload length"); 2560 if (!decoder.checkAvailable(name_payload_len)) break; 2561 2562 if (name_type != name_section_kind) { 2563 decoder.consume_bytes(name_payload_len, "name subsection payload"); 2564 continue; 2565 } 2566 2567 uint32_t outer_count = decoder.consume_u32v("outer count"); 2568 for (uint32_t i = 0; i < outer_count; ++i) { 2569 uint32_t outer_index = decoder.consume_u32v("outer index"); 2570 if (outer_index > kMaxInt) continue; 2571 std::vector<NameAssoc> names; 2572 uint32_t inner_count = decoder.consume_u32v("inner count"); 2573 for (uint32_t k = 0; k < inner_count; ++k) { 2574 uint32_t inner_index = decoder.consume_u32v("inner index"); 2575 WireBytesRef name = consume_string(&decoder, false, "name"); 2576 if (!decoder.ok()) break; 2577 if (inner_index > kMaxInt) continue; 2578 // Ignore non-utf8 names. 2579 if (!validate_utf8(&decoder, name)) continue; 2580 names.emplace_back(static_cast<int>(inner_index), name); 2581 } 2582 // Use stable sort to get deterministic names (the first one declared) 2583 // even in the presence of duplicates. 2584 std::stable_sort(names.begin(), names.end(), NameAssoc::IndexLess{}); 2585 entries.emplace_back(static_cast<int>(outer_index), std::move(names)); 2586 } 2587 } 2588 std::stable_sort(entries.begin(), entries.end(), 2589 IndirectNameMapEntry::IndexLess{}); 2590 return IndirectNameMap{std::move(entries)}; 2591} 2592 2593#undef TRACE 2594 2595} // namespace wasm 2596} // namespace internal 2597} // namespace v8 2598