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/macro-assembler.h" 10 #include "src/objects.h" 11 #include "src/v8.h" 12 13 #include "src/wasm/decoder.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace wasm { 18 19 #if DEBUG 20 #define TRACE(...) \ 21 do { \ 22 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 23 } while (false) 24 #else 25 #define TRACE(...) 26 #endif 27 28 namespace { 29 30 // The main logic for decoding the bytes of a module. 31 class ModuleDecoder : public Decoder { 32 public: 33 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end, 34 ModuleOrigin origin) 35 : Decoder(module_start, module_end), module_zone(zone), origin_(origin) { 36 result_.start = start_; 37 if (limit_ < start_) { 38 error(start_, "end is less than start"); 39 limit_ = start_; 40 } 41 } 42 43 virtual void onFirstError() { 44 pc_ = limit_; // On error, terminate section decoding loop. 45 } 46 47 static void DumpModule(WasmModule* module, ModuleResult result) { 48 std::string path; 49 if (FLAG_dump_wasm_module_path) { 50 path = FLAG_dump_wasm_module_path; 51 if (path.size() && 52 !base::OS::isDirectorySeparator(path[path.size() - 1])) { 53 path += base::OS::DirectorySeparator(); 54 } 55 } 56 // File are named `HASH.{ok,failed}.wasm`. 57 size_t hash = base::hash_range(module->module_start, module->module_end); 58 char buf[32] = {'\0'}; 59 #if V8_OS_WIN && _MSC_VER < 1900 60 #define snprintf sprintf_s 61 #endif 62 snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash, 63 result.ok() ? "ok" : "failed"); 64 std::string name(buf); 65 if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) { 66 fwrite(module->module_start, module->module_end - module->module_start, 1, 67 wasm_file); 68 fclose(wasm_file); 69 } 70 } 71 72 // Decodes an entire module. 73 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) { 74 pc_ = start_; 75 module->module_start = start_; 76 module->module_end = limit_; 77 module->min_mem_pages = 0; 78 module->max_mem_pages = 0; 79 module->mem_export = false; 80 module->mem_external = false; 81 module->origin = origin_; 82 83 const byte* pos = pc_; 84 int current_order = 0; 85 uint32_t magic_word = consume_u32("wasm magic"); 86 #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff 87 if (magic_word != kWasmMagic) { 88 error(pos, pos, 89 "expected magic word %02x %02x %02x %02x, " 90 "found %02x %02x %02x %02x", 91 BYTES(kWasmMagic), BYTES(magic_word)); 92 goto done; 93 } 94 95 pos = pc_; 96 { 97 uint32_t magic_version = consume_u32("wasm version"); 98 if (magic_version != kWasmVersion) { 99 error(pos, pos, 100 "expected version %02x %02x %02x %02x, " 101 "found %02x %02x %02x %02x", 102 BYTES(kWasmVersion), BYTES(magic_version)); 103 goto done; 104 } 105 } 106 107 // Decode the module sections. 108 while (pc_ < limit_) { 109 TRACE("DecodeSection\n"); 110 pos = pc_; 111 112 // Read the section name. 113 uint32_t string_length = consume_u32v("section name length"); 114 const byte* section_name_start = pc_; 115 consume_bytes(string_length); 116 if (failed()) { 117 TRACE("Section name of length %u couldn't be read\n", string_length); 118 break; 119 } 120 121 TRACE(" +%d section name : \"%.*s\"\n", 122 static_cast<int>(section_name_start - start_), 123 string_length < 20 ? string_length : 20, section_name_start); 124 125 WasmSection::Code section = 126 WasmSection::lookup(section_name_start, string_length); 127 128 // Read and check the section size. 129 uint32_t section_length = consume_u32v("section length"); 130 if (!checkAvailable(section_length)) { 131 // The section would extend beyond the end of the module. 132 break; 133 } 134 const byte* section_start = pc_; 135 const byte* expected_section_end = pc_ + section_length; 136 137 current_order = CheckSectionOrder(current_order, section); 138 139 switch (section) { 140 case WasmSection::Code::End: 141 // Terminate section decoding. 142 limit_ = pc_; 143 break; 144 case WasmSection::Code::Memory: { 145 module->min_mem_pages = consume_u32v("min memory"); 146 module->max_mem_pages = consume_u32v("max memory"); 147 module->mem_export = consume_u8("export memory") != 0; 148 break; 149 } 150 case WasmSection::Code::Signatures: { 151 uint32_t signatures_count = consume_u32v("signatures count"); 152 module->signatures.reserve(SafeReserve(signatures_count)); 153 // Decode signatures. 154 for (uint32_t i = 0; i < signatures_count; ++i) { 155 if (failed()) break; 156 TRACE("DecodeSignature[%d] module+%d\n", i, 157 static_cast<int>(pc_ - start_)); 158 FunctionSig* s = consume_sig(); 159 module->signatures.push_back(s); 160 } 161 break; 162 } 163 case WasmSection::Code::FunctionSignatures: { 164 uint32_t functions_count = consume_u32v("functions count"); 165 module->functions.reserve(SafeReserve(functions_count)); 166 for (uint32_t i = 0; i < functions_count; ++i) { 167 module->functions.push_back({nullptr, // sig 168 i, // func_index 169 0, // sig_index 170 0, // name_offset 171 0, // name_length 172 0, // code_start_offset 173 0}); // code_end_offset 174 WasmFunction* function = &module->functions.back(); 175 function->sig_index = consume_sig_index(module, &function->sig); 176 } 177 break; 178 } 179 case WasmSection::Code::FunctionBodies: { 180 const byte* pos = pc_; 181 uint32_t functions_count = consume_u32v("functions count"); 182 if (functions_count != module->functions.size()) { 183 error(pos, pos, "function body count %u mismatch (%u expected)", 184 functions_count, 185 static_cast<uint32_t>(module->functions.size())); 186 break; 187 } 188 for (uint32_t i = 0; i < functions_count; ++i) { 189 WasmFunction* function = &module->functions[i]; 190 uint32_t size = consume_u32v("body size"); 191 function->code_start_offset = pc_offset(); 192 function->code_end_offset = pc_offset() + size; 193 194 TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body", 195 size); 196 pc_ += size; 197 if (pc_ > limit_) { 198 error(pc_, "function body extends beyond end of file"); 199 } 200 } 201 break; 202 } 203 case WasmSection::Code::Names: { 204 const byte* pos = pc_; 205 uint32_t functions_count = consume_u32v("functions count"); 206 if (functions_count != module->functions.size()) { 207 error(pos, pos, "function name count %u mismatch (%u expected)", 208 functions_count, 209 static_cast<uint32_t>(module->functions.size())); 210 break; 211 } 212 213 for (uint32_t i = 0; i < functions_count; ++i) { 214 WasmFunction* function = &module->functions[i]; 215 function->name_offset = 216 consume_string(&function->name_length, false); 217 218 uint32_t local_names_count = consume_u32v("local names count"); 219 for (uint32_t j = 0; j < local_names_count; j++) { 220 uint32_t unused = 0; 221 uint32_t offset = consume_string(&unused, false); 222 USE(unused); 223 USE(offset); 224 } 225 } 226 break; 227 } 228 case WasmSection::Code::Globals: { 229 uint32_t globals_count = consume_u32v("globals count"); 230 module->globals.reserve(SafeReserve(globals_count)); 231 // Decode globals. 232 for (uint32_t i = 0; i < globals_count; ++i) { 233 if (failed()) break; 234 TRACE("DecodeGlobal[%d] module+%d\n", i, 235 static_cast<int>(pc_ - start_)); 236 module->globals.push_back({0, 0, MachineType::Int32(), 0, false}); 237 WasmGlobal* global = &module->globals.back(); 238 DecodeGlobalInModule(global); 239 } 240 break; 241 } 242 case WasmSection::Code::DataSegments: { 243 uint32_t data_segments_count = consume_u32v("data segments count"); 244 module->data_segments.reserve(SafeReserve(data_segments_count)); 245 // Decode data segments. 246 for (uint32_t i = 0; i < data_segments_count; ++i) { 247 if (failed()) break; 248 TRACE("DecodeDataSegment[%d] module+%d\n", i, 249 static_cast<int>(pc_ - start_)); 250 module->data_segments.push_back({0, // dest_addr 251 0, // source_offset 252 0, // source_size 253 false}); // init 254 WasmDataSegment* segment = &module->data_segments.back(); 255 DecodeDataSegmentInModule(module, segment); 256 } 257 break; 258 } 259 case WasmSection::Code::FunctionTablePad: { 260 if (!FLAG_wasm_jit_prototype) { 261 error("FunctionTablePad section without jiting enabled"); 262 } 263 // An indirect function table requires functions first. 264 module->indirect_table_size = consume_u32v("indirect entry count"); 265 if (module->indirect_table_size > 0 && 266 module->indirect_table_size < module->function_table.size()) { 267 error("more predefined indirect entries than table can hold"); 268 } 269 break; 270 } 271 case WasmSection::Code::FunctionTable: { 272 // An indirect function table requires functions first. 273 CheckForFunctions(module, section); 274 uint32_t function_table_count = consume_u32v("function table count"); 275 module->function_table.reserve(SafeReserve(function_table_count)); 276 // Decode function table. 277 for (uint32_t i = 0; i < function_table_count; ++i) { 278 if (failed()) break; 279 TRACE("DecodeFunctionTable[%d] module+%d\n", i, 280 static_cast<int>(pc_ - start_)); 281 uint16_t index = consume_u32v(); 282 if (index >= module->functions.size()) { 283 error(pc_ - 2, "invalid function index"); 284 break; 285 } 286 module->function_table.push_back(index); 287 } 288 if (module->indirect_table_size > 0 && 289 module->indirect_table_size < module->function_table.size()) { 290 error("more predefined indirect entries than table can hold"); 291 } 292 break; 293 } 294 case WasmSection::Code::StartFunction: { 295 // Declares a start function for a module. 296 CheckForFunctions(module, section); 297 if (module->start_function_index >= 0) { 298 error("start function already declared"); 299 break; 300 } 301 WasmFunction* func; 302 const byte* pos = pc_; 303 module->start_function_index = consume_func_index(module, &func); 304 if (func && func->sig->parameter_count() > 0) { 305 error(pos, "invalid start function: non-zero parameter count"); 306 break; 307 } 308 break; 309 } 310 case WasmSection::Code::ImportTable: { 311 uint32_t import_table_count = consume_u32v("import table count"); 312 module->import_table.reserve(SafeReserve(import_table_count)); 313 // Decode import table. 314 for (uint32_t i = 0; i < import_table_count; ++i) { 315 if (failed()) break; 316 TRACE("DecodeImportTable[%d] module+%d\n", i, 317 static_cast<int>(pc_ - start_)); 318 319 module->import_table.push_back({nullptr, // sig 320 0, // sig_index 321 0, // module_name_offset 322 0, // module_name_length 323 0, // function_name_offset 324 0}); // function_name_length 325 WasmImport* import = &module->import_table.back(); 326 327 import->sig_index = consume_sig_index(module, &import->sig); 328 const byte* pos = pc_; 329 import->module_name_offset = 330 consume_string(&import->module_name_length, true); 331 if (import->module_name_length == 0) { 332 error(pos, "import module name cannot be NULL"); 333 } 334 import->function_name_offset = 335 consume_string(&import->function_name_length, true); 336 } 337 break; 338 } 339 case WasmSection::Code::ExportTable: { 340 // Declares an export table. 341 CheckForFunctions(module, section); 342 uint32_t export_table_count = consume_u32v("export table count"); 343 module->export_table.reserve(SafeReserve(export_table_count)); 344 // Decode export table. 345 for (uint32_t i = 0; i < export_table_count; ++i) { 346 if (failed()) break; 347 TRACE("DecodeExportTable[%d] module+%d\n", i, 348 static_cast<int>(pc_ - start_)); 349 350 module->export_table.push_back({0, // func_index 351 0, // name_offset 352 0}); // name_length 353 WasmExport* exp = &module->export_table.back(); 354 355 WasmFunction* func; 356 exp->func_index = consume_func_index(module, &func); 357 exp->name_offset = consume_string(&exp->name_length, true); 358 } 359 // Check for duplicate exports. 360 if (ok() && module->export_table.size() > 1) { 361 std::vector<WasmExport> sorted_exports(module->export_table); 362 const byte* base = start_; 363 auto cmp_less = [base](const WasmExport& a, const WasmExport& b) { 364 // Return true if a < b. 365 uint32_t len = a.name_length; 366 if (len != b.name_length) return len < b.name_length; 367 return memcmp(base + a.name_offset, base + b.name_offset, len) < 368 0; 369 }; 370 std::stable_sort(sorted_exports.begin(), sorted_exports.end(), 371 cmp_less); 372 auto it = sorted_exports.begin(); 373 WasmExport* last = &*it++; 374 for (auto end = sorted_exports.end(); it != end; last = &*it++) { 375 DCHECK(!cmp_less(*it, *last)); // Vector must be sorted. 376 if (!cmp_less(*last, *it)) { 377 const byte* pc = start_ + it->name_offset; 378 error(pc, pc, 379 "Duplicate export name '%.*s' for functions %d and %d", 380 it->name_length, pc, last->func_index, it->func_index); 381 break; 382 } 383 } 384 } 385 break; 386 } 387 case WasmSection::Code::Max: 388 // Skip unknown sections. 389 TRACE("Unknown section: '"); 390 for (uint32_t i = 0; i != string_length; ++i) { 391 TRACE("%c", *(section_name_start + i)); 392 } 393 TRACE("'\n"); 394 consume_bytes(section_length); 395 break; 396 } 397 398 if (pc_ != expected_section_end) { 399 const char* diff = pc_ < expected_section_end ? "shorter" : "longer"; 400 size_t expected_length = static_cast<size_t>(section_length); 401 size_t actual_length = static_cast<size_t>(pc_ - section_start); 402 error(pc_, pc_, 403 "section \"%s\" %s (%zu bytes) than specified (%zu bytes)", 404 WasmSection::getName(section), diff, actual_length, 405 expected_length); 406 break; 407 } 408 } 409 410 done: 411 if (ok()) CalculateGlobalsOffsets(module); 412 const WasmModule* finished_module = module; 413 ModuleResult result = toResult(finished_module); 414 if (FLAG_dump_wasm_module) { 415 DumpModule(module, result); 416 } 417 return result; 418 } 419 420 uint32_t SafeReserve(uint32_t count) { 421 // Avoid OOM by only reserving up to a certain size. 422 const uint32_t kMaxReserve = 20000; 423 return count < kMaxReserve ? count : kMaxReserve; 424 } 425 426 void CheckForFunctions(WasmModule* module, WasmSection::Code section) { 427 if (module->functions.size() == 0) { 428 error(pc_ - 1, nullptr, "functions must appear before section %s", 429 WasmSection::getName(section)); 430 } 431 } 432 433 int CheckSectionOrder(int current_order, WasmSection::Code section) { 434 int next_order = WasmSection::getOrder(section); 435 if (next_order == 0) return current_order; 436 if (next_order == current_order) { 437 error(pc_, pc_, "section \"%s\" already defined", 438 WasmSection::getName(section)); 439 } 440 if (next_order < current_order) { 441 error(pc_, pc_, "section \"%s\" out of order", 442 WasmSection::getName(section)); 443 } 444 return next_order; 445 } 446 447 // Decodes a single anonymous function starting at {start_}. 448 FunctionResult DecodeSingleFunction(ModuleEnv* module_env, 449 WasmFunction* function) { 450 pc_ = start_; 451 function->sig = consume_sig(); // read signature 452 function->name_offset = 0; // ---- name 453 function->name_length = 0; // ---- name length 454 function->code_start_offset = off(pc_); // ---- code start 455 function->code_end_offset = off(limit_); // ---- code end 456 457 if (ok()) VerifyFunctionBody(0, module_env, function); 458 459 FunctionResult result; 460 result.CopyFrom(result_); // Copy error code and location. 461 result.val = function; 462 return result; 463 } 464 465 // Decodes a single function signature at {start}. 466 FunctionSig* DecodeFunctionSignature(const byte* start) { 467 pc_ = start; 468 FunctionSig* result = consume_sig(); 469 return ok() ? result : nullptr; 470 } 471 472 private: 473 Zone* module_zone; 474 ModuleResult result_; 475 ModuleOrigin origin_; 476 477 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); } 478 479 // Decodes a single global entry inside a module starting at {pc_}. 480 void DecodeGlobalInModule(WasmGlobal* global) { 481 global->name_offset = consume_string(&global->name_length, false); 482 if (!unibrow::Utf8::Validate(start_ + global->name_offset, 483 global->name_length)) { 484 error("global name is not valid utf8"); 485 } 486 global->type = mem_type(); 487 global->offset = 0; 488 global->exported = consume_u8("exported") != 0; 489 } 490 491 bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) { 492 if (offset > limit) return false; 493 if ((offset + size) < offset) return false; // overflow 494 return (offset + size) <= limit; 495 } 496 497 // Decodes a single data segment entry inside a module starting at {pc_}. 498 void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) { 499 const byte* start = pc_; 500 segment->dest_addr = consume_u32v("destination"); 501 segment->source_size = consume_u32v("source size"); 502 segment->source_offset = static_cast<uint32_t>(pc_ - start_); 503 segment->init = true; 504 505 // Validate the data is in the module. 506 uint32_t module_limit = static_cast<uint32_t>(limit_ - start_); 507 if (!IsWithinLimit(module_limit, segment->source_offset, 508 segment->source_size)) { 509 error(start, "segment out of bounds of module"); 510 } 511 512 // Validate that the segment will fit into the (minimum) memory. 513 uint32_t memory_limit = 514 WasmModule::kPageSize * (module ? module->min_mem_pages 515 : WasmModule::kMaxMemPages); 516 if (!IsWithinLimit(memory_limit, segment->dest_addr, 517 segment->source_size)) { 518 error(start, "segment out of bounds of memory"); 519 } 520 521 consume_bytes(segment->source_size); 522 } 523 524 // Calculate individual global offsets and total size of globals table. 525 void CalculateGlobalsOffsets(WasmModule* module) { 526 uint32_t offset = 0; 527 if (module->globals.size() == 0) { 528 module->globals_size = 0; 529 return; 530 } 531 for (WasmGlobal& global : module->globals) { 532 byte size = WasmOpcodes::MemSize(global.type); 533 offset = (offset + size - 1) & ~(size - 1); // align 534 global.offset = offset; 535 offset += size; 536 } 537 module->globals_size = offset; 538 } 539 540 // Verifies the body (code) of a given function. 541 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, 542 WasmFunction* function) { 543 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { 544 OFStream os(stdout); 545 os << "Verifying WASM function " << WasmFunctionName(function, menv) 546 << std::endl; 547 } 548 FunctionBody body = {menv, function->sig, start_, 549 start_ + function->code_start_offset, 550 start_ + function->code_end_offset}; 551 TreeResult result = VerifyWasmCode(module_zone->allocator(), body); 552 if (result.failed()) { 553 // Wrap the error message from the function decoder. 554 std::ostringstream str; 555 str << "in function " << WasmFunctionName(function, menv) << ": "; 556 str << result; 557 std::string strval = str.str(); 558 const char* raw = strval.c_str(); 559 size_t len = strlen(raw); 560 char* buffer = new char[len]; 561 strncpy(buffer, raw, len); 562 buffer[len - 1] = 0; 563 564 // Copy error code and location. 565 result_.CopyFrom(result); 566 result_.error_msg.Reset(buffer); 567 } 568 } 569 570 // Reads a single 32-bit unsigned integer interpreted as an offset, checking 571 // the offset is within bounds and advances. 572 uint32_t consume_offset(const char* name = nullptr) { 573 uint32_t offset = consume_u32(name ? name : "offset"); 574 if (offset > static_cast<uint32_t>(limit_ - start_)) { 575 error(pc_ - sizeof(uint32_t), "offset out of bounds of module"); 576 } 577 return offset; 578 } 579 580 // Reads a length-prefixed string, checking that it is within bounds. Returns 581 // the offset of the string, and the length as an out parameter. 582 uint32_t consume_string(uint32_t* length, bool validate_utf8) { 583 *length = consume_u32v("string length"); 584 uint32_t offset = pc_offset(); 585 TRACE(" +%u %-20s: (%u bytes)\n", offset, "string", *length); 586 if (validate_utf8 && !unibrow::Utf8::Validate(pc_, *length)) { 587 error(pc_, "no valid UTF-8 string"); 588 } 589 consume_bytes(*length); 590 return offset; 591 } 592 593 uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) { 594 const byte* pos = pc_; 595 uint32_t sig_index = consume_u32v("signature index"); 596 if (sig_index >= module->signatures.size()) { 597 error(pos, pos, "signature index %u out of bounds (%d signatures)", 598 sig_index, static_cast<int>(module->signatures.size())); 599 *sig = nullptr; 600 return 0; 601 } 602 *sig = module->signatures[sig_index]; 603 return sig_index; 604 } 605 606 uint32_t consume_func_index(WasmModule* module, WasmFunction** func) { 607 const byte* pos = pc_; 608 uint32_t func_index = consume_u32v("function index"); 609 if (func_index >= module->functions.size()) { 610 error(pos, pos, "function index %u out of bounds (%d functions)", 611 func_index, static_cast<int>(module->functions.size())); 612 *func = nullptr; 613 return 0; 614 } 615 *func = &module->functions[func_index]; 616 return func_index; 617 } 618 619 // Reads a single 8-bit integer, interpreting it as a local type. 620 LocalType consume_local_type() { 621 byte val = consume_u8("local type"); 622 LocalTypeCode t = static_cast<LocalTypeCode>(val); 623 switch (t) { 624 case kLocalVoid: 625 return kAstStmt; 626 case kLocalI32: 627 return kAstI32; 628 case kLocalI64: 629 return kAstI64; 630 case kLocalF32: 631 return kAstF32; 632 case kLocalF64: 633 return kAstF64; 634 default: 635 error(pc_ - 1, "invalid local type"); 636 return kAstStmt; 637 } 638 } 639 640 // Reads a single 8-bit integer, interpreting it as a memory type. 641 MachineType mem_type() { 642 byte val = consume_u8("memory type"); 643 MemTypeCode t = static_cast<MemTypeCode>(val); 644 switch (t) { 645 case kMemI8: 646 return MachineType::Int8(); 647 case kMemU8: 648 return MachineType::Uint8(); 649 case kMemI16: 650 return MachineType::Int16(); 651 case kMemU16: 652 return MachineType::Uint16(); 653 case kMemI32: 654 return MachineType::Int32(); 655 case kMemU32: 656 return MachineType::Uint32(); 657 case kMemI64: 658 return MachineType::Int64(); 659 case kMemU64: 660 return MachineType::Uint64(); 661 case kMemF32: 662 return MachineType::Float32(); 663 case kMemF64: 664 return MachineType::Float64(); 665 case kMemS128: 666 return MachineType::Simd128(); 667 default: 668 error(pc_ - 1, "invalid memory type"); 669 return MachineType::None(); 670 } 671 } 672 673 // Parses a type entry, which is currently limited to functions only. 674 FunctionSig* consume_sig() { 675 const byte* pos = pc_; 676 byte form = consume_u8("type form"); 677 if (form != kWasmFunctionTypeForm) { 678 error(pos, pos, "expected function type form (0x%02x), got: 0x%02x", 679 kWasmFunctionTypeForm, form); 680 return nullptr; 681 } 682 // parse parameter types 683 uint32_t param_count = consume_u32v("param count"); 684 std::vector<LocalType> params; 685 for (uint32_t i = 0; i < param_count; ++i) { 686 LocalType param = consume_local_type(); 687 if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type"); 688 params.push_back(param); 689 } 690 691 // parse return types 692 const byte* pt = pc_; 693 uint32_t return_count = consume_u32v("return count"); 694 if (return_count > kMaxReturnCount) { 695 error(pt, pt, "return count of %u exceeds maximum of %u", return_count, 696 kMaxReturnCount); 697 return nullptr; 698 } 699 std::vector<LocalType> returns; 700 for (uint32_t i = 0; i < return_count; ++i) { 701 LocalType ret = consume_local_type(); 702 if (ret == kAstStmt) error(pc_ - 1, "invalid void return type"); 703 returns.push_back(ret); 704 } 705 706 // FunctionSig stores the return types first. 707 LocalType* buffer = 708 module_zone->NewArray<LocalType>(param_count + return_count); 709 uint32_t b = 0; 710 for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i]; 711 for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i]; 712 713 return new (module_zone) FunctionSig(return_count, param_count, buffer); 714 } 715 }; 716 717 // Helpers for nice error messages. 718 class ModuleError : public ModuleResult { 719 public: 720 explicit ModuleError(const char* msg) { 721 error_code = kError; 722 size_t len = strlen(msg) + 1; 723 char* result = new char[len]; 724 strncpy(result, msg, len); 725 result[len - 1] = 0; 726 error_msg.Reset(result); 727 } 728 }; 729 730 // Helpers for nice error messages. 731 class FunctionError : public FunctionResult { 732 public: 733 explicit FunctionError(const char* msg) { 734 error_code = kError; 735 size_t len = strlen(msg) + 1; 736 char* result = new char[len]; 737 strncpy(result, msg, len); 738 result[len - 1] = 0; 739 error_msg.Reset(result); 740 } 741 }; 742 743 Vector<const byte> FindSection(const byte* module_start, const byte* module_end, 744 WasmSection::Code code) { 745 Decoder decoder(module_start, module_end); 746 747 uint32_t magic_word = decoder.consume_u32("wasm magic"); 748 if (magic_word != kWasmMagic) decoder.error("wrong magic word"); 749 750 uint32_t magic_version = decoder.consume_u32("wasm version"); 751 if (magic_version != kWasmVersion) decoder.error("wrong wasm version"); 752 753 while (decoder.more() && decoder.ok()) { 754 // Read the section name. 755 uint32_t string_length = decoder.consume_u32v("section name length"); 756 const byte* section_name_start = decoder.pc(); 757 decoder.consume_bytes(string_length); 758 if (decoder.failed()) break; 759 760 WasmSection::Code section = 761 WasmSection::lookup(section_name_start, string_length); 762 763 // Read and check the section size. 764 uint32_t section_length = decoder.consume_u32v("section length"); 765 766 const byte* section_start = decoder.pc(); 767 decoder.consume_bytes(section_length); 768 if (section == code && decoder.ok()) { 769 return Vector<const uint8_t>(section_start, section_length); 770 } 771 } 772 773 return Vector<const uint8_t>(); 774 } 775 776 } // namespace 777 778 ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone, 779 const byte* module_start, const byte* module_end, 780 bool verify_functions, ModuleOrigin origin) { 781 size_t decode_memory_start = zone->allocation_size(); 782 HistogramTimerScope wasm_decode_module_time_scope( 783 isolate->counters()->wasm_decode_module_time()); 784 size_t size = module_end - module_start; 785 if (module_start > module_end) return ModuleError("start > end"); 786 if (size >= kMaxModuleSize) return ModuleError("size > maximum module size"); 787 // TODO(bradnelson): Improve histogram handling of size_t. 788 isolate->counters()->wasm_module_size_bytes()->AddSample( 789 static_cast<int>(size)); 790 WasmModule* module = new WasmModule(); 791 ModuleDecoder decoder(zone, module_start, module_end, origin); 792 ModuleResult result = decoder.DecodeModule(module, verify_functions); 793 // TODO(bradnelson): Improve histogram handling of size_t. 794 isolate->counters()->wasm_decode_module_peak_memory_bytes()->AddSample( 795 static_cast<int>(zone->allocation_size() - decode_memory_start)); 796 return result; 797 } 798 799 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start, 800 const byte* end) { 801 ModuleDecoder decoder(zone, start, end, kWasmOrigin); 802 return decoder.DecodeFunctionSignature(start); 803 } 804 805 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone, 806 ModuleEnv* module_env, 807 const byte* function_start, 808 const byte* function_end) { 809 HistogramTimerScope wasm_decode_function_time_scope( 810 isolate->counters()->wasm_decode_function_time()); 811 size_t size = function_end - function_start; 812 if (function_start > function_end) return FunctionError("start > end"); 813 if (size > kMaxFunctionSize) 814 return FunctionError("size > maximum function size"); 815 isolate->counters()->wasm_function_size_bytes()->AddSample( 816 static_cast<int>(size)); 817 WasmFunction* function = new WasmFunction(); 818 ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin); 819 return decoder.DecodeSingleFunction(module_env, function); 820 } 821 822 FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start, 823 const byte* module_end) { 824 Vector<const byte> code_section = 825 FindSection(module_start, module_end, WasmSection::Code::FunctionBodies); 826 Decoder decoder(code_section.start(), code_section.end()); 827 if (!code_section.start()) decoder.error("no code section"); 828 829 uint32_t functions_count = decoder.consume_u32v("functions count"); 830 FunctionOffsets table; 831 // Take care of invalid input here. 832 if (functions_count < static_cast<unsigned>(code_section.length()) / 2) 833 table.reserve(functions_count); 834 int section_offset = static_cast<int>(code_section.start() - module_start); 835 DCHECK_LE(0, section_offset); 836 for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { 837 uint32_t size = decoder.consume_u32v("body size"); 838 int offset = static_cast<int>(section_offset + decoder.pc_offset()); 839 table.push_back(std::make_pair(offset, static_cast<int>(size))); 840 DCHECK(table.back().first >= 0 && table.back().second >= 0); 841 decoder.consume_bytes(size); 842 } 843 if (decoder.more()) decoder.error("unexpected additional bytes"); 844 845 return decoder.toResult(std::move(table)); 846 } 847 848 } // namespace wasm 849 } // namespace internal 850 } // namespace v8 851