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 #include "src/wasm/function-body-decoder-impl.h" 7 8 #include "src/base/functional.h" 9 #include "src/base/platform/platform.h" 10 #include "src/counters.h" 11 #include "src/flags.h" 12 #include "src/macro-assembler.h" 13 #include "src/objects-inl.h" 14 #include "src/ostreams.h" 15 #include "src/v8.h" 16 17 #include "src/wasm/decoder.h" 18 #include "src/wasm/wasm-limits.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace wasm { 23 24 #if DEBUG 25 #define TRACE(...) \ 26 do { \ 27 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 28 } while (false) 29 #else 30 #define TRACE(...) 31 #endif 32 33 const char* SectionName(WasmSectionCode code) { 34 switch (code) { 35 case kUnknownSectionCode: 36 return "Unknown"; 37 case kTypeSectionCode: 38 return "Type"; 39 case kImportSectionCode: 40 return "Import"; 41 case kFunctionSectionCode: 42 return "Function"; 43 case kTableSectionCode: 44 return "Table"; 45 case kMemorySectionCode: 46 return "Memory"; 47 case kGlobalSectionCode: 48 return "Global"; 49 case kExportSectionCode: 50 return "Export"; 51 case kStartSectionCode: 52 return "Start"; 53 case kCodeSectionCode: 54 return "Code"; 55 case kElementSectionCode: 56 return "Element"; 57 case kDataSectionCode: 58 return "Data"; 59 case kNameSectionCode: 60 return "Name"; 61 default: 62 return "<unknown>"; 63 } 64 } 65 66 namespace { 67 68 const char* kNameString = "name"; 69 const size_t kNameStringLength = 4; 70 71 ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) { 72 switch (expr.kind) { 73 case WasmInitExpr::kNone: 74 return kWasmStmt; 75 case WasmInitExpr::kGlobalIndex: 76 return expr.val.global_index < module->globals.size() 77 ? module->globals[expr.val.global_index].type 78 : kWasmStmt; 79 case WasmInitExpr::kI32Const: 80 return kWasmI32; 81 case WasmInitExpr::kI64Const: 82 return kWasmI64; 83 case WasmInitExpr::kF32Const: 84 return kWasmF32; 85 case WasmInitExpr::kF64Const: 86 return kWasmF64; 87 default: 88 UNREACHABLE(); 89 return kWasmStmt; 90 } 91 } 92 93 // An iterator over the sections in a WASM binary module. 94 // Automatically skips all unknown sections. 95 class WasmSectionIterator { 96 public: 97 explicit WasmSectionIterator(Decoder& decoder) 98 : decoder_(decoder), 99 section_code_(kUnknownSectionCode), 100 section_start_(decoder.pc()), 101 section_end_(decoder.pc()) { 102 next(); 103 } 104 105 inline bool more() const { 106 return section_code_ != kUnknownSectionCode && decoder_.more(); 107 } 108 109 inline WasmSectionCode section_code() const { return section_code_; } 110 111 inline const byte* section_start() const { return section_start_; } 112 113 inline uint32_t section_length() const { 114 return static_cast<uint32_t>(section_end_ - section_start_); 115 } 116 117 inline const byte* payload_start() const { return payload_start_; } 118 119 inline uint32_t payload_length() const { 120 return static_cast<uint32_t>(section_end_ - payload_start_); 121 } 122 123 inline const byte* section_end() const { return section_end_; } 124 125 // Advances to the next section, checking that decoding the current section 126 // stopped at {section_end_}. 127 void advance() { 128 if (decoder_.pc() != section_end_) { 129 const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer"; 130 decoder_.error(decoder_.pc(), decoder_.pc(), 131 "section was %s than expected size " 132 "(%u bytes expected, %zu decoded)", 133 msg, section_length(), 134 static_cast<size_t>(decoder_.pc() - section_start_)); 135 } 136 next(); 137 } 138 139 private: 140 Decoder& decoder_; 141 WasmSectionCode section_code_; 142 const byte* section_start_; 143 const byte* payload_start_; 144 const byte* section_end_; 145 146 // Reads the section code/name at the current position and sets up 147 // the internal fields. 148 void next() { 149 while (true) { 150 if (!decoder_.more()) { 151 section_code_ = kUnknownSectionCode; 152 return; 153 } 154 uint8_t section_code = decoder_.consume_u8("section code"); 155 // Read and check the section size. 156 uint32_t section_length = decoder_.consume_u32v("section length"); 157 section_start_ = decoder_.pc(); 158 payload_start_ = section_start_; 159 if (decoder_.checkAvailable(section_length)) { 160 // Get the limit of the section within the module. 161 section_end_ = section_start_ + section_length; 162 } else { 163 // The section would extend beyond the end of the module. 164 section_end_ = section_start_; 165 } 166 167 if (section_code == kUnknownSectionCode) { 168 // Check for the known "name" section. 169 uint32_t string_length = decoder_.consume_u32v("section name length"); 170 const byte* section_name_start = decoder_.pc(); 171 decoder_.consume_bytes(string_length, "section name"); 172 if (decoder_.failed() || decoder_.pc() > section_end_) { 173 TRACE("Section name of length %u couldn't be read\n", string_length); 174 section_code_ = kUnknownSectionCode; 175 return; 176 } 177 payload_start_ = decoder_.pc(); 178 179 TRACE(" +%d section name : \"%.*s\"\n", 180 static_cast<int>(section_name_start - decoder_.start()), 181 string_length < 20 ? string_length : 20, section_name_start); 182 183 if (string_length == kNameStringLength && 184 strncmp(reinterpret_cast<const char*>(section_name_start), 185 kNameString, kNameStringLength) == 0) { 186 section_code = kNameSectionCode; 187 } else { 188 section_code = kUnknownSectionCode; 189 } 190 } else if (!IsValidSectionCode(section_code)) { 191 decoder_.error(decoder_.pc(), decoder_.pc(), 192 "unknown section code #0x%02x", section_code); 193 section_code = kUnknownSectionCode; 194 } 195 section_code_ = static_cast<WasmSectionCode>(section_code); 196 197 TRACE("Section: %s\n", SectionName(section_code_)); 198 if (section_code_ == kUnknownSectionCode && 199 section_end_ > decoder_.pc()) { 200 // skip to the end of the unknown section. 201 uint32_t remaining = 202 static_cast<uint32_t>(section_end_ - decoder_.pc()); 203 decoder_.consume_bytes(remaining, "section payload"); 204 // fall through and continue to the next section. 205 } else { 206 return; 207 } 208 } 209 } 210 }; 211 212 // The main logic for decoding the bytes of a module. 213 class ModuleDecoder : public Decoder { 214 public: 215 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end, 216 ModuleOrigin origin) 217 : Decoder(module_start, module_end), 218 module_zone(zone), 219 origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) { 220 result_.start = start_; 221 if (end_ < start_) { 222 error(start_, "end is less than start"); 223 end_ = start_; 224 } 225 } 226 227 virtual void onFirstError() { 228 pc_ = end_; // On error, terminate section decoding loop. 229 } 230 231 void DumpModule(const ModuleResult& result) { 232 std::string path; 233 if (FLAG_dump_wasm_module_path) { 234 path = FLAG_dump_wasm_module_path; 235 if (path.size() && 236 !base::OS::isDirectorySeparator(path[path.size() - 1])) { 237 path += base::OS::DirectorySeparator(); 238 } 239 } 240 // File are named `HASH.{ok,failed}.wasm`. 241 size_t hash = base::hash_range(start_, end_); 242 char buf[32] = {'\0'}; 243 #if V8_OS_WIN && _MSC_VER < 1900 244 #define snprintf sprintf_s 245 #endif 246 snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash, 247 result.ok() ? "ok" : "failed"); 248 std::string name(buf); 249 if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) { 250 fwrite(start_, end_ - start_, 1, wasm_file); 251 fclose(wasm_file); 252 } 253 } 254 255 // Decodes an entire module. 256 ModuleResult DecodeModule(bool verify_functions = true) { 257 pc_ = start_; 258 WasmModule* module = new WasmModule(module_zone); 259 module->min_mem_pages = 0; 260 module->max_mem_pages = 0; 261 module->mem_export = false; 262 module->origin = origin_; 263 264 const byte* pos = pc_; 265 uint32_t magic_word = consume_u32("wasm magic"); 266 #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff 267 if (magic_word != kWasmMagic) { 268 error(pos, pos, 269 "expected magic word %02x %02x %02x %02x, " 270 "found %02x %02x %02x %02x", 271 BYTES(kWasmMagic), BYTES(magic_word)); 272 } 273 274 pos = pc_; 275 { 276 uint32_t magic_version = consume_u32("wasm version"); 277 if (magic_version != kWasmVersion) { 278 error(pos, pos, 279 "expected version %02x %02x %02x %02x, " 280 "found %02x %02x %02x %02x", 281 BYTES(kWasmVersion), BYTES(magic_version)); 282 } 283 } 284 285 WasmSectionIterator section_iter(*this); 286 287 // ===== Type section ==================================================== 288 if (section_iter.section_code() == kTypeSectionCode) { 289 uint32_t signatures_count = consume_count("types count", kV8MaxWasmTypes); 290 module->signatures.reserve(signatures_count); 291 for (uint32_t i = 0; ok() && i < signatures_count; ++i) { 292 TRACE("DecodeSignature[%d] module+%d\n", i, 293 static_cast<int>(pc_ - start_)); 294 FunctionSig* s = consume_sig(); 295 module->signatures.push_back(s); 296 } 297 section_iter.advance(); 298 } 299 300 // ===== Import section ================================================== 301 if (section_iter.section_code() == kImportSectionCode) { 302 uint32_t import_table_count = 303 consume_count("imports count", kV8MaxWasmImports); 304 module->import_table.reserve(import_table_count); 305 for (uint32_t i = 0; ok() && i < import_table_count; ++i) { 306 TRACE("DecodeImportTable[%d] module+%d\n", i, 307 static_cast<int>(pc_ - start_)); 308 309 module->import_table.push_back({ 310 0, // module_name_length 311 0, // module_name_offset 312 0, // field_name_offset 313 0, // field_name_length 314 kExternalFunction, // kind 315 0 // index 316 }); 317 WasmImport* import = &module->import_table.back(); 318 const byte* pos = pc_; 319 import->module_name_offset = 320 consume_string(&import->module_name_length, true); 321 import->field_name_offset = 322 consume_string(&import->field_name_length, true); 323 324 import->kind = static_cast<WasmExternalKind>(consume_u8("import kind")); 325 switch (import->kind) { 326 case kExternalFunction: { 327 // ===== Imported function ======================================= 328 import->index = static_cast<uint32_t>(module->functions.size()); 329 module->num_imported_functions++; 330 module->functions.push_back({nullptr, // sig 331 import->index, // func_index 332 0, // sig_index 333 0, // name_offset 334 0, // name_length 335 0, // code_start_offset 336 0, // code_end_offset 337 true, // imported 338 false}); // exported 339 WasmFunction* function = &module->functions.back(); 340 function->sig_index = consume_sig_index(module, &function->sig); 341 break; 342 } 343 case kExternalTable: { 344 // ===== Imported table ========================================== 345 if (!AddTable(module)) break; 346 import->index = 347 static_cast<uint32_t>(module->function_tables.size()); 348 module->function_tables.push_back({0, 0, false, 349 std::vector<int32_t>(), true, 350 false, SignatureMap()}); 351 expect_u8("element type", kWasmAnyFunctionTypeForm); 352 WasmIndirectFunctionTable* table = &module->function_tables.back(); 353 consume_resizable_limits("element count", "elements", 354 FLAG_wasm_max_table_size, &table->min_size, 355 &table->has_max, FLAG_wasm_max_table_size, 356 &table->max_size); 357 break; 358 } 359 case kExternalMemory: { 360 // ===== Imported memory ========================================= 361 if (!AddMemory(module)) break; 362 consume_resizable_limits( 363 "memory", "pages", FLAG_wasm_max_mem_pages, 364 &module->min_mem_pages, &module->has_max_mem, 365 kSpecMaxWasmMemoryPages, &module->max_mem_pages); 366 break; 367 } 368 case kExternalGlobal: { 369 // ===== Imported global ========================================= 370 import->index = static_cast<uint32_t>(module->globals.size()); 371 module->globals.push_back( 372 {kWasmStmt, false, WasmInitExpr(), 0, true, false}); 373 WasmGlobal* global = &module->globals.back(); 374 global->type = consume_value_type(); 375 global->mutability = consume_mutability(); 376 if (global->mutability) { 377 error("mutable globals cannot be imported"); 378 } 379 break; 380 } 381 default: 382 error(pos, pos, "unknown import kind 0x%02x", import->kind); 383 break; 384 } 385 } 386 section_iter.advance(); 387 } 388 389 // ===== Function section ================================================ 390 if (section_iter.section_code() == kFunctionSectionCode) { 391 uint32_t functions_count = 392 consume_count("functions count", kV8MaxWasmFunctions); 393 module->functions.reserve(functions_count); 394 module->num_declared_functions = functions_count; 395 for (uint32_t i = 0; ok() && i < functions_count; ++i) { 396 uint32_t func_index = static_cast<uint32_t>(module->functions.size()); 397 module->functions.push_back({nullptr, // sig 398 func_index, // func_index 399 0, // sig_index 400 0, // name_offset 401 0, // name_length 402 0, // code_start_offset 403 0, // code_end_offset 404 false, // imported 405 false}); // exported 406 WasmFunction* function = &module->functions.back(); 407 function->sig_index = consume_sig_index(module, &function->sig); 408 } 409 section_iter.advance(); 410 } 411 412 // ===== Table section =================================================== 413 if (section_iter.section_code() == kTableSectionCode) { 414 uint32_t table_count = consume_count("table count", kV8MaxWasmTables); 415 416 for (uint32_t i = 0; ok() && i < table_count; i++) { 417 if (!AddTable(module)) break; 418 module->function_tables.push_back({0, 0, false, std::vector<int32_t>(), 419 false, false, SignatureMap()}); 420 WasmIndirectFunctionTable* table = &module->function_tables.back(); 421 expect_u8("table type", kWasmAnyFunctionTypeForm); 422 consume_resizable_limits("table elements", "elements", 423 FLAG_wasm_max_table_size, &table->min_size, 424 &table->has_max, FLAG_wasm_max_table_size, 425 &table->max_size); 426 } 427 section_iter.advance(); 428 } 429 430 // ===== Memory section ================================================== 431 if (section_iter.section_code() == kMemorySectionCode) { 432 uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories); 433 434 for (uint32_t i = 0; ok() && i < memory_count; i++) { 435 if (!AddMemory(module)) break; 436 consume_resizable_limits("memory", "pages", FLAG_wasm_max_mem_pages, 437 &module->min_mem_pages, &module->has_max_mem, 438 kSpecMaxWasmMemoryPages, 439 &module->max_mem_pages); 440 } 441 section_iter.advance(); 442 } 443 444 // ===== Global section ================================================== 445 if (section_iter.section_code() == kGlobalSectionCode) { 446 uint32_t globals_count = 447 consume_count("globals count", kV8MaxWasmGlobals); 448 uint32_t imported_globals = static_cast<uint32_t>(module->globals.size()); 449 module->globals.reserve(imported_globals + globals_count); 450 for (uint32_t i = 0; ok() && i < globals_count; ++i) { 451 TRACE("DecodeGlobal[%d] module+%d\n", i, 452 static_cast<int>(pc_ - start_)); 453 // Add an uninitialized global and pass a pointer to it. 454 module->globals.push_back( 455 {kWasmStmt, false, WasmInitExpr(), 0, false, false}); 456 WasmGlobal* global = &module->globals.back(); 457 DecodeGlobalInModule(module, i + imported_globals, global); 458 } 459 section_iter.advance(); 460 } 461 462 // ===== Export section ================================================== 463 if (section_iter.section_code() == kExportSectionCode) { 464 uint32_t export_table_count = 465 consume_count("exports count", kV8MaxWasmImports); 466 module->export_table.reserve(export_table_count); 467 for (uint32_t i = 0; ok() && i < export_table_count; ++i) { 468 TRACE("DecodeExportTable[%d] module+%d\n", i, 469 static_cast<int>(pc_ - start_)); 470 471 module->export_table.push_back({ 472 0, // name_length 473 0, // name_offset 474 kExternalFunction, // kind 475 0 // index 476 }); 477 WasmExport* exp = &module->export_table.back(); 478 479 exp->name_offset = consume_string(&exp->name_length, true); 480 const byte* pos = pc(); 481 exp->kind = static_cast<WasmExternalKind>(consume_u8("export kind")); 482 switch (exp->kind) { 483 case kExternalFunction: { 484 WasmFunction* func = nullptr; 485 exp->index = consume_func_index(module, &func); 486 module->num_exported_functions++; 487 if (func) func->exported = true; 488 break; 489 } 490 case kExternalTable: { 491 WasmIndirectFunctionTable* table = nullptr; 492 exp->index = consume_table_index(module, &table); 493 if (table) table->exported = true; 494 break; 495 } 496 case kExternalMemory: { 497 uint32_t index = consume_u32v("memory index"); 498 // TODO(titzer): This should become more regular 499 // once we support multiple memories. 500 if (!module->has_memory || index != 0) { 501 error("invalid memory index != 0"); 502 } 503 module->mem_export = true; 504 break; 505 } 506 case kExternalGlobal: { 507 WasmGlobal* global = nullptr; 508 exp->index = consume_global_index(module, &global); 509 if (global) { 510 if (global->mutability) { 511 error("mutable globals cannot be exported"); 512 } 513 global->exported = true; 514 } 515 break; 516 } 517 default: 518 error(pos, pos, "invalid export kind 0x%02x", exp->kind); 519 break; 520 } 521 } 522 // Check for duplicate exports (except for asm.js). 523 if (ok() && origin_ != kAsmJsOrigin && module->export_table.size() > 1) { 524 std::vector<WasmExport> sorted_exports(module->export_table); 525 const byte* base = start_; 526 auto cmp_less = [base](const WasmExport& a, const WasmExport& b) { 527 // Return true if a < b. 528 if (a.name_length != b.name_length) { 529 return a.name_length < b.name_length; 530 } 531 return memcmp(base + a.name_offset, base + b.name_offset, 532 a.name_length) < 0; 533 }; 534 std::stable_sort(sorted_exports.begin(), sorted_exports.end(), 535 cmp_less); 536 auto it = sorted_exports.begin(); 537 WasmExport* last = &*it++; 538 for (auto end = sorted_exports.end(); it != end; last = &*it++) { 539 DCHECK(!cmp_less(*it, *last)); // Vector must be sorted. 540 if (!cmp_less(*last, *it)) { 541 const byte* pc = start_ + it->name_offset; 542 error(pc, pc, 543 "Duplicate export name '%.*s' for functions %d and %d", 544 it->name_length, pc, last->index, it->index); 545 break; 546 } 547 } 548 } 549 section_iter.advance(); 550 } 551 552 // ===== Start section =================================================== 553 if (section_iter.section_code() == kStartSectionCode) { 554 WasmFunction* func; 555 const byte* pos = pc_; 556 module->start_function_index = consume_func_index(module, &func); 557 if (func && 558 (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) { 559 error(pos, 560 "invalid start function: non-zero parameter or return count"); 561 } 562 section_iter.advance(); 563 } 564 565 // ===== Elements section ================================================ 566 if (section_iter.section_code() == kElementSectionCode) { 567 uint32_t element_count = 568 consume_count("element count", FLAG_wasm_max_table_size); 569 for (uint32_t i = 0; ok() && i < element_count; ++i) { 570 const byte* pos = pc(); 571 uint32_t table_index = consume_u32v("table index"); 572 if (table_index != 0) { 573 error(pos, pos, "illegal table index %u != 0", table_index); 574 } 575 WasmIndirectFunctionTable* table = nullptr; 576 if (table_index >= module->function_tables.size()) { 577 error(pos, pos, "out of bounds table index %u", table_index); 578 } else { 579 table = &module->function_tables[table_index]; 580 } 581 WasmInitExpr offset = consume_init_expr(module, kWasmI32); 582 uint32_t num_elem = 583 consume_count("number of elements", kV8MaxWasmTableEntries); 584 std::vector<uint32_t> vector; 585 module->table_inits.push_back({table_index, offset, vector}); 586 WasmTableInit* init = &module->table_inits.back(); 587 for (uint32_t j = 0; ok() && j < num_elem; j++) { 588 WasmFunction* func = nullptr; 589 uint32_t index = consume_func_index(module, &func); 590 init->entries.push_back(index); 591 if (table && index < module->functions.size()) { 592 // Canonicalize signature indices during decoding. 593 table->map.FindOrInsert(module->functions[index].sig); 594 } 595 } 596 } 597 598 section_iter.advance(); 599 } 600 601 // ===== Code section ==================================================== 602 if (section_iter.section_code() == kCodeSectionCode) { 603 const byte* pos = pc_; 604 uint32_t functions_count = consume_u32v("functions count"); 605 if (functions_count != module->num_declared_functions) { 606 error(pos, pos, "function body count %u mismatch (%u expected)", 607 functions_count, module->num_declared_functions); 608 } 609 for (uint32_t i = 0; ok() && i < functions_count; ++i) { 610 WasmFunction* function = 611 &module->functions[i + module->num_imported_functions]; 612 uint32_t size = consume_u32v("body size"); 613 function->code_start_offset = pc_offset(); 614 function->code_end_offset = pc_offset() + size; 615 if (verify_functions) { 616 ModuleBytesEnv module_env(module, nullptr, 617 ModuleWireBytes(start_, end_)); 618 VerifyFunctionBody(i + module->num_imported_functions, &module_env, 619 function); 620 } 621 consume_bytes(size, "function body"); 622 } 623 section_iter.advance(); 624 } 625 626 // ===== Data section ==================================================== 627 if (section_iter.section_code() == kDataSectionCode) { 628 uint32_t data_segments_count = 629 consume_count("data segments count", kV8MaxWasmDataSegments); 630 module->data_segments.reserve(data_segments_count); 631 for (uint32_t i = 0; ok() && i < data_segments_count; ++i) { 632 if (!module->has_memory) { 633 error("cannot load data without memory"); 634 break; 635 } 636 TRACE("DecodeDataSegment[%d] module+%d\n", i, 637 static_cast<int>(pc_ - start_)); 638 module->data_segments.push_back({ 639 WasmInitExpr(), // dest_addr 640 0, // source_offset 641 0 // source_size 642 }); 643 WasmDataSegment* segment = &module->data_segments.back(); 644 DecodeDataSegmentInModule(module, segment); 645 } 646 section_iter.advance(); 647 } 648 649 // ===== Name section ==================================================== 650 if (section_iter.section_code() == kNameSectionCode) { 651 // TODO(titzer): find a way to report name errors as warnings. 652 // Use an inner decoder so that errors don't fail the outer decoder. 653 Decoder inner(start_, pc_, end_); 654 uint32_t functions_count = inner.consume_u32v("functions count"); 655 656 for (uint32_t i = 0; inner.ok() && i < functions_count; ++i) { 657 uint32_t function_name_length = 0; 658 uint32_t name_offset = 659 consume_string(inner, &function_name_length, false); 660 uint32_t func_index = i; 661 if (inner.ok() && func_index < module->functions.size()) { 662 module->functions[func_index].name_offset = name_offset; 663 module->functions[func_index].name_length = function_name_length; 664 } 665 666 uint32_t local_names_count = inner.consume_u32v("local names count"); 667 for (uint32_t j = 0; inner.ok() && j < local_names_count; j++) { 668 uint32_t length = inner.consume_u32v("string length"); 669 inner.consume_bytes(length, "string"); 670 } 671 } 672 // Skip the whole names section in the outer decoder. 673 consume_bytes(section_iter.payload_length(), nullptr); 674 section_iter.advance(); 675 } 676 677 // ===== Remaining sections ============================================== 678 if (section_iter.more() && ok()) { 679 error(pc(), pc(), "unexpected section: %s", 680 SectionName(section_iter.section_code())); 681 } 682 683 if (ok()) { 684 CalculateGlobalOffsets(module); 685 } 686 const WasmModule* finished_module = module; 687 ModuleResult result = toResult(finished_module); 688 if (verify_functions && result.ok()) { 689 result.MoveFrom(result_); // Copy error code and location. 690 } 691 if (FLAG_dump_wasm_module) DumpModule(result); 692 return result; 693 } 694 695 // Decodes a single anonymous function starting at {start_}. 696 FunctionResult DecodeSingleFunction(ModuleBytesEnv* module_env, 697 WasmFunction* function) { 698 pc_ = start_; 699 function->sig = consume_sig(); // read signature 700 function->name_offset = 0; // ---- name 701 function->name_length = 0; // ---- name length 702 function->code_start_offset = off(pc_); // ---- code start 703 function->code_end_offset = off(end_); // ---- code end 704 705 if (ok()) VerifyFunctionBody(0, module_env, function); 706 707 FunctionResult result; 708 result.MoveFrom(result_); // Copy error code and location. 709 result.val = function; 710 return result; 711 } 712 713 // Decodes a single function signature at {start}. 714 FunctionSig* DecodeFunctionSignature(const byte* start) { 715 pc_ = start; 716 FunctionSig* result = consume_sig(); 717 return ok() ? result : nullptr; 718 } 719 720 WasmInitExpr DecodeInitExpr(const byte* start) { 721 pc_ = start; 722 return consume_init_expr(nullptr, kWasmStmt); 723 } 724 725 private: 726 Zone* module_zone; 727 ModuleResult result_; 728 ModuleOrigin origin_; 729 730 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); } 731 732 bool AddTable(WasmModule* module) { 733 if (module->function_tables.size() > 0) { 734 error("At most one table is supported"); 735 return false; 736 } else { 737 return true; 738 } 739 } 740 741 bool AddMemory(WasmModule* module) { 742 if (module->has_memory) { 743 error("At most one memory is supported"); 744 return false; 745 } else { 746 module->has_memory = true; 747 return true; 748 } 749 } 750 751 // Decodes a single global entry inside a module starting at {pc_}. 752 void DecodeGlobalInModule(WasmModule* module, uint32_t index, 753 WasmGlobal* global) { 754 global->type = consume_value_type(); 755 global->mutability = consume_mutability(); 756 const byte* pos = pc(); 757 global->init = consume_init_expr(module, kWasmStmt); 758 switch (global->init.kind) { 759 case WasmInitExpr::kGlobalIndex: { 760 uint32_t other_index = global->init.val.global_index; 761 if (other_index >= index) { 762 error(pos, pos, 763 "invalid global index in init expression, " 764 "index %u, other_index %u", 765 index, other_index); 766 } else if (module->globals[other_index].type != global->type) { 767 error(pos, pos, 768 "type mismatch in global initialization " 769 "(from global #%u), expected %s, got %s", 770 other_index, WasmOpcodes::TypeName(global->type), 771 WasmOpcodes::TypeName(module->globals[other_index].type)); 772 } 773 break; 774 } 775 default: 776 if (global->type != TypeOf(module, global->init)) { 777 error(pos, pos, 778 "type error in global initialization, expected %s, got %s", 779 WasmOpcodes::TypeName(global->type), 780 WasmOpcodes::TypeName(TypeOf(module, global->init))); 781 } 782 } 783 } 784 785 bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) { 786 if (offset > limit) return false; 787 if ((offset + size) < offset) return false; // overflow 788 return (offset + size) <= limit; 789 } 790 791 // Decodes a single data segment entry inside a module starting at {pc_}. 792 void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) { 793 const byte* start = pc_; 794 expect_u8("linear memory index", 0); 795 segment->dest_addr = consume_init_expr(module, kWasmI32); 796 segment->source_size = consume_u32v("source size"); 797 segment->source_offset = static_cast<uint32_t>(pc_ - start_); 798 799 // Validate the data is in the module. 800 uint32_t module_limit = static_cast<uint32_t>(end_ - start_); 801 if (!IsWithinLimit(module_limit, segment->source_offset, 802 segment->source_size)) { 803 error(start, "segment out of bounds of module"); 804 } 805 806 consume_bytes(segment->source_size, "segment data"); 807 } 808 809 // Calculate individual global offsets and total size of globals table. 810 void CalculateGlobalOffsets(WasmModule* module) { 811 uint32_t offset = 0; 812 if (module->globals.size() == 0) { 813 module->globals_size = 0; 814 return; 815 } 816 for (WasmGlobal& global : module->globals) { 817 byte size = 818 WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type)); 819 offset = (offset + size - 1) & ~(size - 1); // align 820 global.offset = offset; 821 offset += size; 822 } 823 module->globals_size = offset; 824 } 825 826 // Verifies the body (code) of a given function. 827 void VerifyFunctionBody(uint32_t func_num, ModuleBytesEnv* menv, 828 WasmFunction* function) { 829 WasmFunctionName func_name(function, 830 menv->wire_bytes.GetNameOrNull(function)); 831 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { 832 OFStream os(stdout); 833 os << "Verifying WASM function " << func_name << std::endl; 834 } 835 FunctionBody body = {function->sig, start_, 836 start_ + function->code_start_offset, 837 start_ + function->code_end_offset}; 838 DecodeResult result = VerifyWasmCode( 839 module_zone->allocator(), 840 menv == nullptr ? nullptr : menv->module_env.module, body); 841 if (result.failed()) { 842 // Wrap the error message from the function decoder. 843 std::ostringstream str; 844 str << "in function " << func_name << ": "; 845 str << result; 846 std::string strval = str.str(); 847 const char* raw = strval.c_str(); 848 size_t len = strlen(raw); 849 char* buffer = new char[len]; 850 strncpy(buffer, raw, len); 851 buffer[len - 1] = 0; 852 853 // Copy error code and location. 854 result_.MoveFrom(result); 855 result_.error_msg.reset(buffer); 856 } 857 } 858 859 uint32_t consume_string(uint32_t* length, bool validate_utf8) { 860 return consume_string(*this, length, validate_utf8); 861 } 862 863 // Reads a length-prefixed string, checking that it is within bounds. Returns 864 // the offset of the string, and the length as an out parameter. 865 uint32_t consume_string(Decoder& decoder, uint32_t* length, 866 bool validate_utf8) { 867 *length = decoder.consume_u32v("string length"); 868 uint32_t offset = decoder.pc_offset(); 869 const byte* string_start = decoder.pc(); 870 // Consume bytes before validation to guarantee that the string is not oob. 871 if (*length > 0) decoder.consume_bytes(*length, "string"); 872 if (decoder.ok() && validate_utf8 && 873 !unibrow::Utf8::Validate(string_start, *length)) { 874 decoder.error(string_start, "no valid UTF-8 string"); 875 } 876 return offset; 877 } 878 879 uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) { 880 const byte* pos = pc_; 881 uint32_t sig_index = consume_u32v("signature index"); 882 if (sig_index >= module->signatures.size()) { 883 error(pos, pos, "signature index %u out of bounds (%d signatures)", 884 sig_index, static_cast<int>(module->signatures.size())); 885 *sig = nullptr; 886 return 0; 887 } 888 *sig = module->signatures[sig_index]; 889 return sig_index; 890 } 891 892 uint32_t consume_count(const char* name, size_t maximum) { 893 const byte* p = pc_; 894 uint32_t count = consume_u32v(name); 895 if (count > maximum) { 896 error(p, p, "%s of %u exceeds internal limit of %zu", name, count, 897 maximum); 898 return static_cast<uint32_t>(maximum); 899 } 900 return count; 901 } 902 903 uint32_t consume_func_index(WasmModule* module, WasmFunction** func) { 904 return consume_index("function index", module->functions, func); 905 } 906 907 uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) { 908 return consume_index("global index", module->globals, global); 909 } 910 911 uint32_t consume_table_index(WasmModule* module, 912 WasmIndirectFunctionTable** table) { 913 return consume_index("table index", module->function_tables, table); 914 } 915 916 template <typename T> 917 uint32_t consume_index(const char* name, std::vector<T>& vector, T** ptr) { 918 const byte* pos = pc_; 919 uint32_t index = consume_u32v(name); 920 if (index >= vector.size()) { 921 error(pos, pos, "%s %u out of bounds (%d entries)", name, index, 922 static_cast<int>(vector.size())); 923 *ptr = nullptr; 924 return 0; 925 } 926 *ptr = &vector[index]; 927 return index; 928 } 929 930 void consume_resizable_limits(const char* name, const char* units, 931 uint32_t max_initial, uint32_t* initial, 932 bool* has_max, uint32_t max_maximum, 933 uint32_t* maximum) { 934 uint32_t flags = consume_u32v("resizable limits flags"); 935 const byte* pos = pc(); 936 *initial = consume_u32v("initial size"); 937 *has_max = false; 938 if (*initial > max_initial) { 939 error(pos, pos, 940 "initial %s size (%u %s) is larger than implementation limit (%u)", 941 name, *initial, units, max_initial); 942 } 943 if (flags & 1) { 944 *has_max = true; 945 pos = pc(); 946 *maximum = consume_u32v("maximum size"); 947 if (*maximum > max_maximum) { 948 error( 949 pos, pos, 950 "maximum %s size (%u %s) is larger than implementation limit (%u)", 951 name, *maximum, units, max_maximum); 952 } 953 if (*maximum < *initial) { 954 error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)", 955 name, *maximum, units, *initial, units); 956 } 957 } else { 958 *has_max = false; 959 *maximum = max_initial; 960 } 961 } 962 963 bool expect_u8(const char* name, uint8_t expected) { 964 const byte* pos = pc(); 965 uint8_t value = consume_u8(name); 966 if (value != expected) { 967 error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); 968 return false; 969 } 970 return true; 971 } 972 973 WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) { 974 const byte* pos = pc(); 975 uint8_t opcode = consume_u8("opcode"); 976 WasmInitExpr expr; 977 unsigned len = 0; 978 switch (opcode) { 979 case kExprGetGlobal: { 980 GlobalIndexOperand operand(this, pc() - 1); 981 if (module->globals.size() <= operand.index) { 982 error("global index is out of bounds"); 983 expr.kind = WasmInitExpr::kNone; 984 expr.val.i32_const = 0; 985 break; 986 } 987 WasmGlobal* global = &module->globals[operand.index]; 988 if (global->mutability || !global->imported) { 989 error( 990 "only immutable imported globals can be used in initializer " 991 "expressions"); 992 expr.kind = WasmInitExpr::kNone; 993 expr.val.i32_const = 0; 994 break; 995 } 996 expr.kind = WasmInitExpr::kGlobalIndex; 997 expr.val.global_index = operand.index; 998 len = operand.length; 999 break; 1000 } 1001 case kExprI32Const: { 1002 ImmI32Operand operand(this, pc() - 1); 1003 expr.kind = WasmInitExpr::kI32Const; 1004 expr.val.i32_const = operand.value; 1005 len = operand.length; 1006 break; 1007 } 1008 case kExprF32Const: { 1009 ImmF32Operand operand(this, pc() - 1); 1010 expr.kind = WasmInitExpr::kF32Const; 1011 expr.val.f32_const = operand.value; 1012 len = operand.length; 1013 break; 1014 } 1015 case kExprI64Const: { 1016 ImmI64Operand operand(this, pc() - 1); 1017 expr.kind = WasmInitExpr::kI64Const; 1018 expr.val.i64_const = operand.value; 1019 len = operand.length; 1020 break; 1021 } 1022 case kExprF64Const: { 1023 ImmF64Operand operand(this, pc() - 1); 1024 expr.kind = WasmInitExpr::kF64Const; 1025 expr.val.f64_const = operand.value; 1026 len = operand.length; 1027 break; 1028 } 1029 default: { 1030 error("invalid opcode in initialization expression"); 1031 expr.kind = WasmInitExpr::kNone; 1032 expr.val.i32_const = 0; 1033 } 1034 } 1035 consume_bytes(len, "init code"); 1036 if (!expect_u8("end opcode", kExprEnd)) { 1037 expr.kind = WasmInitExpr::kNone; 1038 } 1039 if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) { 1040 error(pos, pos, "type error in init expression, expected %s, got %s", 1041 WasmOpcodes::TypeName(expected), 1042 WasmOpcodes::TypeName(TypeOf(module, expr))); 1043 } 1044 return expr; 1045 } 1046 1047 // Read a mutability flag 1048 bool consume_mutability() { 1049 byte val = consume_u8("mutability"); 1050 if (val > 1) error(pc_ - 1, "invalid mutability"); 1051 return val != 0; 1052 } 1053 1054 // Reads a single 8-bit integer, interpreting it as a local type. 1055 ValueType consume_value_type() { 1056 byte val = consume_u8("value type"); 1057 ValueTypeCode t = static_cast<ValueTypeCode>(val); 1058 switch (t) { 1059 case kLocalI32: 1060 return kWasmI32; 1061 case kLocalI64: 1062 return kWasmI64; 1063 case kLocalF32: 1064 return kWasmF32; 1065 case kLocalF64: 1066 return kWasmF64; 1067 default: 1068 if (origin_ != kAsmJsOrigin && FLAG_wasm_simd_prototype) { 1069 switch (t) { 1070 case kLocalS128: 1071 return kWasmS128; 1072 case kLocalS1x4: 1073 return kWasmS1x4; 1074 case kLocalS1x8: 1075 return kWasmS1x8; 1076 case kLocalS1x16: 1077 return kWasmS1x16; 1078 default: 1079 break; 1080 } 1081 } 1082 error(pc_ - 1, "invalid local type"); 1083 return kWasmStmt; 1084 } 1085 } 1086 1087 // Parses a type entry, which is currently limited to functions only. 1088 FunctionSig* consume_sig() { 1089 if (!expect_u8("type form", kWasmFunctionTypeForm)) return nullptr; 1090 // parse parameter types 1091 uint32_t param_count = 1092 consume_count("param count", kV8MaxWasmFunctionParams); 1093 if (failed()) return nullptr; 1094 std::vector<ValueType> params; 1095 for (uint32_t i = 0; ok() && i < param_count; ++i) { 1096 ValueType param = consume_value_type(); 1097 params.push_back(param); 1098 } 1099 1100 // parse return types 1101 const size_t max_return_count = FLAG_wasm_mv_prototype 1102 ? kV8MaxWasmFunctionMultiReturns 1103 : kV8MaxWasmFunctionReturns; 1104 uint32_t return_count = consume_count("return count", max_return_count); 1105 if (failed()) return nullptr; 1106 std::vector<ValueType> returns; 1107 for (uint32_t i = 0; ok() && i < return_count; ++i) { 1108 ValueType ret = consume_value_type(); 1109 returns.push_back(ret); 1110 } 1111 1112 if (failed()) return nullptr; 1113 1114 // FunctionSig stores the return types first. 1115 ValueType* buffer = 1116 module_zone->NewArray<ValueType>(param_count + return_count); 1117 uint32_t b = 0; 1118 for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i]; 1119 for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i]; 1120 1121 return new (module_zone) FunctionSig(return_count, param_count, buffer); 1122 } 1123 }; 1124 1125 // Helpers for nice error messages. 1126 class ModuleError : public ModuleResult { 1127 public: 1128 explicit ModuleError(const char* msg) { 1129 error_code = kError; 1130 size_t len = strlen(msg) + 1; 1131 char* result = new char[len]; 1132 strncpy(result, msg, len); 1133 result[len - 1] = 0; 1134 error_msg.reset(result); 1135 } 1136 }; 1137 1138 // Helpers for nice error messages. 1139 class FunctionError : public FunctionResult { 1140 public: 1141 explicit FunctionError(const char* msg) { 1142 error_code = kError; 1143 size_t len = strlen(msg) + 1; 1144 char* result = new char[len]; 1145 strncpy(result, msg, len); 1146 result[len - 1] = 0; 1147 error_msg.reset(result); 1148 } 1149 }; 1150 1151 // Find section with given section code. Return Vector of the payload, or null 1152 // Vector if section is not found or module bytes are invalid. 1153 Vector<const byte> FindSection(const byte* module_start, const byte* module_end, 1154 WasmSectionCode code) { 1155 Decoder decoder(module_start, module_end); 1156 1157 uint32_t magic_word = decoder.consume_u32("wasm magic"); 1158 if (magic_word != kWasmMagic) decoder.error("wrong magic word"); 1159 1160 uint32_t magic_version = decoder.consume_u32("wasm version"); 1161 if (magic_version != kWasmVersion) decoder.error("wrong wasm version"); 1162 1163 WasmSectionIterator section_iter(decoder); 1164 while (section_iter.more()) { 1165 if (section_iter.section_code() == code) { 1166 return Vector<const uint8_t>(section_iter.payload_start(), 1167 section_iter.payload_length()); 1168 } 1169 decoder.consume_bytes(section_iter.payload_length(), "section payload"); 1170 section_iter.advance(); 1171 } 1172 1173 return Vector<const uint8_t>(); 1174 } 1175 1176 } // namespace 1177 1178 ModuleResult DecodeWasmModule(Isolate* isolate, const byte* module_start, 1179 const byte* module_end, bool verify_functions, 1180 ModuleOrigin origin) { 1181 HistogramTimerScope wasm_decode_module_time_scope( 1182 isolate->counters()->wasm_decode_module_time()); 1183 size_t size = module_end - module_start; 1184 if (module_start > module_end) return ModuleError("start > end"); 1185 if (size >= kV8MaxWasmModuleSize) 1186 return ModuleError("size > maximum module size"); 1187 // TODO(bradnelson): Improve histogram handling of size_t. 1188 isolate->counters()->wasm_module_size_bytes()->AddSample( 1189 static_cast<int>(size)); 1190 // Signatures are stored in zone memory, which have the same lifetime 1191 // as the {module}. 1192 Zone* zone = new Zone(isolate->allocator(), ZONE_NAME); 1193 ModuleDecoder decoder(zone, module_start, module_end, origin); 1194 ModuleResult result = decoder.DecodeModule(verify_functions); 1195 // TODO(bradnelson): Improve histogram handling of size_t. 1196 // TODO(titzer): this isn't accurate, since it doesn't count the data 1197 // allocated on the C++ heap. 1198 // https://bugs.chromium.org/p/chromium/issues/detail?id=657320 1199 isolate->counters()->wasm_decode_module_peak_memory_bytes()->AddSample( 1200 static_cast<int>(zone->allocation_size())); 1201 return result; 1202 } 1203 1204 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start, 1205 const byte* end) { 1206 ModuleDecoder decoder(zone, start, end, kWasmOrigin); 1207 return decoder.DecodeFunctionSignature(start); 1208 } 1209 1210 WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) { 1211 AccountingAllocator allocator; 1212 Zone zone(&allocator, ZONE_NAME); 1213 ModuleDecoder decoder(&zone, start, end, kWasmOrigin); 1214 return decoder.DecodeInitExpr(start); 1215 } 1216 1217 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, 1218 ModuleBytesEnv* module_env, 1219 const byte* function_start, 1220 const byte* function_end) { 1221 HistogramTimerScope wasm_decode_function_time_scope( 1222 isolate->counters()->wasm_decode_function_time()); 1223 size_t size = function_end - function_start; 1224 if (function_start > function_end) return FunctionError("start > end"); 1225 if (size > kV8MaxWasmFunctionSize) 1226 return FunctionError("size > maximum function size"); 1227 isolate->counters()->wasm_function_size_bytes()->AddSample( 1228 static_cast<int>(size)); 1229 WasmFunction* function = new WasmFunction(); 1230 ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin); 1231 return decoder.DecodeSingleFunction(module_env, function); 1232 } 1233 1234 FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start, 1235 const byte* module_end) { 1236 // Find and decode the code section. 1237 Vector<const byte> code_section = 1238 FindSection(module_start, module_end, kCodeSectionCode); 1239 Decoder decoder(code_section.start(), code_section.end()); 1240 FunctionOffsets table; 1241 if (!code_section.start()) { 1242 decoder.error("no code section"); 1243 return decoder.toResult(std::move(table)); 1244 } 1245 1246 uint32_t functions_count = decoder.consume_u32v("functions count"); 1247 // Reserve space for the entries, taking care of invalid input. 1248 if (functions_count < static_cast<unsigned>(code_section.length()) / 2) { 1249 table.reserve(functions_count); 1250 } 1251 1252 int section_offset = static_cast<int>(code_section.start() - module_start); 1253 DCHECK_LE(0, section_offset); 1254 for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { 1255 uint32_t size = decoder.consume_u32v("body size"); 1256 int offset = static_cast<int>(section_offset + decoder.pc_offset()); 1257 table.emplace_back(offset, static_cast<int>(size)); 1258 DCHECK(table.back().first >= 0 && table.back().second >= 0); 1259 decoder.consume_bytes(size); 1260 } 1261 if (decoder.more()) decoder.error("unexpected additional bytes"); 1262 1263 return decoder.toResult(std::move(table)); 1264 } 1265 1266 AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start, 1267 const byte* tables_end) { 1268 AsmJsOffsets table; 1269 1270 Decoder decoder(tables_start, tables_end); 1271 uint32_t functions_count = decoder.consume_u32v("functions count"); 1272 // Reserve space for the entries, taking care of invalid input. 1273 if (functions_count < static_cast<unsigned>(tables_end - tables_start)) { 1274 table.reserve(functions_count); 1275 } 1276 1277 for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { 1278 uint32_t size = decoder.consume_u32v("table size"); 1279 if (size == 0) { 1280 table.emplace_back(); 1281 continue; 1282 } 1283 if (!decoder.checkAvailable(size)) { 1284 decoder.error("illegal asm function offset table size"); 1285 } 1286 const byte* table_end = decoder.pc() + size; 1287 uint32_t locals_size = decoder.consume_u32v("locals size"); 1288 int function_start_position = decoder.consume_u32v("function start pos"); 1289 int last_byte_offset = locals_size; 1290 int last_asm_position = function_start_position; 1291 std::vector<AsmJsOffsetEntry> func_asm_offsets; 1292 func_asm_offsets.reserve(size / 4); // conservative estimation 1293 // Add an entry for the stack check, associated with position 0. 1294 func_asm_offsets.push_back( 1295 {0, function_start_position, function_start_position}); 1296 while (decoder.ok() && decoder.pc() < table_end) { 1297 last_byte_offset += decoder.consume_u32v("byte offset delta"); 1298 int call_position = 1299 last_asm_position + decoder.consume_i32v("call position delta"); 1300 int to_number_position = 1301 call_position + decoder.consume_i32v("to_number position delta"); 1302 last_asm_position = to_number_position; 1303 func_asm_offsets.push_back( 1304 {last_byte_offset, call_position, to_number_position}); 1305 } 1306 if (decoder.pc() != table_end) { 1307 decoder.error("broken asm offset table"); 1308 } 1309 table.push_back(std::move(func_asm_offsets)); 1310 } 1311 if (decoder.more()) decoder.error("unexpected additional bytes"); 1312 1313 return decoder.toResult(std::move(table)); 1314 } 1315 1316 std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start, 1317 const byte* end) { 1318 Decoder decoder(start, end); 1319 decoder.consume_bytes(4, "wasm magic"); 1320 decoder.consume_bytes(4, "wasm version"); 1321 1322 std::vector<CustomSectionOffset> result; 1323 1324 while (decoder.more()) { 1325 byte section_code = decoder.consume_u8("section code"); 1326 uint32_t section_length = decoder.consume_u32v("section length"); 1327 uint32_t section_start = decoder.pc_offset(); 1328 if (section_code != 0) { 1329 // Skip known sections. 1330 decoder.consume_bytes(section_length, "section bytes"); 1331 continue; 1332 } 1333 uint32_t name_length = decoder.consume_u32v("name length"); 1334 uint32_t name_offset = decoder.pc_offset(); 1335 decoder.consume_bytes(name_length, "section name"); 1336 uint32_t payload_offset = decoder.pc_offset(); 1337 uint32_t payload_length = section_length - (payload_offset - section_start); 1338 decoder.consume_bytes(payload_length); 1339 result.push_back({section_start, name_offset, name_length, payload_offset, 1340 payload_length, section_length}); 1341 } 1342 1343 return result; 1344 } 1345 1346 } // namespace wasm 1347 } // namespace internal 1348 } // namespace v8 1349