module-decoder.cc 68.8 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

jfb's avatar
jfb committed
5 6 7 8
#include "src/wasm/module-decoder.h"

#include "src/base/functional.h"
#include "src/base/platform/platform.h"
9
#include "src/base/template-utils.h"
10
#include "src/counters.h"
11
#include "src/flags.h"
12
#include "src/macro-assembler.h"
13 14
#include "src/objects-inl.h"
#include "src/ostreams.h"
15 16
#include "src/v8.h"
#include "src/wasm/decoder.h"
17
#include "src/wasm/function-body-decoder-impl.h"
18
#include "src/wasm/wasm-engine.h"
19
#include "src/wasm/wasm-limits.h"
20 21 22 23 24 25 26 27 28

namespace v8 {
namespace internal {
namespace wasm {

#define TRACE(...)                                    \
  do {                                                \
    if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
  } while (false)
29

30 31
namespace {

32
constexpr char kNameString[] = "name";
33
constexpr char kSourceMappingURLString[] = "sourceMappingURL";
34 35 36 37 38 39

template <size_t N>
constexpr size_t num_chars(const char (&)[N]) {
  return N - 1;  // remove null character at end.
}

40 41 42 43 44 45 46 47 48 49
const char* ExternalKindName(ImportExportKindCode kind) {
  switch (kind) {
    case kExternalFunction:
      return "function";
    case kExternalTable:
      return "table";
    case kExternalMemory:
      return "memory";
    case kExternalGlobal:
      return "global";
50 51
    case kExternalException:
      return "exception";
52 53 54 55
  }
  return "unknown";
}

56
}  // namespace
57

58
const char* SectionName(SectionCode code) {
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
  switch (code) {
    case kUnknownSectionCode:
      return "Unknown";
    case kTypeSectionCode:
      return "Type";
    case kImportSectionCode:
      return "Import";
    case kFunctionSectionCode:
      return "Function";
    case kTableSectionCode:
      return "Table";
    case kMemorySectionCode:
      return "Memory";
    case kGlobalSectionCode:
      return "Global";
    case kExportSectionCode:
      return "Export";
    case kStartSectionCode:
      return "Start";
    case kCodeSectionCode:
      return "Code";
    case kElementSectionCode:
      return "Element";
    case kDataSectionCode:
      return "Data";
84 85
    case kExceptionSectionCode:
      return "Exception";
86 87
    case kDataCountSectionCode:
      return "DataCount";
88
    case kNameSectionCode:
89
      return kNameString;
90 91
    case kSourceMappingURLSectionCode:
      return kSourceMappingURLString;
92
    default:
93
      return "<unknown>";
94 95 96
  }
}

97 98
namespace {

99 100 101 102 103 104
bool validate_utf8(Decoder* decoder, WireBytesRef string) {
  return unibrow::Utf8::ValidateEncoding(
      decoder->start() + decoder->GetBufferRelativeOffset(string.offset()),
      string.length());
}

105
ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
106 107
  switch (expr.kind) {
    case WasmInitExpr::kNone:
108
      return kWasmStmt;
109 110 111
    case WasmInitExpr::kGlobalIndex:
      return expr.val.global_index < module->globals.size()
                 ? module->globals[expr.val.global_index].type
112
                 : kWasmStmt;
113
    case WasmInitExpr::kI32Const:
114
      return kWasmI32;
115
    case WasmInitExpr::kI64Const:
116
      return kWasmI64;
117
    case WasmInitExpr::kF32Const:
118
      return kWasmF32;
119
    case WasmInitExpr::kF64Const:
120
      return kWasmF64;
121 122
    case WasmInitExpr::kAnyRefConst:
      return kWasmAnyRef;
123 124 125 126 127
    default:
      UNREACHABLE();
  }
}

128 129
// Reads a length-prefixed string, checking that it is within bounds. Returns
// the offset of the string, and the length as an out parameter.
130 131 132
WireBytesRef consume_string(Decoder& decoder, bool validate_utf8,
                            const char* name) {
  uint32_t length = decoder.consume_u32v("string length");
133 134 135
  uint32_t offset = decoder.pc_offset();
  const byte* string_start = decoder.pc();
  // Consume bytes before validation to guarantee that the string is not oob.
136 137
  if (length > 0) {
    decoder.consume_bytes(length, name);
138
    if (decoder.ok() && validate_utf8 &&
139
        !unibrow::Utf8::ValidateEncoding(string_start, length)) {
140
      decoder.errorf(string_start, "%s: no valid UTF-8 string", name);
141 142
    }
  }
143
  return {offset, decoder.failed() ? 0 : length};
144 145
}

146
// An iterator over the sections in a wasm binary module.
147 148 149 150 151 152 153 154 155 156 157
// Automatically skips all unknown sections.
class WasmSectionIterator {
 public:
  explicit WasmSectionIterator(Decoder& decoder)
      : decoder_(decoder),
        section_code_(kUnknownSectionCode),
        section_start_(decoder.pc()),
        section_end_(decoder.pc()) {
    next();
  }

158
  inline bool more() const { return decoder_.ok() && decoder_.more(); }
159

160
  inline SectionCode section_code() const { return section_code_; }
161 162 163 164 165 166 167

  inline const byte* section_start() const { return section_start_; }

  inline uint32_t section_length() const {
    return static_cast<uint32_t>(section_end_ - section_start_);
  }

168 169 170 171
  inline Vector<const uint8_t> payload() const {
    return {payload_start_, payload_length()};
  }

172 173 174 175 176 177
  inline const byte* payload_start() const { return payload_start_; }

  inline uint32_t payload_length() const {
    return static_cast<uint32_t>(section_end_ - payload_start_);
  }

178 179 180 181
  inline const byte* section_end() const { return section_end_; }

  // Advances to the next section, checking that decoding the current section
  // stopped at {section_end_}.
182 183 184 185 186
  void advance(bool move_to_section_end = false) {
    if (move_to_section_end && decoder_.pc() < section_end_) {
      decoder_.consume_bytes(
          static_cast<uint32_t>(section_end_ - decoder_.pc()));
    }
187 188
    if (decoder_.pc() != section_end_) {
      const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
189 190 191 192 193
      decoder_.errorf(decoder_.pc(),
                      "section was %s than expected size "
                      "(%u bytes expected, %zu decoded)",
                      msg, section_length(),
                      static_cast<size_t>(decoder_.pc() - section_start_));
194 195 196 197 198 199
    }
    next();
  }

 private:
  Decoder& decoder_;
200
  SectionCode section_code_;
201
  const byte* section_start_;
202
  const byte* payload_start_;
203 204 205
  const byte* section_end_;

  // Reads the section code/name at the current position and sets up
206
  // the embedder fields.
207
  void next() {
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
    if (!decoder_.more()) {
      section_code_ = kUnknownSectionCode;
      return;
    }
    section_start_ = decoder_.pc();
    uint8_t section_code = decoder_.consume_u8("section code");
    // Read and check the section size.
    uint32_t section_length = decoder_.consume_u32v("section length");

    payload_start_ = decoder_.pc();
    if (decoder_.checkAvailable(section_length)) {
      // Get the limit of the section within the module.
      section_end_ = payload_start_ + section_length;
    } else {
      // The section would extend beyond the end of the module.
      section_end_ = payload_start_;
    }

    if (section_code == kUnknownSectionCode) {
227
      // Check for the known "name" or "sourceMappingURL" section.
228 229 230 231
      section_code =
          ModuleDecoder::IdentifyUnknownSection(decoder_, section_end_);
      // As a side effect, the above function will forward the decoder to after
      // the identifier string.
232 233
      payload_start_ = decoder_.pc();
    } else if (!IsValidSectionCode(section_code)) {
234 235
      decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
                      section_code);
236 237 238 239 240 241 242 243 244
      section_code = kUnknownSectionCode;
    }
    section_code_ = decoder_.failed() ? kUnknownSectionCode
                                      : static_cast<SectionCode>(section_code);

    if (section_code_ == kUnknownSectionCode && section_end_ > decoder_.pc()) {
      // skip to the end of the unknown section.
      uint32_t remaining = static_cast<uint32_t>(section_end_ - decoder_.pc());
      decoder_.consume_bytes(remaining, "section payload");
245 246 247 248
    }
  }
};

249 250
}  // namespace

251
// The main logic for decoding the bytes of a module.
252
class ModuleDecoderImpl : public Decoder {
253
 public:
254
  explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin)
255
      : Decoder(nullptr, nullptr),
256
        enabled_features_(enabled),
257 258
        origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}

259 260
  ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
                    const byte* module_end, ModuleOrigin origin)
261
      : Decoder(module_start, module_end),
262
        enabled_features_(enabled),
263
        origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
264
    if (end_ < start_) {
265
      error(start_, "end is less than start");
266
      end_ = start_;
267 268 269
    }
  }

270
  void onFirstError() override {
271
    pc_ = end_;  // On error, terminate section decoding loop.
272 273
  }

274
  void DumpModule(const Vector<const byte> module_bytes) {
jfb's avatar
jfb committed
275 276 277 278 279 280 281 282 283
    std::string path;
    if (FLAG_dump_wasm_module_path) {
      path = FLAG_dump_wasm_module_path;
      if (path.size() &&
          !base::OS::isDirectorySeparator(path[path.size() - 1])) {
        path += base::OS::DirectorySeparator();
      }
    }
    // File are named `HASH.{ok,failed}.wasm`.
284
    size_t hash = base::hash_range(module_bytes.start(), module_bytes.end());
285
    EmbeddedVector<char, 32> buf;
286
    SNPrintF(buf, "%016zx.%s.wasm", hash, ok() ? "ok" : "failed");
287
    std::string name(buf.start());
jfb's avatar
jfb committed
288
    if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
289 290
      if (fwrite(module_bytes.start(), module_bytes.length(), 1, wasm_file) !=
          1) {
291 292 293
        OFStream os(stderr);
        os << "Error while dumping wasm file" << std::endl;
      }
jfb's avatar
jfb committed
294 295 296 297
      fclose(wasm_file);
    }
  }

298
  void StartDecoding(Counters* counters, AccountingAllocator* allocator) {
299
    CHECK_NULL(module_);
300 301 302
    SetCounters(counters);
    module_.reset(
        new WasmModule(base::make_unique<Zone>(allocator, "signatures")));
303 304
    module_->initial_pages = 0;
    module_->maximum_pages = 0;
305
    module_->mem_export = false;
306
    module_->origin = origin_;
307 308 309 310 311
  }

  void DecodeModuleHeader(Vector<const uint8_t> bytes, uint8_t offset) {
    if (failed()) return;
    Reset(bytes, offset);
312

313 314
    const byte* pos = pc_;
    uint32_t magic_word = consume_u32("wasm magic");
315
#define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF
316
    if (magic_word != kWasmMagic) {
317 318 319 320
      errorf(pos,
             "expected magic word %02x %02x %02x %02x, "
             "found %02x %02x %02x %02x",
             BYTES(kWasmMagic), BYTES(magic_word));
321 322 323
    }

    pos = pc_;
jfb's avatar
jfb committed
324 325
    {
      uint32_t magic_version = consume_u32("wasm version");
326
      if (magic_version != kWasmVersion) {
327 328 329 330
        errorf(pos,
               "expected version %02x %02x %02x %02x, "
               "found %02x %02x %02x %02x",
               BYTES(kWasmVersion), BYTES(magic_version));
jfb's avatar
jfb committed
331
      }
332
    }
333
#undef BYTES
334
  }
335

336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
  bool CheckSectionOrder(SectionCode section_code,
                         SectionCode prev_section_code,
                         SectionCode next_section_code) {
    if (next_ordered_section_ > next_section_code) {
      errorf(pc(), "The %s section must appear before the %s section",
             SectionName(section_code), SectionName(next_section_code));
      return false;
    }
    if (next_ordered_section_ <= prev_section_code) {
      next_ordered_section_ = prev_section_code + 1;
    }
    return true;
  }

  bool CheckUnorderedSection(SectionCode section_code) {
    if (has_seen_unordered_section(section_code)) {
      errorf(pc(), "Multiple %s sections not allowed",
             SectionName(section_code));
      return false;
    }
    set_seen_unordered_section(section_code);

    switch (section_code) {
      case kDataCountSectionCode:
        return CheckSectionOrder(section_code, kElementSectionCode,
                                 kCodeSectionCode);
      case kExceptionSectionCode:
363
        return CheckSectionOrder(section_code, kGlobalSectionCode,
364 365 366 367 368 369
                                 kExportSectionCode);
      default:
        UNREACHABLE();
    }
  }

370 371 372 373
  void DecodeSection(SectionCode section_code, Vector<const uint8_t> bytes,
                     uint32_t offset, bool verify_functions = true) {
    if (failed()) return;
    Reset(bytes, offset);
374
    TRACE("Section: %s\n", SectionName(section_code));
375 376
    TRACE("Decode Section %p - %p\n", static_cast<const void*>(bytes.begin()),
          static_cast<const void*>(bytes.end()));
377 378

    // Check if the section is out-of-order.
379 380
    if (section_code < next_ordered_section_ &&
        section_code < kFirstUnorderedSection) {
381
      errorf(pc(), "unexpected section: %s", SectionName(section_code));
382 383
      return;
    }
384 385 386 387

    switch (section_code) {
      case kUnknownSectionCode:
        break;
388
      case kDataCountSectionCode:
389
      case kExceptionSectionCode:
390 391 392 393
        // Note: These sections have a section code that is numerically
        // out-of-order with respect to their required location. So they are
        // treated as a special case.
        if (!CheckUnorderedSection(section_code)) return;
394
        break;
395 396 397 398
      case kSourceMappingURLSectionCode:
        // sourceMappingURL is a custom section and currently can occur anywhere
        // in the module. In case of multiple sourceMappingURL sections, all
        // except the first occurrence are ignored.
399 400 401 402
      case kNameSectionCode:
        // TODO(titzer): report out of place name section as a warning.
        // Be lenient with placement of name section. All except first
        // occurrence are ignored.
403
        break;
404
      default:
405
        next_ordered_section_ = section_code + 1;
406
        break;
407
    }
408

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
    switch (section_code) {
      case kUnknownSectionCode:
        break;
      case kTypeSectionCode:
        DecodeTypeSection();
        break;
      case kImportSectionCode:
        DecodeImportSection();
        break;
      case kFunctionSectionCode:
        DecodeFunctionSection();
        break;
      case kTableSectionCode:
        DecodeTableSection();
        break;
      case kMemorySectionCode:
        DecodeMemorySection();
        break;
      case kGlobalSectionCode:
        DecodeGlobalSection();
        break;
      case kExportSectionCode:
        DecodeExportSection();
        break;
      case kStartSectionCode:
        DecodeStartSection();
        break;
      case kCodeSectionCode:
        DecodeCodeSection(verify_functions);
        break;
      case kElementSectionCode:
        DecodeElementSection();
        break;
      case kDataSectionCode:
        DecodeDataSection();
        break;
      case kNameSectionCode:
        DecodeNameSection();
        break;
448 449 450
      case kSourceMappingURLSectionCode:
        DecodeSourceMappingURLSection();
        break;
451 452 453 454 455 456 457
      case kDataCountSectionCode:
        if (enabled_features_.bulk_memory) {
          DecodeDataCountSection();
        } else {
          errorf(pc(), "unexpected section: %s", SectionName(section_code));
        }
        break;
458
      case kExceptionSectionCode:
459
        if (enabled_features_.eh) {
460 461 462 463
          DecodeExceptionSection();
        } else {
          errorf(pc(), "unexpected section: %s", SectionName(section_code));
        }
464
        break;
465
      default:
466
        errorf(pc(), "unexpected section: %s", SectionName(section_code));
467 468 469 470 471
        return;
    }

    if (pc() != bytes.end()) {
      const char* msg = pc() < bytes.end() ? "shorter" : "longer";
472 473 474 475
      errorf(pc(),
             "section was %s than expected size "
             "(%zu bytes expected, %zu decoded)",
             msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin()));
476 477 478 479 480 481 482 483 484 485 486
    }
  }

  void DecodeTypeSection() {
    uint32_t signatures_count = consume_count("types count", kV8MaxWasmTypes);
    module_->signatures.reserve(signatures_count);
    for (uint32_t i = 0; ok() && i < signatures_count; ++i) {
      TRACE("DecodeSignature[%d] module+%d\n", i,
            static_cast<int>(pc_ - start_));
      FunctionSig* s = consume_sig(module_->signature_zone.get());
      module_->signatures.push_back(s);
487
      uint32_t id = s ? module_->signature_map.FindOrInsert(*s) : 0;
488
      module_->signature_ids.push_back(id);
489
    }
490
    module_->signature_map.Freeze();
491 492 493 494 495 496 497 498 499 500 501
  }

  void DecodeImportSection() {
    uint32_t import_table_count =
        consume_count("imports count", kV8MaxWasmImports);
    module_->import_table.reserve(import_table_count);
    for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
      TRACE("DecodeImportTable[%d] module+%d\n", i,
            static_cast<int>(pc_ - start_));

      module_->import_table.push_back({
502 503
          {0, 0},             // module_name
          {0, 0},             // field_name
504 505 506 507 508
          kExternalFunction,  // kind
          0                   // index
      });
      WasmImport* import = &module_->import_table.back();
      const byte* pos = pc_;
509 510
      import->module_name = consume_string(*this, true, "module name");
      import->field_name = consume_string(*this, true, "field name");
511 512
      import->kind =
          static_cast<ImportExportKindCode>(consume_u8("import kind"));
513 514 515 516 517 518 519 520
      switch (import->kind) {
        case kExternalFunction: {
          // ===== Imported function =======================================
          import->index = static_cast<uint32_t>(module_->functions.size());
          module_->num_imported_functions++;
          module_->functions.push_back({nullptr,        // sig
                                        import->index,  // func_index
                                        0,              // sig_index
521
                                        {0, 0},         // code
522 523 524 525 526 527 528 529 530 531
                                        true,           // imported
                                        false});        // exported
          WasmFunction* function = &module_->functions.back();
          function->sig_index =
              consume_sig_index(module_.get(), &function->sig);
          break;
        }
        case kExternalTable: {
          // ===== Imported table ==========================================
          if (!AddTable(module_.get())) break;
532 533 534
          import->index = static_cast<uint32_t>(module_->tables.size());
          module_->tables.emplace_back();
          WasmTable* table = &module_->tables.back();
535
          table->imported = true;
536
          ValueType type = consume_reference_type();
537
          if (!enabled_features_.anyref) {
538 539 540 541 542 543
            if (type != kWasmAnyFunc) {
              error(pc_ - 1, "invalid table type");
              break;
            }
          }
          table->type = type;
544
          uint8_t flags = validate_table_flags("element count");
545 546 547
          consume_resizable_limits(
              "element count", "elements", FLAG_wasm_max_table_size,
              &table->initial_size, &table->has_maximum_size,
548
              FLAG_wasm_max_table_size, &table->maximum_size, flags);
549 550 551 552 553
          break;
        }
        case kExternalMemory: {
          // ===== Imported memory =========================================
          if (!AddMemory(module_.get())) break;
554
          uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
555
          consume_resizable_limits(
556
              "memory", "pages", kSpecMaxWasmMemoryPages,
557
              &module_->initial_pages, &module_->has_maximum_pages,
558
              kSpecMaxWasmMemoryPages, &module_->maximum_pages, flags);
559 560 561 562 563 564
          break;
        }
        case kExternalGlobal: {
          // ===== Imported global =========================================
          import->index = static_cast<uint32_t>(module_->globals.size());
          module_->globals.push_back(
565
              {kWasmStmt, false, WasmInitExpr(), {0}, true, false});
566 567 568
          WasmGlobal* global = &module_->globals.back();
          global->type = consume_value_type();
          global->mutability = consume_mutability();
569
          if (global->mutability) {
570
            if (enabled_features_.mut_global) {
571 572 573 574
              module_->num_imported_mutable_globals++;
            } else {
              error("mutable globals cannot be imported");
            }
575
          }
576
          break;
577
        }
578 579 580 581 582 583 584
        case kExternalException: {
          // ===== Imported exception ======================================
          if (!enabled_features_.eh) {
            errorf(pos, "unknown import kind 0x%02x", import->kind);
            break;
          }
          import->index = static_cast<uint32_t>(module_->exceptions.size());
585
          WasmExceptionSig* exception_sig = nullptr;
586
          consume_exception_attribute();  // Attribute ignored for now.
587 588
          consume_exception_sig_index(module_.get(), &exception_sig);
          module_->exceptions.emplace_back(exception_sig);
589 590
          break;
        }
591
        default:
592
          errorf(pos, "unknown import kind 0x%02x", import->kind);
593
          break;
594 595
      }
    }
596
  }
597

598 599 600
  void DecodeFunctionSection() {
    uint32_t functions_count =
        consume_count("functions count", kV8MaxWasmFunctions);
601 602 603
    auto counter =
        SELECT_WASM_COUNTER(GetCounters(), origin_, wasm_functions_per, module);
    counter->AddSample(static_cast<int>(functions_count));
604 605 606 607
    DCHECK_EQ(module_->functions.size(), module_->num_imported_functions);
    uint32_t total_function_count =
        module_->num_imported_functions + functions_count;
    module_->functions.reserve(total_function_count);
608
    module_->num_declared_functions = functions_count;
609
    for (uint32_t i = 0; i < functions_count; ++i) {
610 611 612 613
      uint32_t func_index = static_cast<uint32_t>(module_->functions.size());
      module_->functions.push_back({nullptr,     // sig
                                    func_index,  // func_index
                                    0,           // sig_index
614
                                    {0, 0},      // code
615 616 617 618
                                    false,       // imported
                                    false});     // exported
      WasmFunction* function = &module_->functions.back();
      function->sig_index = consume_sig_index(module_.get(), &function->sig);
619
      if (!ok()) return;
620
    }
621
    DCHECK_EQ(module_->functions.size(), total_function_count);
622
  }
623

624
  void DecodeTableSection() {
625 626
    // TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
    // implementation of AnyRef landed.
627
    uint32_t max_count = enabled_features_.anyref ? 10 : kV8MaxWasmTables;
628
    uint32_t table_count = consume_count("table count", max_count);
629 630 631

    for (uint32_t i = 0; ok() && i < table_count; i++) {
      if (!AddTable(module_.get())) break;
632 633 634
      module_->tables.emplace_back();
      WasmTable* table = &module_->tables.back();
      table->type = consume_reference_type();
635 636 637 638 639
      uint8_t flags = validate_table_flags("table elements");
      consume_resizable_limits(
          "table elements", "elements", FLAG_wasm_max_table_size,
          &table->initial_size, &table->has_maximum_size,
          FLAG_wasm_max_table_size, &table->maximum_size, flags);
640
    }
641
  }
642

643 644
  void DecodeMemorySection() {
    uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
645

646 647
    for (uint32_t i = 0; ok() && i < memory_count; i++) {
      if (!AddMemory(module_.get())) break;
648
      uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
649
      consume_resizable_limits(
650
          "memory", "pages", kSpecMaxWasmMemoryPages, &module_->initial_pages,
651
          &module_->has_maximum_pages, kSpecMaxWasmMemoryPages,
652
          &module_->maximum_pages, flags);
653
    }
654
  }
655

656 657 658 659 660 661 662 663
  void DecodeGlobalSection() {
    uint32_t globals_count = consume_count("globals count", kV8MaxWasmGlobals);
    uint32_t imported_globals = static_cast<uint32_t>(module_->globals.size());
    module_->globals.reserve(imported_globals + globals_count);
    for (uint32_t i = 0; ok() && i < globals_count; ++i) {
      TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
      // Add an uninitialized global and pass a pointer to it.
      module_->globals.push_back(
664
          {kWasmStmt, false, WasmInitExpr(), {0}, false, false});
665 666
      WasmGlobal* global = &module_->globals.back();
      DecodeGlobalInModule(module_.get(), i + imported_globals, global);
667
    }
668
    if (ok()) CalculateGlobalOffsets(module_.get());
669
  }
670

671 672
  void DecodeExportSection() {
    uint32_t export_table_count =
673
        consume_count("exports count", kV8MaxWasmExports);
674 675 676 677 678 679
    module_->export_table.reserve(export_table_count);
    for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
      TRACE("DecodeExportTable[%d] module+%d\n", i,
            static_cast<int>(pc_ - start_));

      module_->export_table.push_back({
680
          {0, 0},             // name
681 682 683 684 685
          kExternalFunction,  // kind
          0                   // index
      });
      WasmExport* exp = &module_->export_table.back();

686
      exp->name = consume_string(*this, true, "field name");
687 688

      const byte* pos = pc();
689
      exp->kind = static_cast<ImportExportKindCode>(consume_u8("export kind"));
690 691 692 693 694 695 696
      switch (exp->kind) {
        case kExternalFunction: {
          WasmFunction* func = nullptr;
          exp->index = consume_func_index(module_.get(), &func);
          module_->num_exported_functions++;
          if (func) func->exported = true;
          break;
697
        }
698
        case kExternalTable: {
699
          WasmTable* table = nullptr;
700 701 702 703 704 705 706 707 708
          exp->index = consume_table_index(module_.get(), &table);
          if (table) table->exported = true;
          break;
        }
        case kExternalMemory: {
          uint32_t index = consume_u32v("memory index");
          // TODO(titzer): This should become more regular
          // once we support multiple memories.
          if (!module_->has_memory || index != 0) {
709
            error("invalid memory index != 0");
710
          }
711 712 713 714 715 716 717
          module_->mem_export = true;
          break;
        }
        case kExternalGlobal: {
          WasmGlobal* global = nullptr;
          exp->index = consume_global_index(module_.get(), &global);
          if (global) {
718
            if (!enabled_features_.mut_global && global->mutability) {
719
              error("mutable globals cannot be exported");
720 721
            }
            global->exported = true;
722
          }
723
          break;
724
        }
725 726 727 728 729 730 731 732 733
        case kExternalException: {
          if (!enabled_features_.eh) {
            errorf(pos, "invalid export kind 0x%02x", exp->kind);
            break;
          }
          WasmException* exception = nullptr;
          exp->index = consume_exception_index(module_.get(), &exception);
          break;
        }
734
        default:
735
          errorf(pos, "invalid export kind 0x%02x", exp->kind);
736
          break;
737
      }
738
    }
739 740 741 742 743 744
    // Check for duplicate exports (except for asm.js).
    if (ok() && origin_ != kAsmJsOrigin && module_->export_table.size() > 1) {
      std::vector<WasmExport> sorted_exports(module_->export_table);

      auto cmp_less = [this](const WasmExport& a, const WasmExport& b) {
        // Return true if a < b.
745 746
        if (a.name.length() != b.name.length()) {
          return a.name.length() < b.name.length();
747
        }
748 749 750
        const byte* left = start() + GetBufferRelativeOffset(a.name.offset());
        const byte* right = start() + GetBufferRelativeOffset(b.name.offset());
        return memcmp(left, right, a.name.length()) < 0;
751 752 753 754 755 756 757 758
      };
      std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less);

      auto it = sorted_exports.begin();
      WasmExport* last = &*it++;
      for (auto end = sorted_exports.end(); it != end; last = &*it++) {
        DCHECK(!cmp_less(*it, *last));  // Vector must be sorted.
        if (!cmp_less(*last, *it)) {
759
          const byte* pc = start() + GetBufferRelativeOffset(it->name.offset());
760
          TruncatedUserString<> name(pc, it->name.length());
761
          errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d",
762
                 name.length(), name.start(), ExternalKindName(last->kind),
763
                 last->index, ExternalKindName(it->kind), it->index);
764
          break;
765
        }
766
      }
767 768
    }
  }
769

770 771 772 773 774 775
  void DecodeStartSection() {
    WasmFunction* func;
    const byte* pos = pc_;
    module_->start_function_index = consume_func_index(module_.get(), &func);
    if (func &&
        (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
776
      error(pos, "invalid start function: non-zero parameter or return count");
777
    }
778
  }
779

780 781 782
  void DecodeElementSection() {
    uint32_t element_count =
        consume_count("element count", FLAG_wasm_max_table_size);
783

784
    if (element_count > 0 && module_->tables.size() == 0) {
785 786
      error(pc_, "The element section requires a table");
    }
787 788
    for (uint32_t i = 0; ok() && i < element_count; ++i) {
      const byte* pos = pc();
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806

      bool is_active;
      uint32_t table_index;
      WasmInitExpr offset;
      consume_segment_header("table index", &is_active, &table_index, &offset);
      if (failed()) return;

      if (is_active) {
        if (table_index >= module_->tables.size()) {
          errorf(pos, "out of bounds table index %u", table_index);
          break;
        }
        if (module_->tables[table_index].type != kWasmAnyFunc) {
          errorf(pos,
                 "Invalid element segment. Table %u is not of type AnyFunc",
                 table_index);
          break;
        }
807
      }
808

809 810
      uint32_t num_elem =
          consume_count("number of elements", kV8MaxWasmTableEntries);
811 812 813 814 815 816
      if (is_active) {
        module_->table_inits.emplace_back(table_index, offset);
      } else {
        module_->table_inits.emplace_back();
      }

817
      WasmTableInit* init = &module_->table_inits.back();
818
      for (uint32_t j = 0; j < num_elem; j++) {
819 820
        WasmFunction* func = nullptr;
        uint32_t index = consume_func_index(module_.get(), &func);
821 822
        DCHECK_IMPLIES(ok(), func != nullptr);
        if (!ok()) break;
823 824
        DCHECK_EQ(index, func->func_index);
        init->entries.push_back(index);
825 826
      }
    }
827
  }
828

829
  void DecodeCodeSection(bool verify_functions) {
830
    uint32_t pos = pc_offset();
831
    uint32_t functions_count = consume_u32v("functions count");
832 833
    CheckFunctionsCount(functions_count, pos);
    for (uint32_t i = 0; ok() && i < functions_count; ++i) {
834
      const byte* pos = pc();
835
      uint32_t size = consume_u32v("body size");
836 837 838 839 840
      if (size > kV8MaxWasmFunctionSize) {
        errorf(pos, "size %u > maximum function size %zu", size,
               kV8MaxWasmFunctionSize);
        return;
      }
841
      uint32_t offset = pc_offset();
842
      consume_bytes(size, "function body");
843
      if (failed()) break;
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
      DecodeFunctionBody(i, size, offset, verify_functions);
    }
  }

  bool CheckFunctionsCount(uint32_t functions_count, uint32_t offset) {
    if (functions_count != module_->num_declared_functions) {
      Reset(nullptr, nullptr, offset);
      errorf(nullptr, "function body count %u mismatch (%u expected)",
             functions_count, module_->num_declared_functions);
      return false;
    }
    return true;
  }

  void DecodeFunctionBody(uint32_t index, uint32_t length, uint32_t offset,
                          bool verify_functions) {
    WasmFunction* function =
        &module_->functions[index + module_->num_imported_functions];
    function->code = {offset, length};
    if (verify_functions) {
      ModuleWireBytes bytes(start_, end_);
      VerifyFunctionBody(module_->signature_zone->allocator(),
                         index + module_->num_imported_functions, bytes,
                         module_.get(), function);
868
    }
869
  }
870

871 872
  bool CheckDataSegmentsCount(uint32_t data_segments_count) {
    if (has_seen_unordered_section(kDataCountSectionCode) &&
873
        data_segments_count != module_->num_declared_data_segments) {
874
      errorf(pc(), "data segments count %u mismatch (%u expected)",
875
             data_segments_count, module_->num_declared_data_segments);
876 877 878 879 880
      return false;
    }
    return true;
  }

881 882 883
  void DecodeDataSection() {
    uint32_t data_segments_count =
        consume_count("data segments count", kV8MaxWasmDataSegments);
884 885
    if (!CheckDataSegmentsCount(data_segments_count)) return;

886 887
    module_->data_segments.reserve(data_segments_count);
    for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
888
      const byte* pos = pc();
889
      if (!module_->has_memory) {
890
        error("cannot load data without memory");
891
        break;
892
      }
893 894
      TRACE("DecodeDataSegment[%d] module+%d\n", i,
            static_cast<int>(pc_ - start_));
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916

      bool is_active;
      uint32_t memory_index;
      WasmInitExpr dest_addr;
      consume_segment_header("memory index", &is_active, &memory_index,
                             &dest_addr);
      if (failed()) break;

      if (is_active && memory_index != 0) {
        errorf(pos, "illegal memory index %u != 0", memory_index);
        break;
      }

      uint32_t source_length = consume_u32v("source size");
      uint32_t source_offset = pc_offset();

      if (is_active) {
        module_->data_segments.emplace_back(dest_addr);
      } else {
        module_->data_segments.emplace_back();
      }

917
      WasmDataSegment* segment = &module_->data_segments.back();
918 919 920 921 922

      consume_bytes(source_length, "segment data");
      if (failed()) break;

      segment->source = {source_offset, source_length};
923
    }
924
  }
925

926 927
  void DecodeNameSection() {
    // TODO(titzer): find a way to report name errors as warnings.
928
    // ignore all but the first occurrence of name section.
929 930
    if (!has_seen_unordered_section(kNameSectionCode)) {
      set_seen_unordered_section(kNameSectionCode);
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
      // Use an inner decoder so that errors don't fail the outer decoder.
      Decoder inner(start_, pc_, end_, buffer_offset_);
      // Decode all name subsections.
      // Be lenient with their order.
      while (inner.ok() && inner.more()) {
        uint8_t name_type = inner.consume_u8("name type");
        if (name_type & 0x80) inner.error("name type if not varuint7");

        uint32_t name_payload_len = inner.consume_u32v("name payload length");
        if (!inner.checkAvailable(name_payload_len)) break;

        // Decode module name, ignore the rest.
        // Function and local names will be decoded when needed.
        if (name_type == NameSectionKindCode::kModule) {
          WireBytesRef name = consume_string(inner, false, "module name");
          if (inner.ok() && validate_utf8(&inner, name)) module_->name = name;
        } else {
          inner.consume_bytes(name_payload_len, "name subsection payload");
        }
950
      }
951
    }
952 953 954
    // Skip the whole names section in the outer decoder.
    consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
  }
955

956 957 958
  void DecodeSourceMappingURLSection() {
    Decoder inner(start_, pc_, end_, buffer_offset_);
    WireBytesRef url = wasm::consume_string(inner, true, "module name");
959
    if (inner.ok() &&
960
        !has_seen_unordered_section(kSourceMappingURLSectionCode)) {
961 962 963 964
      const byte* url_start =
          inner.start() + inner.GetBufferRelativeOffset(url.offset());
      module_->source_map_url.assign(reinterpret_cast<const char*>(url_start),
                                     url.length());
965
      set_seen_unordered_section(kSourceMappingURLSectionCode);
966 967 968 969
    }
    consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
  }

970
  void DecodeDataCountSection() {
971
    module_->num_declared_data_segments =
972 973 974
        consume_count("data segments count", kV8MaxWasmDataSegments);
  }

975 976 977 978
  void DecodeExceptionSection() {
    uint32_t exception_count =
        consume_count("exception count", kV8MaxWasmExceptions);
    for (uint32_t i = 0; ok() && i < exception_count; ++i) {
979
      TRACE("DecodeException[%d] module+%d\n", i,
980
            static_cast<int>(pc_ - start_));
981
      WasmExceptionSig* exception_sig = nullptr;
982
      consume_exception_attribute();  // Attribute ignored for now.
983 984
      consume_exception_sig_index(module_.get(), &exception_sig);
      module_->exceptions.emplace_back(exception_sig);
985 986 987
    }
  }

988 989 990 991 992 993 994 995 996 997 998 999
  bool CheckMismatchedCounts() {
    // The declared vs. defined function count is normally checked when
    // decoding the code section, but we have to check it here too in case the
    // code section is absent.
    if (module_->num_declared_functions != 0) {
      DCHECK_LT(module_->num_imported_functions, module_->functions.size());
      // We know that the code section has been decoded if the first
      // non-imported function has its code set.
      if (!module_->functions[module_->num_imported_functions].code.is_set()) {
        errorf(pc(), "function count is %u, but code section is absent",
               module_->num_declared_functions);
        return false;
1000
      }
1001 1002 1003 1004 1005 1006 1007 1008 1009
    }
    // Perform a similar check for the DataCount and Data sections, where data
    // segments are declared but the Data section is absent.
    if (!CheckDataSegmentsCount(
            static_cast<uint32_t>(module_->data_segments.size()))) {
      return false;
    }
    return true;
  }
1010

1011 1012 1013
  ModuleResult FinishDecoding(bool verify_functions = true) {
    if (ok() && CheckMismatchedCounts()) {
      CalculateGlobalOffsets(module_.get());
1014
    }
1015
    ModuleResult result = toResult(std::move(module_));
1016
    if (verify_functions && result.ok() && intermediate_result_.failed()) {
1017
      // Copy error code and location.
1018
      result = ModuleResult::ErrorFrom(std::move(intermediate_result_));
1019
    }
jfb's avatar
jfb committed
1020
    return result;
1021 1022
  }

1023
  // Decodes an entire module.
1024 1025 1026
  ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator,
                            bool verify_functions = true) {
    StartDecoding(counters, allocator);
1027
    uint32_t offset = 0;
1028
    Vector<const byte> orig_bytes(start(), end() - start());
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
    DecodeModuleHeader(Vector<const uint8_t>(start(), end() - start()), offset);
    if (failed()) {
      return FinishDecoding(verify_functions);
    }
    // Size of the module header.
    offset += 8;
    Decoder decoder(start_ + offset, end_, offset);

    WasmSectionIterator section_iter(decoder);

    while (ok() && section_iter.more()) {
      // Shift the offset by the section header length
      offset += section_iter.payload_start() - section_iter.section_start();
      if (section_iter.section_code() != SectionCode::kUnknownSectionCode) {
        DecodeSection(section_iter.section_code(), section_iter.payload(),
                      offset, verify_functions);
      }
      // Shift the offset by the remaining section payload
      offset += section_iter.payload_length();
      section_iter.advance(true);
    }

1051 1052
    if (FLAG_dump_wasm_module) DumpModule(orig_bytes);

1053 1054 1055 1056 1057 1058 1059
    if (decoder.failed()) {
      return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr);
    }

    return FinishDecoding(verify_functions);
  }

1060
  // Decodes a single anonymous function starting at {start_}.
1061 1062 1063
  FunctionResult DecodeSingleFunction(Zone* zone,
                                      const ModuleWireBytes& wire_bytes,
                                      const WasmModule* module,
1064
                                      std::unique_ptr<WasmFunction> function) {
1065
    pc_ = start_;
1066 1067
    function->sig = consume_sig(zone);
    function->code = {off(pc_), static_cast<uint32_t>(end_ - pc_)};
1068

1069
    if (ok())
1070 1071
      VerifyFunctionBody(zone->allocator(), 0, wire_bytes, module,
                         function.get());
1072

1073 1074 1075 1076 1077
    if (intermediate_result_.failed()) {
      return FunctionResult::ErrorFrom(std::move(intermediate_result_));
    }

    return FunctionResult(std::move(function));
1078 1079 1080
  }

  // Decodes a single function signature at {start}.
1081
  FunctionSig* DecodeFunctionSignature(Zone* zone, const byte* start) {
1082
    pc_ = start;
1083
    FunctionSig* result = consume_sig(zone);
1084 1085 1086
    return ok() ? result : nullptr;
  }

1087 1088
  WasmInitExpr DecodeInitExpr(const byte* start) {
    pc_ = start;
1089
    return consume_init_expr(nullptr, kWasmStmt);
1090 1091
  }

1092
  const std::shared_ptr<WasmModule>& shared_module() const { return module_; }
1093

1094
  Counters* GetCounters() const {
1095 1096 1097 1098 1099 1100 1101 1102 1103
    DCHECK_NOT_NULL(counters_);
    return counters_;
  }

  void SetCounters(Counters* counters) {
    DCHECK_NULL(counters_);
    counters_ = counters;
  }

1104
 private:
1105
  const WasmFeatures enabled_features_;
1106
  std::shared_ptr<WasmModule> module_;
1107
  Counters* counters_ = nullptr;
1108
  // The type section is the first section in a module.
1109 1110 1111 1112 1113 1114
  uint8_t next_ordered_section_ = kFirstSectionInModule;
  // We store next_ordered_section_ as uint8_t instead of SectionCode so that we
  // can increment it. This static_assert should make sure that SectionCode does
  // not get bigger than uint8_t accidentially.
  static_assert(sizeof(ModuleDecoderImpl::next_ordered_section_) ==
                    sizeof(SectionCode),
1115
                "type mismatch");
1116 1117 1118 1119 1120
  uint32_t seen_unordered_sections_ = 0;
  static_assert(kBitsPerByte *
                        sizeof(ModuleDecoderImpl::seen_unordered_sections_) >
                    kLastKnownModuleSection,
                "not enough bits");
1121
  VoidResult intermediate_result_;
1122
  ModuleOrigin origin_;
1123 1124 1125 1126 1127 1128 1129 1130

  bool has_seen_unordered_section(SectionCode section_code) {
    return seen_unordered_sections_ & (1 << section_code);
  }

  void set_seen_unordered_section(SectionCode section_code) {
    seen_unordered_sections_ |= 1 << section_code;
  }
1131

1132 1133 1134
  uint32_t off(const byte* ptr) {
    return static_cast<uint32_t>(ptr - start_) + buffer_offset_;
  }
1135

1136
  bool AddTable(WasmModule* module) {
1137
    if (enabled_features_.anyref) return true;
1138
    if (module->tables.size() > 0) {
1139
      error("At most one table is supported");
1140 1141 1142 1143 1144 1145 1146
      return false;
    } else {
      return true;
    }
  }

  bool AddMemory(WasmModule* module) {
mtrofin's avatar
mtrofin committed
1147
    if (module->has_memory) {
1148
      error("At most one memory is supported");
1149
      return false;
mtrofin's avatar
mtrofin committed
1150 1151
    } else {
      module->has_memory = true;
1152
      return true;
mtrofin's avatar
mtrofin committed
1153 1154 1155
    }
  }

1156
  // Decodes a single global entry inside a module starting at {pc_}.
1157 1158 1159
  void DecodeGlobalInModule(WasmModule* module, uint32_t index,
                            WasmGlobal* global) {
    global->type = consume_value_type();
1160
    global->mutability = consume_mutability();
1161
    const byte* pos = pc();
1162
    global->init = consume_init_expr(module, kWasmStmt);
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
    if (global->init.kind == WasmInitExpr::kGlobalIndex) {
      uint32_t other_index = global->init.val.global_index;
      if (other_index >= index) {
        errorf(pos,
               "invalid global index in init expression, "
               "index %u, other_index %u",
               index, other_index);
      } else if (module->globals[other_index].type != global->type) {
        errorf(pos,
               "type mismatch in global initialization "
               "(from global #%u), expected %s, got %s",
1174 1175
               other_index, ValueTypes::TypeName(global->type),
               ValueTypes::TypeName(module->globals[other_index].type));
1176 1177 1178 1179
      }
    } else {
      if (global->type != TypeOf(module, global->init)) {
        errorf(pos, "type error in global initialization, expected %s, got %s",
1180 1181
               ValueTypes::TypeName(global->type),
               ValueTypes::TypeName(TypeOf(module, global->init)));
1182
      }
1183
    }
1184 1185 1186
  }

  // Decodes a single data segment entry inside a module starting at {pc_}.
1187

1188
  // Calculate individual global offsets and total size of globals table.
1189
  void CalculateGlobalOffsets(WasmModule* module) {
1190
    uint32_t offset = 0;
1191
    uint32_t num_imported_mutable_globals = 0;
1192
    if (module->globals.size() == 0) {
1193
      module->globals_buffer_size = 0;
1194 1195 1196
      return;
    }
    for (WasmGlobal& global : module->globals) {
1197
      byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
1198
      if (global.mutability && global.imported) {
1199
        DCHECK(enabled_features_.mut_global);
1200
        global.index = num_imported_mutable_globals++;
1201 1202 1203 1204 1205
      } else {
        offset = (offset + size - 1) & ~(size - 1);  // align
        global.offset = offset;
        offset += size;
      }
1206
    }
1207
    module->globals_buffer_size = offset;
1208 1209
  }

1210
  // Verifies the body (code) of a given function.
1211
  void VerifyFunctionBody(AccountingAllocator* allocator, uint32_t func_num,
1212 1213
                          const ModuleWireBytes& wire_bytes,
                          const WasmModule* module, WasmFunction* function) {
1214 1215
    WasmFunctionName func_name(function,
                               wire_bytes.GetNameOrNull(function, module));
1216
    if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
1217
      StdoutStream os;
1218
      os << "Verifying wasm function " << func_name << std::endl;
1219
    }
1220
    FunctionBody body = {
1221
        function->sig, function->code.offset(),
1222 1223
        start_ + GetBufferRelativeOffset(function->code.offset()),
        start_ + GetBufferRelativeOffset(function->code.end_offset())};
1224 1225 1226 1227 1228 1229 1230

    DecodeResult result;
    {
      auto time_counter = SELECT_WASM_COUNTER(GetCounters(), origin_,
                                              wasm_decode, function_time);

      TimedHistogramScope wasm_decode_function_time_scope(time_counter);
1231 1232 1233
      WasmFeatures unused_detected_features;
      result = VerifyWasmCode(allocator, enabled_features_, module,
                              &unused_detected_features, body);
1234 1235
    }

1236 1237 1238
    // If the decode failed and this is the first error, set error code and
    // location.
    if (result.failed() && intermediate_result_.ok()) {
1239
      // Wrap the error message from the function decoder.
1240 1241 1242 1243
      std::ostringstream error_msg;
      error_msg << "in function " << func_name << ": " << result.error_msg();
      intermediate_result_ =
          VoidResult::Error(result.error_offset(), error_msg.str());
1244 1245 1246
    }
  }

1247 1248
  uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
    const byte* pos = pc_;
1249
    uint32_t sig_index = consume_u32v("signature index");
1250
    if (sig_index >= module->signatures.size()) {
1251 1252
      errorf(pos, "signature index %u out of bounds (%d signatures)", sig_index,
             static_cast<int>(module->signatures.size()));
1253 1254 1255 1256 1257 1258 1259
      *sig = nullptr;
      return 0;
    }
    *sig = module->signatures[sig_index];
    return sig_index;
  }

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
  uint32_t consume_exception_sig_index(WasmModule* module, FunctionSig** sig) {
    const byte* pos = pc_;
    uint32_t sig_index = consume_sig_index(module, sig);
    if (*sig && (*sig)->return_count() != 0) {
      errorf(pos, "exception signature %u has non-void return", sig_index);
      *sig = nullptr;
      return 0;
    }
    return sig_index;
  }

1271 1272 1273 1274
  uint32_t consume_count(const char* name, size_t maximum) {
    const byte* p = pc_;
    uint32_t count = consume_u32v(name);
    if (count > maximum) {
1275
      errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum);
1276 1277 1278 1279 1280
      return static_cast<uint32_t>(maximum);
    }
    return count;
  }

1281
  uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
1282 1283 1284 1285 1286 1287 1288
    return consume_index("function index", module->functions, func);
  }

  uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) {
    return consume_index("global index", module->globals, global);
  }

1289 1290
  uint32_t consume_table_index(WasmModule* module, WasmTable** table) {
    return consume_index("table index", module->tables, table);
1291 1292
  }

1293 1294 1295 1296
  uint32_t consume_exception_index(WasmModule* module, WasmException** except) {
    return consume_index("exception index", module->exceptions, except);
  }

1297 1298
  template <typename T>
  uint32_t consume_index(const char* name, std::vector<T>& vector, T** ptr) {
1299
    const byte* pos = pc_;
1300 1301
    uint32_t index = consume_u32v(name);
    if (index >= vector.size()) {
1302 1303
      errorf(pos, "%s %u out of bounds (%d entr%s)", name, index,
             static_cast<int>(vector.size()), vector.size() == 1 ? "y" : "ies");
1304
      *ptr = nullptr;
1305 1306
      return 0;
    }
1307 1308 1309 1310
    *ptr = &vector[index];
    return index;
  }

1311
  uint8_t validate_table_flags(const char* name) {
1312
    uint8_t flags = consume_u8("resizable limits flags");
1313
    const byte* pos = pc();
1314 1315 1316 1317 1318
    if (flags & 0xFE) {
      errorf(pos - 1, "invalid %s limits flags", name);
    }
    return flags;
  }
1319

1320 1321 1322 1323
  uint8_t validate_memory_flags(bool* has_shared_memory) {
    uint8_t flags = consume_u8("resizable limits flags");
    const byte* pos = pc();
    *has_shared_memory = false;
1324
    if (enabled_features_.threads) {
1325 1326 1327
      if (flags & 0xFC) {
        errorf(pos - 1, "invalid memory limits flags");
      } else if (flags == 3) {
1328
        DCHECK_NOT_NULL(has_shared_memory);
1329 1330 1331
        *has_shared_memory = true;
      } else if (flags == 2) {
        errorf(pos - 1,
1332 1333
               "memory limits flags should have maximum defined if shared is "
               "true");
1334 1335
      }
    } else {
1336
      if (flags & 0xFE) {
1337
        errorf(pos - 1, "invalid memory limits flags");
1338
      }
1339
    }
1340 1341
    return flags;
  }
1342

1343 1344 1345 1346 1347
  void consume_resizable_limits(const char* name, const char* units,
                                uint32_t max_initial, uint32_t* initial,
                                bool* has_max, uint32_t max_maximum,
                                uint32_t* maximum, uint8_t flags) {
    const byte* pos = pc();
1348
    *initial = consume_u32v("initial size");
1349
    *has_max = false;
1350
    if (*initial > max_initial) {
1351 1352 1353
      errorf(pos,
             "initial %s size (%u %s) is larger than implementation limit (%u)",
             name, *initial, units, max_initial);
1354 1355
    }
    if (flags & 1) {
1356
      *has_max = true;
1357 1358
      pos = pc();
      *maximum = consume_u32v("maximum size");
1359
      if (*maximum > max_maximum) {
1360 1361 1362 1363
        errorf(
            pos,
            "maximum %s size (%u %s) is larger than implementation limit (%u)",
            name, *maximum, units, max_maximum);
1364 1365
      }
      if (*maximum < *initial) {
1366 1367
        errorf(pos, "maximum %s size (%u %s) is less than initial (%u %s)",
               name, *maximum, units, *initial, units);
1368 1369
      }
    } else {
1370
      *has_max = false;
1371
      *maximum = max_initial;
1372 1373 1374 1375 1376 1377 1378
    }
  }

  bool expect_u8(const char* name, uint8_t expected) {
    const byte* pos = pc();
    uint8_t value = consume_u8(name);
    if (value != expected) {
1379
      errorf(pos, "expected %s 0x%02x, got 0x%02x", name, expected, value);
1380 1381 1382 1383 1384
      return false;
    }
    return true;
  }

1385
  WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
1386 1387 1388
    const byte* pos = pc();
    uint8_t opcode = consume_u8("opcode");
    WasmInitExpr expr;
1389
    uint32_t len = 0;
1390 1391
    switch (opcode) {
      case kExprGetGlobal: {
1392 1393
        GlobalIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
        if (module->globals.size() <= imm.index) {
1394
          error("global index is out of bounds");
1395 1396 1397 1398
          expr.kind = WasmInitExpr::kNone;
          expr.val.i32_const = 0;
          break;
        }
1399
        WasmGlobal* global = &module->globals[imm.index];
1400
        if (global->mutability || !global->imported) {
1401 1402 1403
          error(
              "only immutable imported globals can be used in initializer "
              "expressions");
1404 1405 1406 1407
          expr.kind = WasmInitExpr::kNone;
          expr.val.i32_const = 0;
          break;
        }
1408
        expr.kind = WasmInitExpr::kGlobalIndex;
1409 1410
        expr.val.global_index = imm.index;
        len = imm.length;
1411 1412 1413
        break;
      }
      case kExprI32Const: {
1414
        ImmI32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1415
        expr.kind = WasmInitExpr::kI32Const;
1416 1417
        expr.val.i32_const = imm.value;
        len = imm.length;
1418 1419 1420
        break;
      }
      case kExprF32Const: {
1421
        ImmF32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1422
        expr.kind = WasmInitExpr::kF32Const;
1423 1424
        expr.val.f32_const = imm.value;
        len = imm.length;
1425 1426 1427
        break;
      }
      case kExprI64Const: {
1428
        ImmI64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1429
        expr.kind = WasmInitExpr::kI64Const;
1430 1431
        expr.val.i64_const = imm.value;
        len = imm.length;
1432 1433 1434
        break;
      }
      case kExprF64Const: {
1435
        ImmF64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1436
        expr.kind = WasmInitExpr::kF64Const;
1437 1438
        expr.val.f64_const = imm.value;
        len = imm.length;
1439 1440
        break;
      }
1441
      case kExprRefNull: {
1442
        if (enabled_features_.anyref) {
1443 1444 1445 1446 1447 1448
          expr.kind = WasmInitExpr::kAnyRefConst;
          len = 0;
          break;
        }
        V8_FALLTHROUGH;
      }
1449
      default: {
1450
        error("invalid opcode in initialization expression");
1451 1452 1453 1454 1455 1456 1457 1458
        expr.kind = WasmInitExpr::kNone;
        expr.val.i32_const = 0;
      }
    }
    consume_bytes(len, "init code");
    if (!expect_u8("end opcode", kExprEnd)) {
      expr.kind = WasmInitExpr::kNone;
    }
1459
    if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
1460
      errorf(pos, "type error in init expression, expected %s, got %s",
1461 1462
             ValueTypes::TypeName(expected),
             ValueTypes::TypeName(TypeOf(module, expr)));
1463 1464
    }
    return expr;
1465 1466
  }

1467 1468 1469
  // Read a mutability flag
  bool consume_mutability() {
    byte val = consume_u8("mutability");
1470
    if (val > 1) error(pc_ - 1, "invalid mutability");
1471 1472 1473
    return val != 0;
  }

1474
  // Reads a single 8-bit integer, interpreting it as a local type.
1475
  ValueType consume_value_type() {
1476
    byte val = consume_u8("value type");
1477
    ValueTypeCode t = static_cast<ValueTypeCode>(val);
1478 1479
    switch (t) {
      case kLocalI32:
1480
        return kWasmI32;
1481
      case kLocalI64:
1482
        return kWasmI64;
1483
      case kLocalF32:
1484
        return kWasmF32;
1485
      case kLocalF64:
1486
        return kWasmF64;
1487
      default:
1488
        if (origin_ == kWasmOrigin) {
1489 1490
          switch (t) {
            case kLocalS128:
1491
              if (enabled_features_.simd) return kWasmS128;
1492
              break;
1493
            case kLocalAnyFunc:
1494
              if (enabled_features_.anyref) return kWasmAnyFunc;
1495
              break;
1496
            case kLocalAnyRef:
1497
              if (enabled_features_.anyref) return kWasmAnyRef;
1498
              break;
1499 1500 1501
            default:
              break;
          }
1502
        }
1503
        error(pc_ - 1, "invalid local type");
1504
        return kWasmStmt;
1505 1506 1507
    }
  }

1508 1509 1510 1511 1512 1513 1514 1515
  // Reads a single 8-bit integer, interpreting it as a reference type.
  ValueType consume_reference_type() {
    byte val = consume_u8("reference type");
    ValueTypeCode t = static_cast<ValueTypeCode>(val);
    switch (t) {
      case kLocalAnyFunc:
        return kWasmAnyFunc;
      case kLocalAnyRef:
1516
        if (!enabled_features_.anyref) {
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
          error(pc_ - 1,
                "Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
        }
        return kWasmAnyRef;
      default:
        break;
    }
    error(pc_ - 1, "invalid reference type");
    return kWasmStmt;
  }

1528
  FunctionSig* consume_sig(Zone* zone) {
1529
    if (!expect_u8("type form", kWasmFunctionTypeCode)) return nullptr;
1530
    // parse parameter types
1531 1532 1533
    uint32_t param_count =
        consume_count("param count", kV8MaxWasmFunctionParams);
    if (failed()) return nullptr;
1534
    std::vector<ValueType> params;
1535
    for (uint32_t i = 0; ok() && i < param_count; ++i) {
1536
      ValueType param = consume_value_type();
1537 1538
      params.push_back(param);
    }
1539
    std::vector<ValueType> returns;
1540 1541 1542 1543
    // parse return types
    const size_t max_return_count = enabled_features_.mv
                                        ? kV8MaxWasmFunctionMultiReturns
                                        : kV8MaxWasmFunctionReturns;
1544
    uint32_t return_count = consume_count("return count", max_return_count);
1545 1546 1547 1548
    if (failed()) return nullptr;
    for (uint32_t i = 0; ok() && i < return_count; ++i) {
      ValueType ret = consume_value_type();
      returns.push_back(ret);
1549
    }
1550

1551
    if (failed()) return nullptr;
1552

1553
    // FunctionSig stores the return types first.
1554
    ValueType* buffer = zone->NewArray<ValueType>(param_count + return_count);
1555
    uint32_t b = 0;
ritesht's avatar
ritesht committed
1556 1557
    for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
    for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
1558

1559
    return new (zone) FunctionSig(return_count, param_count, buffer);
1560
  }
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571

  // Consume the attribute field of an exception.
  uint32_t consume_exception_attribute() {
    const byte* pos = pc_;
    uint32_t attribute = consume_u32v("exception attribute");
    if (attribute != kExceptionAttribute) {
      errorf(pos, "exception attribute %u not supported", attribute);
      return 0;
    }
    return attribute;
  }
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620

  void consume_segment_header(const char* name, bool* is_active,
                              uint32_t* index, WasmInitExpr* offset) {
    const byte* pos = pc();
    // In the MVP, this is a table or memory index field that must be 0, but
    // we've repurposed it as a flags field in the bulk memory proposal.
    uint32_t flags;
    if (enabled_features_.bulk_memory) {
      flags = consume_u32v("flags");
      if (failed()) return;
    } else {
      flags = consume_u32v(name);
      if (failed()) return;

      if (flags != 0) {
        errorf(pos, "illegal %s %u != 0", name, flags);
        return;
      }
    }

    bool read_index;
    bool read_offset;
    if (flags == SegmentFlags::kActiveNoIndex) {
      *is_active = true;
      read_index = false;
      read_offset = true;
    } else if (flags == SegmentFlags::kPassive) {
      *is_active = false;
      read_index = false;
      read_offset = false;
    } else if (flags == SegmentFlags::kActiveWithIndex) {
      *is_active = true;
      read_index = true;
      read_offset = true;
    } else {
      errorf(pos, "illegal flag value %u. Must be 0, 1, or 2", flags);
      return;
    }

    if (read_index) {
      *index = consume_u32v(name);
    } else {
      *index = 0;
    }

    if (read_offset) {
      *offset = consume_init_expr(module_.get(), kWasmI32);
    }
  }
1621 1622
};

1623 1624
ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
                              const byte* module_start, const byte* module_end,
1625 1626 1627
                              bool verify_functions, ModuleOrigin origin,
                              Counters* counters,
                              AccountingAllocator* allocator) {
1628 1629
  auto counter =
      SELECT_WASM_COUNTER(counters, origin, wasm_decode, module_time);
1630
  TimedHistogramScope wasm_decode_module_time_scope(counter);
1631
  size_t size = module_end - module_start;
1632 1633 1634 1635 1636
  CHECK_LE(module_start, module_end);
  if (size >= kV8MaxWasmModuleSize) {
    return ModuleResult::Error(0, "size > maximum module size (%zu): %zu",
                               kV8MaxWasmModuleSize, size);
  }
1637
  // TODO(bradnelson): Improve histogram handling of size_t.
1638 1639
  auto size_counter =
      SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes);
1640
  size_counter->AddSample(static_cast<int>(size));
1641 1642
  // Signatures are stored in zone memory, which have the same lifetime
  // as the {module}.
1643
  ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
1644 1645
  ModuleResult result =
      decoder.DecodeModule(counters, allocator, verify_functions);
1646
  // TODO(bradnelson): Improve histogram handling of size_t.
1647 1648 1649
  // TODO(titzer): this isn't accurate, since it doesn't count the data
  // allocated on the C++ heap.
  // https://bugs.chromium.org/p/chromium/issues/detail?id=657320
1650
  if (result.ok()) {
1651 1652
    auto peak_counter = SELECT_WASM_COUNTER(counters, origin, wasm_decode,
                                            module_peak_memory_bytes);
1653
    peak_counter->AddSample(
1654
        static_cast<int>(result.value()->signature_zone->allocation_size()));
1655
  }
1656
  return result;
1657 1658
}

1659 1660 1661
ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
    : enabled_features_(enabled) {}

1662 1663
ModuleDecoder::~ModuleDecoder() = default;

1664 1665 1666
const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
  return impl_->shared_module();
}
1667

1668 1669 1670
void ModuleDecoder::StartDecoding(Counters* counters,
                                  AccountingAllocator* allocator,
                                  ModuleOrigin origin) {
1671
  DCHECK_NULL(impl_);
1672
  impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
1673
  impl_->StartDecoding(counters, allocator);
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
}

void ModuleDecoder::DecodeModuleHeader(Vector<const uint8_t> bytes,
                                       uint32_t offset) {
  impl_->DecodeModuleHeader(bytes, offset);
}

void ModuleDecoder::DecodeSection(SectionCode section_code,
                                  Vector<const uint8_t> bytes, uint32_t offset,
                                  bool verify_functions) {
  impl_->DecodeSection(section_code, bytes, offset, verify_functions);
}

void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length,
                                       uint32_t offset, bool verify_functions) {
  impl_->DecodeFunctionBody(index, length, offset, verify_functions);
}

bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count,
                                        uint32_t offset) {
  return impl_->CheckFunctionsCount(functions_count, offset);
}

ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
  return impl_->FinishDecoding(verify_functions);
}

1701 1702
SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder& decoder,
                                                  const byte* end) {
1703
  WireBytesRef string = consume_string(decoder, true, "section name");
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
  if (decoder.failed() || decoder.pc() > end) {
    return kUnknownSectionCode;
  }
  const byte* section_name_start =
      decoder.start() + decoder.GetBufferRelativeOffset(string.offset());

  TRACE("  +%d  section name        : \"%.*s\"\n",
        static_cast<int>(section_name_start - decoder.start()),
        string.length() < 20 ? string.length() : 20, section_name_start);

  if (string.length() == num_chars(kNameString) &&
      strncmp(reinterpret_cast<const char*>(section_name_start), kNameString,
              num_chars(kNameString)) == 0) {
    return kNameSectionCode;
1718 1719 1720 1721 1722
  } else if (string.length() == num_chars(kSourceMappingURLString) &&
             strncmp(reinterpret_cast<const char*>(section_name_start),
                     kSourceMappingURLString,
                     num_chars(kSourceMappingURLString)) == 0) {
    return kSourceMappingURLSectionCode;
1723 1724 1725 1726
  }
  return kUnknownSectionCode;
}

1727
bool ModuleDecoder::ok() { return impl_->ok(); }
1728

1729 1730
FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled,
                                           Zone* zone, const byte* start,
1731
                                           const byte* end) {
1732
  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1733
  return decoder.DecodeFunctionSignature(zone, start);
1734 1735
}

1736 1737
WasmInitExpr DecodeWasmInitExprForTesting(const WasmFeatures& enabled,
                                          const byte* start, const byte* end) {
1738
  AccountingAllocator allocator;
1739
  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1740 1741 1742
  return decoder.DecodeInitExpr(start);
}

1743
FunctionResult DecodeWasmFunctionForTesting(
1744 1745 1746
    const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
    const WasmModule* module, const byte* function_start,
    const byte* function_end, Counters* counters) {
1747
  size_t size = function_end - function_start;
1748
  CHECK_LE(function_start, function_end);
1749 1750
  auto size_histogram = SELECT_WASM_COUNTER(counters, module->origin, wasm,
                                            function_size_bytes);
1751 1752
  // TODO(bradnelson): Improve histogram handling of ptrdiff_t.
  size_histogram->AddSample(static_cast<int>(size));
1753 1754 1755 1756
  if (size > kV8MaxWasmFunctionSize) {
    return FunctionResult::Error(0, "size > maximum function size (%zu): %zu",
                                 kV8MaxWasmFunctionSize, size);
  }
1757
  ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
1758
  decoder.SetCounters(counters);
1759
  return decoder.DecodeSingleFunction(zone, wire_bytes, module,
1760
                                      base::make_unique<WasmFunction>());
1761
}
1762

1763
AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
1764
                                      const byte* tables_end) {
1765 1766 1767 1768 1769
  AsmJsOffsets table;

  Decoder decoder(tables_start, tables_end);
  uint32_t functions_count = decoder.consume_u32v("functions count");
  // Reserve space for the entries, taking care of invalid input.
1770
  if (functions_count < static_cast<uint32_t>(tables_end - tables_start)) {
1771
    table.reserve(functions_count);
1772 1773 1774 1775 1776
  }

  for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
    uint32_t size = decoder.consume_u32v("table size");
    if (size == 0) {
1777
      table.emplace_back();
1778 1779 1780
      continue;
    }
    if (!decoder.checkAvailable(size)) {
1781
      decoder.error("illegal asm function offset table size");
1782 1783
    }
    const byte* table_end = decoder.pc() + size;
1784 1785
    uint32_t locals_size = decoder.consume_u32v("locals size");
    int function_start_position = decoder.consume_u32v("function start pos");
1786
    int last_byte_offset = locals_size;
1787
    int last_asm_position = function_start_position;
1788
    std::vector<AsmJsOffsetEntry> func_asm_offsets;
1789
    func_asm_offsets.reserve(size / 4);  // conservative estimation
1790 1791 1792
    // Add an entry for the stack check, associated with position 0.
    func_asm_offsets.push_back(
        {0, function_start_position, function_start_position});
1793 1794
    while (decoder.ok() && decoder.pc() < table_end) {
      last_byte_offset += decoder.consume_u32v("byte offset delta");
1795 1796 1797 1798 1799 1800 1801
      int call_position =
          last_asm_position + decoder.consume_i32v("call position delta");
      int to_number_position =
          call_position + decoder.consume_i32v("to_number position delta");
      last_asm_position = to_number_position;
      func_asm_offsets.push_back(
          {last_byte_offset, call_position, to_number_position});
1802 1803
    }
    if (decoder.pc() != table_end) {
1804
      decoder.error("broken asm offset table");
1805 1806 1807
    }
    table.push_back(std::move(func_asm_offsets));
  }
1808
  if (decoder.more()) decoder.error("unexpected additional bytes");
1809 1810 1811 1812

  return decoder.toResult(std::move(table));
}

1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833
std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
                                                      const byte* end) {
  Decoder decoder(start, end);
  decoder.consume_bytes(4, "wasm magic");
  decoder.consume_bytes(4, "wasm version");

  std::vector<CustomSectionOffset> result;

  while (decoder.more()) {
    byte section_code = decoder.consume_u8("section code");
    uint32_t section_length = decoder.consume_u32v("section length");
    uint32_t section_start = decoder.pc_offset();
    if (section_code != 0) {
      // Skip known sections.
      decoder.consume_bytes(section_length, "section bytes");
      continue;
    }
    uint32_t name_length = decoder.consume_u32v("name length");
    uint32_t name_offset = decoder.pc_offset();
    decoder.consume_bytes(name_length, "section name");
    uint32_t payload_offset = decoder.pc_offset();
1834 1835 1836 1837
    if (section_length < (payload_offset - section_start)) {
      decoder.error("invalid section length");
      break;
    }
1838 1839
    uint32_t payload_length = section_length - (payload_offset - section_start);
    decoder.consume_bytes(payload_length);
1840
    if (decoder.failed()) break;
1841 1842 1843
    result.push_back({{section_start, section_length},
                      {name_offset, name_length},
                      {payload_offset, payload_length}});
1844 1845 1846 1847 1848
  }

  return result;
}

1849
namespace {
1850

1851
bool FindNameSection(Decoder& decoder) {
1852 1853 1854 1855 1856 1857 1858 1859 1860
  static constexpr int kModuleHeaderSize = 8;
  decoder.consume_bytes(kModuleHeaderSize, "module header");

  WasmSectionIterator section_iter(decoder);

  while (decoder.ok() && section_iter.more() &&
         section_iter.section_code() != kNameSectionCode) {
    section_iter.advance(true);
  }
1861
  if (!section_iter.more()) return false;
1862 1863 1864

  // Reset the decoder to not read beyond the name section end.
  decoder.Reset(section_iter.payload(), decoder.pc_offset());
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
  return true;
}

}  // namespace

void DecodeFunctionNames(const byte* module_start, const byte* module_end,
                         std::unordered_map<uint32_t, WireBytesRef>* names) {
  DCHECK_NOT_NULL(names);
  DCHECK(names->empty());

  Decoder decoder(module_start, module_end);
1876
  if (!FindNameSection(decoder)) return;
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892

  while (decoder.ok() && decoder.more()) {
    uint8_t name_type = decoder.consume_u8("name type");
    if (name_type & 0x80) break;  // no varuint7

    uint32_t name_payload_len = decoder.consume_u32v("name payload length");
    if (!decoder.checkAvailable(name_payload_len)) break;

    if (name_type != NameSectionKindCode::kFunction) {
      decoder.consume_bytes(name_payload_len, "name subsection payload");
      continue;
    }
    uint32_t functions_count = decoder.consume_u32v("functions count");

    for (; decoder.ok() && functions_count > 0; --functions_count) {
      uint32_t function_index = decoder.consume_u32v("function index");
1893
      WireBytesRef name = consume_string(decoder, false, "function name");
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910

      // Be lenient with errors in the name section: Ignore non-UTF8 names. You
      // can even assign to the same function multiple times (last valid one
      // wins).
      if (decoder.ok() && validate_utf8(&decoder, name)) {
        names->insert(std::make_pair(function_index, name));
      }
    }
  }
}

void DecodeLocalNames(const byte* module_start, const byte* module_end,
                      LocalNames* result) {
  DCHECK_NOT_NULL(result);
  DCHECK(result->names.empty());

  Decoder decoder(module_start, module_end);
1911
  if (!FindNameSection(decoder)) return;
1912 1913 1914 1915 1916 1917 1918 1919

  while (decoder.ok() && decoder.more()) {
    uint8_t name_type = decoder.consume_u8("name type");
    if (name_type & 0x80) break;  // no varuint7

    uint32_t name_payload_len = decoder.consume_u32v("name payload length");
    if (!decoder.checkAvailable(name_payload_len)) break;

1920
    if (name_type != NameSectionKindCode::kLocal) {
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
      decoder.consume_bytes(name_payload_len, "name subsection payload");
      continue;
    }

    uint32_t local_names_count = decoder.consume_u32v("local names count");
    for (uint32_t i = 0; i < local_names_count; ++i) {
      uint32_t func_index = decoder.consume_u32v("function index");
      if (func_index > kMaxInt) continue;
      result->names.emplace_back(static_cast<int>(func_index));
      LocalNamesPerFunction& func_names = result->names.back();
      result->max_function_index =
          std::max(result->max_function_index, func_names.function_index);
      uint32_t num_names = decoder.consume_u32v("namings count");
      for (uint32_t k = 0; k < num_names; ++k) {
        uint32_t local_index = decoder.consume_u32v("local index");
1936
        WireBytesRef name = consume_string(decoder, true, "local name");
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946
        if (!decoder.ok()) break;
        if (local_index > kMaxInt) continue;
        func_names.max_local_index =
            std::max(func_names.max_local_index, static_cast<int>(local_index));
        func_names.names.emplace_back(static_cast<int>(local_index), name);
      }
    }
  }
}

1947 1948
#undef TRACE

1949 1950 1951
}  // namespace wasm
}  // namespace internal
}  // namespace v8