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