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