V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
module-decoder.cc
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/base/template-utils.h"
10 #include "src/counters.h"
11 #include "src/flags.h"
12 #include "src/macro-assembler.h"
13 #include "src/objects-inl.h"
14 #include "src/ostreams.h"
15 #include "src/v8.h"
16 #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 namespace v8 {
22 namespace internal {
23 namespace wasm {
24 
25 #define TRACE(...) \
26  do { \
27  if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
28  } while (false)
29 
30 namespace {
31 
32 constexpr char kNameString[] = "name";
33 constexpr char kSourceMappingURLString[] = "sourceMappingURL";
34 constexpr char kExceptionString[] = "exception";
35 constexpr char kUnknownString[] = "<unknown>";
36 
37 template <size_t N>
38 constexpr size_t num_chars(const char (&)[N]) {
39  return N - 1; // remove null character at end.
40 }
41 
42 const char* ExternalKindName(ImportExportKindCode kind) {
43  switch (kind) {
44  case kExternalFunction:
45  return "function";
46  case kExternalTable:
47  return "table";
48  case kExternalMemory:
49  return "memory";
50  case kExternalGlobal:
51  return "global";
52  case kExternalException:
53  return "exception";
54  }
55  return "unknown";
56 }
57 
58 } // namespace
59 
60 const char* SectionName(SectionCode code) {
61  switch (code) {
62  case kUnknownSectionCode:
63  return "Unknown";
64  case kTypeSectionCode:
65  return "Type";
66  case kImportSectionCode:
67  return "Import";
68  case kFunctionSectionCode:
69  return "Function";
70  case kTableSectionCode:
71  return "Table";
72  case kMemorySectionCode:
73  return "Memory";
74  case kGlobalSectionCode:
75  return "Global";
76  case kExportSectionCode:
77  return "Export";
78  case kStartSectionCode:
79  return "Start";
80  case kCodeSectionCode:
81  return "Code";
82  case kElementSectionCode:
83  return "Element";
84  case kDataSectionCode:
85  return "Data";
86  case kNameSectionCode:
87  return kNameString;
88  case kSourceMappingURLSectionCode:
89  return kSourceMappingURLString;
90  case kExceptionSectionCode:
91  return kExceptionString;
92  default:
93  return kUnknownString;
94  }
95 }
96 
97 namespace {
98 
99 bool validate_utf8(Decoder* decoder, WireBytesRef string) {
100  return unibrow::Utf8::ValidateEncoding(
101  decoder->start() + decoder->GetBufferRelativeOffset(string.offset()),
102  string.length());
103 }
104 
105 ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
106  switch (expr.kind) {
107  case WasmInitExpr::kNone:
108  return kWasmStmt;
109  case WasmInitExpr::kGlobalIndex:
110  return expr.val.global_index < module->globals.size()
111  ? 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  case WasmInitExpr::kAnyRefConst:
122  return kWasmAnyRef;
123  default:
124  UNREACHABLE();
125  }
126 }
127 
128 // Reads a length-prefixed string, checking that it is within bounds. Returns
129 // the offset of the string, and the length as an out parameter.
130 WireBytesRef consume_string(Decoder& decoder, bool validate_utf8,
131  const char* name) {
132  uint32_t length = decoder.consume_u32v("string length");
133  uint32_t offset = decoder.pc_offset();
134  const byte* string_start = decoder.pc();
135  // Consume bytes before validation to guarantee that the string is not oob.
136  if (length > 0) {
137  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 // Automatically skips all unknown sections.
148 class WasmSectionIterator {
149  public:
150  explicit WasmSectionIterator(Decoder& decoder)
151  : decoder_(decoder),
152  section_code_(kUnknownSectionCode),
153  section_start_(decoder.pc()),
154  section_end_(decoder.pc()) {
155  next();
156  }
157 
158  inline bool more() const { return decoder_.ok() && decoder_.more(); }
159 
160  inline SectionCode section_code() const { return section_code_; }
161 
162  inline const byte* section_start() const { return section_start_; }
163 
164  inline uint32_t section_length() const {
165  return static_cast<uint32_t>(section_end_ - section_start_);
166  }
167 
168  inline Vector<const uint8_t> payload() const {
169  return {payload_start_, payload_length()};
170  }
171 
172  inline const byte* payload_start() const { return payload_start_; }
173 
174  inline uint32_t payload_length() const {
175  return static_cast<uint32_t>(section_end_ - payload_start_);
176  }
177 
178  inline const byte* section_end() const { return section_end_; }
179 
180  // Advances to the next section, checking that decoding the current section
181  // stopped at {section_end_}.
182  void advance(bool move_to_section_end = false) {
183  if (move_to_section_end && decoder_.pc() < section_end_) {
184  decoder_.consume_bytes(
185  static_cast<uint32_t>(section_end_ - decoder_.pc()));
186  }
187  if (decoder_.pc() != section_end_) {
188  const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
189  decoder_.errorf(decoder_.pc(),
190  "section was %s than expected size "
191  "(%u bytes expected, %zu decoded)",
192  msg, section_length(),
193  static_cast<size_t>(decoder_.pc() - section_start_));
194  }
195  next();
196  }
197 
198  private:
199  Decoder& decoder_;
200  SectionCode section_code_;
201  const byte* section_start_;
202  const byte* payload_start_;
203  const byte* section_end_;
204 
205  // Reads the section code/name at the current position and sets up
206  // the embedder fields.
207  void next() {
208  if (!decoder_.more()) {
209  section_code_ = kUnknownSectionCode;
210  return;
211  }
212  section_start_ = decoder_.pc();
213  uint8_t section_code = decoder_.consume_u8("section code");
214  // Read and check the section size.
215  uint32_t section_length = decoder_.consume_u32v("section length");
216 
217  payload_start_ = decoder_.pc();
218  if (decoder_.checkAvailable(section_length)) {
219  // Get the limit of the section within the module.
220  section_end_ = payload_start_ + section_length;
221  } else {
222  // The section would extend beyond the end of the module.
223  section_end_ = payload_start_;
224  }
225 
226  if (section_code == kUnknownSectionCode) {
227  // Check for the known "name" or "sourceMappingURL" section.
228  section_code =
229  ModuleDecoder::IdentifyUnknownSection(decoder_, section_end_);
230  // As a side effect, the above function will forward the decoder to after
231  // the identifier string.
232  payload_start_ = decoder_.pc();
233  } else if (!IsValidSectionCode(section_code)) {
234  decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
235  section_code);
236  section_code = kUnknownSectionCode;
237  }
238  section_code_ = decoder_.failed() ? kUnknownSectionCode
239  : static_cast<SectionCode>(section_code);
240 
241  if (section_code_ == kUnknownSectionCode && section_end_ > decoder_.pc()) {
242  // skip to the end of the unknown section.
243  uint32_t remaining = static_cast<uint32_t>(section_end_ - decoder_.pc());
244  decoder_.consume_bytes(remaining, "section payload");
245  }
246  }
247 };
248 
249 } // namespace
250 
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  origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
258 
259  ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
260  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) {
275  std::string path;
276  if (FLAG_dump_wasm_module_path) {
277  path = FLAG_dump_wasm_module_path;
278  if (path.size() &&
279  !base::OS::isDirectorySeparator(path[path.size() - 1])) {
280  path += base::OS::DirectorySeparator();
281  }
282  }
283  // File are named `HASH.{ok,failed}.wasm`.
284  size_t hash = base::hash_range(module_bytes.start(), module_bytes.end());
286  SNPrintF(buf, "%016zx.%s.wasm", hash, ok() ? "ok" : "failed");
287  std::string name(buf.start());
288  if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
289  if (fwrite(module_bytes.start(), module_bytes.length(), 1, wasm_file) !=
290  1) {
291  OFStream os(stderr);
292  os << "Error while dumping wasm file" << std::endl;
293  }
294  fclose(wasm_file);
295  }
296  }
297 
298  void StartDecoding(Counters* counters, AccountingAllocator* allocator) {
299  CHECK_NULL(module_);
300  SetCounters(counters);
301  module_.reset(
302  new WasmModule(base::make_unique<Zone>(allocator, "signatures")));
303  module_->initial_pages = 0;
304  module_->maximum_pages = 0;
305  module_->mem_export = false;
306  module_->origin = origin_;
307  }
308 
309  void DecodeModuleHeader(Vector<const uint8_t> bytes, uint8_t offset) {
310  if (failed()) return;
311  Reset(bytes, offset);
312 
313  const byte* pos = pc_;
314  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  errorf(pos,
318  "expected magic word %02x %02x %02x %02x, "
319  "found %02x %02x %02x %02x",
320  BYTES(kWasmMagic), BYTES(magic_word));
321  }
322 
323  pos = pc_;
324  {
325  uint32_t magic_version = consume_u32("wasm version");
326  if (magic_version != kWasmVersion) {
327  errorf(pos,
328  "expected version %02x %02x %02x %02x, "
329  "found %02x %02x %02x %02x",
330  BYTES(kWasmVersion), BYTES(magic_version));
331  }
332  }
333 #undef BYTES
334  }
335 
336  void DecodeSection(SectionCode section_code, Vector<const uint8_t> bytes,
337  uint32_t offset, bool verify_functions = true) {
338  if (failed()) return;
339  Reset(bytes, offset);
340  TRACE("Section: %s\n", SectionName(section_code));
341  TRACE("Decode Section %p - %p\n", static_cast<const void*>(bytes.begin()),
342  static_cast<const void*>(bytes.end()));
343 
344  // Check if the section is out-of-order.
345  if (section_code < next_ordered_section_ &&
346  section_code < kFirstUnorderedSection) {
347  errorf(pc(), "unexpected section: %s", SectionName(section_code));
348  return;
349  }
350 
351  switch (section_code) {
352  case kUnknownSectionCode:
353  break;
354  case kExceptionSectionCode:
355  // Note: kExceptionSectionCode > kExportSectionCode, but must appear
356  // before the export (and code) section, as well as after the import
357  // section. Hence, treat it as a special case.
358  if (seen_unordered_sections_ & (1 << kExceptionSectionCode)) {
359  errorf(pc(), "Multiple exception sections not allowed");
360  return;
361  } else if (next_ordered_section_ > kExportSectionCode) {
362  errorf(pc(), "Exception section must appear before export section");
363  return;
364  } else if (next_ordered_section_ <= kImportSectionCode) {
365  next_ordered_section_ = kImportSectionCode + 1;
366  }
367  seen_unordered_sections_ |= 1 << kExceptionSectionCode;
368  break;
369  case kSourceMappingURLSectionCode:
370  // sourceMappingURL is a custom section and currently can occur anywhere
371  // in the module. In case of multiple sourceMappingURL sections, all
372  // except the first occurrence are ignored.
373  case kNameSectionCode:
374  // TODO(titzer): report out of place name section as a warning.
375  // Be lenient with placement of name section. All except first
376  // occurrence are ignored.
377  break;
378  default:
379  next_ordered_section_ = section_code + 1;
380  break;
381  }
382 
383  switch (section_code) {
384  case kUnknownSectionCode:
385  break;
386  case kTypeSectionCode:
387  DecodeTypeSection();
388  break;
389  case kImportSectionCode:
390  DecodeImportSection();
391  break;
392  case kFunctionSectionCode:
393  DecodeFunctionSection();
394  break;
395  case kTableSectionCode:
396  DecodeTableSection();
397  break;
398  case kMemorySectionCode:
399  DecodeMemorySection();
400  break;
401  case kGlobalSectionCode:
402  DecodeGlobalSection();
403  break;
404  case kExportSectionCode:
405  DecodeExportSection();
406  break;
407  case kStartSectionCode:
408  DecodeStartSection();
409  break;
410  case kCodeSectionCode:
411  DecodeCodeSection(verify_functions);
412  break;
413  case kElementSectionCode:
414  DecodeElementSection();
415  break;
416  case kDataSectionCode:
417  DecodeDataSection();
418  break;
419  case kNameSectionCode:
420  DecodeNameSection();
421  break;
422  case kSourceMappingURLSectionCode:
423  DecodeSourceMappingURLSection();
424  break;
425  case kExceptionSectionCode:
426  if (enabled_features_.eh) {
427  DecodeExceptionSection();
428  } else {
429  errorf(pc(), "unexpected section: %s", SectionName(section_code));
430  }
431  break;
432  default:
433  errorf(pc(), "unexpected section: %s", SectionName(section_code));
434  return;
435  }
436 
437  if (pc() != bytes.end()) {
438  const char* msg = pc() < bytes.end() ? "shorter" : "longer";
439  errorf(pc(),
440  "section was %s than expected size "
441  "(%zu bytes expected, %zu decoded)",
442  msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin()));
443  }
444  }
445 
446  void DecodeTypeSection() {
447  uint32_t signatures_count = consume_count("types count", kV8MaxWasmTypes);
448  module_->signatures.reserve(signatures_count);
449  for (uint32_t i = 0; ok() && i < signatures_count; ++i) {
450  TRACE("DecodeSignature[%d] module+%d\n", i,
451  static_cast<int>(pc_ - start_));
452  FunctionSig* s = consume_sig(module_->signature_zone.get());
453  module_->signatures.push_back(s);
454  uint32_t id = s ? module_->signature_map.FindOrInsert(*s) : 0;
455  module_->signature_ids.push_back(id);
456  }
457  module_->signature_map.Freeze();
458  }
459 
460  void DecodeImportSection() {
461  uint32_t import_table_count =
462  consume_count("imports count", kV8MaxWasmImports);
463  module_->import_table.reserve(import_table_count);
464  for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
465  TRACE("DecodeImportTable[%d] module+%d\n", i,
466  static_cast<int>(pc_ - start_));
467 
468  module_->import_table.push_back({
469  {0, 0}, // module_name
470  {0, 0}, // field_name
471  kExternalFunction, // kind
472  0 // index
473  });
474  WasmImport* import = &module_->import_table.back();
475  const byte* pos = pc_;
476  import->module_name = consume_string(*this, true, "module name");
477  import->field_name = consume_string(*this, true, "field name");
478  import->kind =
479  static_cast<ImportExportKindCode>(consume_u8("import kind"));
480  switch (import->kind) {
481  case kExternalFunction: {
482  // ===== Imported function =======================================
483  import->index = static_cast<uint32_t>(module_->functions.size());
484  module_->num_imported_functions++;
485  module_->functions.push_back({nullptr, // sig
486  import->index, // func_index
487  0, // sig_index
488  {0, 0}, // code
489  true, // imported
490  false}); // exported
491  WasmFunction* function = &module_->functions.back();
492  function->sig_index =
493  consume_sig_index(module_.get(), &function->sig);
494  break;
495  }
496  case kExternalTable: {
497  // ===== Imported table ==========================================
498  if (!AddTable(module_.get())) break;
499  import->index = static_cast<uint32_t>(module_->tables.size());
500  module_->tables.emplace_back();
501  WasmTable* table = &module_->tables.back();
502  table->imported = true;
503  ValueType type = consume_reference_type();
504  if (!enabled_features_.anyref) {
505  if (type != kWasmAnyFunc) {
506  error(pc_ - 1, "invalid table type");
507  break;
508  }
509  }
510  table->type = type;
511  uint8_t flags = validate_table_flags("element count");
512  consume_resizable_limits(
513  "element count", "elements", FLAG_wasm_max_table_size,
514  &table->initial_size, &table->has_maximum_size,
515  FLAG_wasm_max_table_size, &table->maximum_size, flags);
516  break;
517  }
518  case kExternalMemory: {
519  // ===== Imported memory =========================================
520  if (!AddMemory(module_.get())) break;
521  uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
522  consume_resizable_limits(
523  "memory", "pages", kSpecMaxWasmMemoryPages,
524  &module_->initial_pages, &module_->has_maximum_pages,
525  kSpecMaxWasmMemoryPages, &module_->maximum_pages, flags);
526  break;
527  }
528  case kExternalGlobal: {
529  // ===== Imported global =========================================
530  import->index = static_cast<uint32_t>(module_->globals.size());
531  module_->globals.push_back(
532  {kWasmStmt, false, WasmInitExpr(), {0}, true, false});
533  WasmGlobal* global = &module_->globals.back();
534  global->type = consume_value_type();
535  global->mutability = consume_mutability();
536  if (global->mutability) {
537  if (enabled_features_.mut_global) {
538  module_->num_imported_mutable_globals++;
539  } else {
540  error("mutable globals cannot be imported");
541  }
542  }
543  break;
544  }
545  case kExternalException: {
546  // ===== Imported exception ======================================
547  if (!enabled_features_.eh) {
548  errorf(pos, "unknown import kind 0x%02x", import->kind);
549  break;
550  }
551  import->index = static_cast<uint32_t>(module_->exceptions.size());
552  WasmExceptionSig* exception_sig = nullptr;
553  consume_exception_attribute(); // Attribute ignored for now.
554  consume_exception_sig_index(module_.get(), &exception_sig);
555  module_->exceptions.emplace_back(exception_sig);
556  break;
557  }
558  default:
559  errorf(pos, "unknown import kind 0x%02x", import->kind);
560  break;
561  }
562  }
563  }
564 
565  void DecodeFunctionSection() {
566  uint32_t functions_count =
567  consume_count("functions count", kV8MaxWasmFunctions);
568  auto counter =
569  SELECT_WASM_COUNTER(GetCounters(), origin_, wasm_functions_per, module);
570  counter->AddSample(static_cast<int>(functions_count));
571  DCHECK_EQ(module_->functions.size(), module_->num_imported_functions);
572  uint32_t total_function_count =
573  module_->num_imported_functions + functions_count;
574  module_->functions.reserve(total_function_count);
575  module_->num_declared_functions = functions_count;
576  for (uint32_t i = 0; i < functions_count; ++i) {
577  uint32_t func_index = static_cast<uint32_t>(module_->functions.size());
578  module_->functions.push_back({nullptr, // sig
579  func_index, // func_index
580  0, // sig_index
581  {0, 0}, // code
582  false, // imported
583  false}); // exported
584  WasmFunction* function = &module_->functions.back();
585  function->sig_index = consume_sig_index(module_.get(), &function->sig);
586  if (!ok()) return;
587  }
588  DCHECK_EQ(module_->functions.size(), total_function_count);
589  }
590 
591  void DecodeTableSection() {
592  // TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
593  // implementation of AnyRef landed.
594  uint32_t max_count = enabled_features_.anyref ? 10 : kV8MaxWasmTables;
595  uint32_t table_count = consume_count("table count", max_count);
596 
597  for (uint32_t i = 0; ok() && i < table_count; i++) {
598  if (!AddTable(module_.get())) break;
599  module_->tables.emplace_back();
600  WasmTable* table = &module_->tables.back();
601  table->type = consume_reference_type();
602  uint8_t flags = validate_table_flags("table elements");
603  consume_resizable_limits(
604  "table elements", "elements", FLAG_wasm_max_table_size,
605  &table->initial_size, &table->has_maximum_size,
606  FLAG_wasm_max_table_size, &table->maximum_size, flags);
607  }
608  }
609 
610  void DecodeMemorySection() {
611  uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
612 
613  for (uint32_t i = 0; ok() && i < memory_count; i++) {
614  if (!AddMemory(module_.get())) break;
615  uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
616  consume_resizable_limits(
617  "memory", "pages", kSpecMaxWasmMemoryPages, &module_->initial_pages,
618  &module_->has_maximum_pages, kSpecMaxWasmMemoryPages,
619  &module_->maximum_pages, flags);
620  }
621  }
622 
623  void DecodeGlobalSection() {
624  uint32_t globals_count = consume_count("globals count", kV8MaxWasmGlobals);
625  uint32_t imported_globals = static_cast<uint32_t>(module_->globals.size());
626  module_->globals.reserve(imported_globals + globals_count);
627  for (uint32_t i = 0; ok() && i < globals_count; ++i) {
628  TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
629  // Add an uninitialized global and pass a pointer to it.
630  module_->globals.push_back(
631  {kWasmStmt, false, WasmInitExpr(), {0}, false, false});
632  WasmGlobal* global = &module_->globals.back();
633  DecodeGlobalInModule(module_.get(), i + imported_globals, global);
634  }
635  if (ok()) CalculateGlobalOffsets(module_.get());
636  }
637 
638  void DecodeExportSection() {
639  uint32_t export_table_count =
640  consume_count("exports count", kV8MaxWasmExports);
641  module_->export_table.reserve(export_table_count);
642  for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
643  TRACE("DecodeExportTable[%d] module+%d\n", i,
644  static_cast<int>(pc_ - start_));
645 
646  module_->export_table.push_back({
647  {0, 0}, // name
648  kExternalFunction, // kind
649  0 // index
650  });
651  WasmExport* exp = &module_->export_table.back();
652 
653  exp->name = consume_string(*this, true, "field name");
654 
655  const byte* pos = pc();
656  exp->kind = static_cast<ImportExportKindCode>(consume_u8("export kind"));
657  switch (exp->kind) {
658  case kExternalFunction: {
659  WasmFunction* func = nullptr;
660  exp->index = consume_func_index(module_.get(), &func);
661  module_->num_exported_functions++;
662  if (func) func->exported = true;
663  break;
664  }
665  case kExternalTable: {
666  WasmTable* table = nullptr;
667  exp->index = consume_table_index(module_.get(), &table);
668  if (table) table->exported = true;
669  break;
670  }
671  case kExternalMemory: {
672  uint32_t index = consume_u32v("memory index");
673  // TODO(titzer): This should become more regular
674  // once we support multiple memories.
675  if (!module_->has_memory || index != 0) {
676  error("invalid memory index != 0");
677  }
678  module_->mem_export = true;
679  break;
680  }
681  case kExternalGlobal: {
682  WasmGlobal* global = nullptr;
683  exp->index = consume_global_index(module_.get(), &global);
684  if (global) {
685  if (!enabled_features_.mut_global && global->mutability) {
686  error("mutable globals cannot be exported");
687  }
688  global->exported = true;
689  }
690  break;
691  }
692  case kExternalException: {
693  if (!enabled_features_.eh) {
694  errorf(pos, "invalid export kind 0x%02x", exp->kind);
695  break;
696  }
697  WasmException* exception = nullptr;
698  exp->index = consume_exception_index(module_.get(), &exception);
699  break;
700  }
701  default:
702  errorf(pos, "invalid export kind 0x%02x", exp->kind);
703  break;
704  }
705  }
706  // Check for duplicate exports (except for asm.js).
707  if (ok() && origin_ != kAsmJsOrigin && module_->export_table.size() > 1) {
708  std::vector<WasmExport> sorted_exports(module_->export_table);
709 
710  auto cmp_less = [this](const WasmExport& a, const WasmExport& b) {
711  // Return true if a < b.
712  if (a.name.length() != b.name.length()) {
713  return a.name.length() < b.name.length();
714  }
715  const byte* left = start() + GetBufferRelativeOffset(a.name.offset());
716  const byte* right = start() + GetBufferRelativeOffset(b.name.offset());
717  return memcmp(left, right, a.name.length()) < 0;
718  };
719  std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less);
720 
721  auto it = sorted_exports.begin();
722  WasmExport* last = &*it++;
723  for (auto end = sorted_exports.end(); it != end; last = &*it++) {
724  DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
725  if (!cmp_less(*last, *it)) {
726  const byte* pc = start() + GetBufferRelativeOffset(it->name.offset());
727  TruncatedUserString<> name(pc, it->name.length());
728  errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d",
729  name.length(), name.start(), ExternalKindName(last->kind),
730  last->index, ExternalKindName(it->kind), it->index);
731  break;
732  }
733  }
734  }
735  }
736 
737  void DecodeStartSection() {
738  WasmFunction* func;
739  const byte* pos = pc_;
740  module_->start_function_index = consume_func_index(module_.get(), &func);
741  if (func &&
742  (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
743  error(pos, "invalid start function: non-zero parameter or return count");
744  }
745  }
746 
747  void DecodeElementSection() {
748  uint32_t element_count =
749  consume_count("element count", FLAG_wasm_max_table_size);
750 
751  if (element_count > 0 && module_->tables.size() == 0) {
752  error(pc_, "The element section requires a table");
753  }
754  for (uint32_t i = 0; ok() && i < element_count; ++i) {
755  const byte* pos = pc();
756 
757  bool is_active;
758  uint32_t table_index;
759  WasmInitExpr offset;
760  consume_segment_header("table index", &is_active, &table_index, &offset);
761  if (failed()) return;
762 
763  if (is_active) {
764  if (table_index >= module_->tables.size()) {
765  errorf(pos, "out of bounds table index %u", table_index);
766  break;
767  }
768  if (module_->tables[table_index].type != kWasmAnyFunc) {
769  errorf(pos,
770  "Invalid element segment. Table %u is not of type AnyFunc",
771  table_index);
772  break;
773  }
774  }
775 
776  uint32_t num_elem =
777  consume_count("number of elements", kV8MaxWasmTableEntries);
778  if (is_active) {
779  module_->table_inits.emplace_back(table_index, offset);
780  } else {
781  module_->table_inits.emplace_back();
782  }
783 
784  WasmTableInit* init = &module_->table_inits.back();
785  for (uint32_t j = 0; j < num_elem; j++) {
786  WasmFunction* func = nullptr;
787  uint32_t index = consume_func_index(module_.get(), &func);
788  DCHECK_IMPLIES(ok(), func != nullptr);
789  if (!ok()) break;
790  DCHECK_EQ(index, func->func_index);
791  init->entries.push_back(index);
792  }
793  }
794  }
795 
796  void DecodeCodeSection(bool verify_functions) {
797  uint32_t pos = pc_offset();
798  uint32_t functions_count = consume_u32v("functions count");
799  CheckFunctionsCount(functions_count, pos);
800  for (uint32_t i = 0; ok() && i < functions_count; ++i) {
801  const byte* pos = pc();
802  uint32_t size = consume_u32v("body size");
803  if (size > kV8MaxWasmFunctionSize) {
804  errorf(pos, "size %u > maximum function size %zu", size,
805  kV8MaxWasmFunctionSize);
806  return;
807  }
808  uint32_t offset = pc_offset();
809  consume_bytes(size, "function body");
810  if (failed()) break;
811  DecodeFunctionBody(i, size, offset, verify_functions);
812  }
813  }
814 
815  bool CheckFunctionsCount(uint32_t functions_count, uint32_t offset) {
816  if (functions_count != module_->num_declared_functions) {
817  Reset(nullptr, nullptr, offset);
818  errorf(nullptr, "function body count %u mismatch (%u expected)",
819  functions_count, module_->num_declared_functions);
820  return false;
821  }
822  return true;
823  }
824 
825  void DecodeFunctionBody(uint32_t index, uint32_t length, uint32_t offset,
826  bool verify_functions) {
827  WasmFunction* function =
828  &module_->functions[index + module_->num_imported_functions];
829  function->code = {offset, length};
830  if (verify_functions) {
831  ModuleWireBytes bytes(start_, end_);
832  VerifyFunctionBody(module_->signature_zone->allocator(),
833  index + module_->num_imported_functions, bytes,
834  module_.get(), function);
835  }
836  }
837 
838  void DecodeDataSection() {
839  uint32_t data_segments_count =
840  consume_count("data segments count", kV8MaxWasmDataSegments);
841  module_->data_segments.reserve(data_segments_count);
842  for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
843  const byte* pos = pc();
844  if (!module_->has_memory) {
845  error("cannot load data without memory");
846  break;
847  }
848  TRACE("DecodeDataSegment[%d] module+%d\n", i,
849  static_cast<int>(pc_ - start_));
850 
851  bool is_active;
852  uint32_t memory_index;
853  WasmInitExpr dest_addr;
854  consume_segment_header("memory index", &is_active, &memory_index,
855  &dest_addr);
856  if (failed()) break;
857 
858  if (is_active && memory_index != 0) {
859  errorf(pos, "illegal memory index %u != 0", memory_index);
860  break;
861  }
862 
863  uint32_t source_length = consume_u32v("source size");
864  uint32_t source_offset = pc_offset();
865 
866  if (is_active) {
867  module_->data_segments.emplace_back(dest_addr);
868  } else {
869  module_->data_segments.emplace_back();
870  }
871 
872  WasmDataSegment* segment = &module_->data_segments.back();
873 
874  consume_bytes(source_length, "segment data");
875  if (failed()) break;
876 
877  segment->source = {source_offset, source_length};
878  }
879  }
880 
881  void DecodeNameSection() {
882  // TODO(titzer): find a way to report name errors as warnings.
883  // ignore all but the first occurrence of name section.
884  if (!(seen_unordered_sections_ & (1 << kNameSectionCode))) {
885  seen_unordered_sections_ |= 1 << kNameSectionCode;
886  // Use an inner decoder so that errors don't fail the outer decoder.
887  Decoder inner(start_, pc_, end_, buffer_offset_);
888  // Decode all name subsections.
889  // Be lenient with their order.
890  while (inner.ok() && inner.more()) {
891  uint8_t name_type = inner.consume_u8("name type");
892  if (name_type & 0x80) inner.error("name type if not varuint7");
893 
894  uint32_t name_payload_len = inner.consume_u32v("name payload length");
895  if (!inner.checkAvailable(name_payload_len)) break;
896 
897  // Decode module name, ignore the rest.
898  // Function and local names will be decoded when needed.
899  if (name_type == NameSectionKindCode::kModule) {
900  WireBytesRef name = consume_string(inner, false, "module name");
901  if (inner.ok() && validate_utf8(&inner, name)) module_->name = name;
902  } else {
903  inner.consume_bytes(name_payload_len, "name subsection payload");
904  }
905  }
906  }
907  // Skip the whole names section in the outer decoder.
908  consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
909  }
910 
911  void DecodeSourceMappingURLSection() {
912  Decoder inner(start_, pc_, end_, buffer_offset_);
913  WireBytesRef url = wasm::consume_string(inner, true, "module name");
914  if (inner.ok() &&
915  !(seen_unordered_sections_ & (1 << kSourceMappingURLSectionCode))) {
916  const byte* url_start =
917  inner.start() + inner.GetBufferRelativeOffset(url.offset());
918  module_->source_map_url.assign(reinterpret_cast<const char*>(url_start),
919  url.length());
920  seen_unordered_sections_ |= 1 << kSourceMappingURLSectionCode;
921  }
922  consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
923  }
924 
925  void DecodeExceptionSection() {
926  uint32_t exception_count =
927  consume_count("exception count", kV8MaxWasmExceptions);
928  for (uint32_t i = 0; ok() && i < exception_count; ++i) {
929  TRACE("DecodeException[%d] module+%d\n", i,
930  static_cast<int>(pc_ - start_));
931  WasmExceptionSig* exception_sig = nullptr;
932  consume_exception_attribute(); // Attribute ignored for now.
933  consume_exception_sig_index(module_.get(), &exception_sig);
934  module_->exceptions.emplace_back(exception_sig);
935  }
936  }
937 
938  ModuleResult FinishDecoding(bool verify_functions = true) {
939  if (ok()) {
940  CalculateGlobalOffsets(module_.get());
941  }
942  ModuleResult result = toResult(std::move(module_));
943  if (verify_functions && result.ok() && intermediate_result_.failed()) {
944  // Copy error code and location.
945  result = ModuleResult::ErrorFrom(std::move(intermediate_result_));
946  }
947  return result;
948  }
949 
950  // Decodes an entire module.
951  ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator,
952  bool verify_functions = true) {
953  StartDecoding(counters, allocator);
954  uint32_t offset = 0;
955  Vector<const byte> orig_bytes(start(), end() - start());
956  DecodeModuleHeader(Vector<const uint8_t>(start(), end() - start()), offset);
957  if (failed()) {
958  return FinishDecoding(verify_functions);
959  }
960  // Size of the module header.
961  offset += 8;
962  Decoder decoder(start_ + offset, end_, offset);
963 
964  WasmSectionIterator section_iter(decoder);
965 
966  while (ok() && section_iter.more()) {
967  // Shift the offset by the section header length
968  offset += section_iter.payload_start() - section_iter.section_start();
969  if (section_iter.section_code() != SectionCode::kUnknownSectionCode) {
970  DecodeSection(section_iter.section_code(), section_iter.payload(),
971  offset, verify_functions);
972  }
973  // Shift the offset by the remaining section payload
974  offset += section_iter.payload_length();
975  section_iter.advance(true);
976  }
977 
978  if (FLAG_dump_wasm_module) DumpModule(orig_bytes);
979 
980  if (decoder.failed()) {
981  return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr);
982  }
983 
984  return FinishDecoding(verify_functions);
985  }
986 
987  // Decodes a single anonymous function starting at {start_}.
988  FunctionResult DecodeSingleFunction(Zone* zone,
989  const ModuleWireBytes& wire_bytes,
990  const WasmModule* module,
991  std::unique_ptr<WasmFunction> function) {
992  pc_ = start_;
993  function->sig = consume_sig(zone);
994  function->code = {off(pc_), static_cast<uint32_t>(end_ - pc_)};
995 
996  if (ok())
997  VerifyFunctionBody(zone->allocator(), 0, wire_bytes, module,
998  function.get());
999 
1000  if (intermediate_result_.failed()) {
1001  return FunctionResult::ErrorFrom(std::move(intermediate_result_));
1002  }
1003 
1004  return FunctionResult(std::move(function));
1005  }
1006 
1007  // Decodes a single function signature at {start}.
1008  FunctionSig* DecodeFunctionSignature(Zone* zone, const byte* start) {
1009  pc_ = start;
1010  FunctionSig* result = consume_sig(zone);
1011  return ok() ? result : nullptr;
1012  }
1013 
1014  WasmInitExpr DecodeInitExpr(const byte* start) {
1015  pc_ = start;
1016  return consume_init_expr(nullptr, kWasmStmt);
1017  }
1018 
1019  const std::shared_ptr<WasmModule>& shared_module() const { return module_; }
1020 
1021  Counters* GetCounters() const {
1022  DCHECK_NOT_NULL(counters_);
1023  return counters_;
1024  }
1025 
1026  void SetCounters(Counters* counters) {
1027  DCHECK_NULL(counters_);
1028  counters_ = counters;
1029  }
1030 
1031  private:
1032  const WasmFeatures enabled_features_;
1033  std::shared_ptr<WasmModule> module_;
1034  Counters* counters_ = nullptr;
1035  // The type section is the first section in a module.
1036  uint8_t next_ordered_section_ = kFirstSectionInModule;
1037  // We store next_ordered_section_ as uint8_t instead of SectionCode so that we
1038  // can increment it. This static_assert should make sure that SectionCode does
1039  // not get bigger than uint8_t accidentially.
1040  static_assert(sizeof(ModuleDecoderImpl::next_ordered_section_) ==
1041  sizeof(SectionCode),
1042  "type mismatch");
1043  uint32_t seen_unordered_sections_ = 0;
1044  static_assert(kBitsPerByte *
1045  sizeof(ModuleDecoderImpl::seen_unordered_sections_) >
1046  kLastKnownModuleSection,
1047  "not enough bits");
1048  VoidResult intermediate_result_;
1049  ModuleOrigin origin_;
1050 
1051  uint32_t off(const byte* ptr) {
1052  return static_cast<uint32_t>(ptr - start_) + buffer_offset_;
1053  }
1054 
1055  bool AddTable(WasmModule* module) {
1056  if (enabled_features_.anyref) return true;
1057  if (module->tables.size() > 0) {
1058  error("At most one table is supported");
1059  return false;
1060  } else {
1061  return true;
1062  }
1063  }
1064 
1065  bool AddMemory(WasmModule* module) {
1066  if (module->has_memory) {
1067  error("At most one memory is supported");
1068  return false;
1069  } else {
1070  module->has_memory = true;
1071  return true;
1072  }
1073  }
1074 
1075  // Decodes a single global entry inside a module starting at {pc_}.
1076  void DecodeGlobalInModule(WasmModule* module, uint32_t index,
1077  WasmGlobal* global) {
1078  global->type = consume_value_type();
1079  global->mutability = consume_mutability();
1080  const byte* pos = pc();
1081  global->init = consume_init_expr(module, kWasmStmt);
1082  if (global->init.kind == WasmInitExpr::kGlobalIndex) {
1083  uint32_t other_index = global->init.val.global_index;
1084  if (other_index >= index) {
1085  errorf(pos,
1086  "invalid global index in init expression, "
1087  "index %u, other_index %u",
1088  index, other_index);
1089  } else if (module->globals[other_index].type != global->type) {
1090  errorf(pos,
1091  "type mismatch in global initialization "
1092  "(from global #%u), expected %s, got %s",
1093  other_index, ValueTypes::TypeName(global->type),
1094  ValueTypes::TypeName(module->globals[other_index].type));
1095  }
1096  } else {
1097  if (global->type != TypeOf(module, global->init)) {
1098  errorf(pos, "type error in global initialization, expected %s, got %s",
1099  ValueTypes::TypeName(global->type),
1100  ValueTypes::TypeName(TypeOf(module, global->init)));
1101  }
1102  }
1103  }
1104 
1105  // Decodes a single data segment entry inside a module starting at {pc_}.
1106 
1107  // Calculate individual global offsets and total size of globals table.
1108  void CalculateGlobalOffsets(WasmModule* module) {
1109  uint32_t offset = 0;
1110  uint32_t num_imported_mutable_globals = 0;
1111  if (module->globals.size() == 0) {
1112  module->globals_buffer_size = 0;
1113  return;
1114  }
1115  for (WasmGlobal& global : module->globals) {
1116  byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
1117  if (global.mutability && global.imported) {
1118  DCHECK(enabled_features_.mut_global);
1119  global.index = num_imported_mutable_globals++;
1120  } else {
1121  offset = (offset + size - 1) & ~(size - 1); // align
1122  global.offset = offset;
1123  offset += size;
1124  }
1125  }
1126  module->globals_buffer_size = offset;
1127  }
1128 
1129  // Verifies the body (code) of a given function.
1130  void VerifyFunctionBody(AccountingAllocator* allocator, uint32_t func_num,
1131  const ModuleWireBytes& wire_bytes,
1132  const WasmModule* module, WasmFunction* function) {
1133  WasmFunctionName func_name(function,
1134  wire_bytes.GetNameOrNull(function, module));
1135  if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
1136  StdoutStream os;
1137  os << "Verifying wasm function " << func_name << std::endl;
1138  }
1139  FunctionBody body = {
1140  function->sig, function->code.offset(),
1141  start_ + GetBufferRelativeOffset(function->code.offset()),
1142  start_ + GetBufferRelativeOffset(function->code.end_offset())};
1143 
1144  DecodeResult result;
1145  {
1146  auto time_counter = SELECT_WASM_COUNTER(GetCounters(), origin_,
1147  wasm_decode, function_time);
1148 
1149  TimedHistogramScope wasm_decode_function_time_scope(time_counter);
1150  WasmFeatures unused_detected_features;
1151  result = VerifyWasmCode(allocator, enabled_features_, module,
1152  &unused_detected_features, body);
1153  }
1154 
1155  // If the decode failed and this is the first error, set error code and
1156  // location.
1157  if (result.failed() && intermediate_result_.ok()) {
1158  // Wrap the error message from the function decoder.
1159  std::ostringstream error_msg;
1160  error_msg << "in function " << func_name << ": " << result.error_msg();
1161  intermediate_result_ =
1162  VoidResult::Error(result.error_offset(), error_msg.str());
1163  }
1164  }
1165 
1166  uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
1167  const byte* pos = pc_;
1168  uint32_t sig_index = consume_u32v("signature index");
1169  if (sig_index >= module->signatures.size()) {
1170  errorf(pos, "signature index %u out of bounds (%d signatures)", sig_index,
1171  static_cast<int>(module->signatures.size()));
1172  *sig = nullptr;
1173  return 0;
1174  }
1175  *sig = module->signatures[sig_index];
1176  return sig_index;
1177  }
1178 
1179  uint32_t consume_exception_sig_index(WasmModule* module, FunctionSig** sig) {
1180  const byte* pos = pc_;
1181  uint32_t sig_index = consume_sig_index(module, sig);
1182  if (*sig && (*sig)->return_count() != 0) {
1183  errorf(pos, "exception signature %u has non-void return", sig_index);
1184  *sig = nullptr;
1185  return 0;
1186  }
1187  return sig_index;
1188  }
1189 
1190  uint32_t consume_count(const char* name, size_t maximum) {
1191  const byte* p = pc_;
1192  uint32_t count = consume_u32v(name);
1193  if (count > maximum) {
1194  errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum);
1195  return static_cast<uint32_t>(maximum);
1196  }
1197  return count;
1198  }
1199 
1200  uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
1201  return consume_index("function index", module->functions, func);
1202  }
1203 
1204  uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) {
1205  return consume_index("global index", module->globals, global);
1206  }
1207 
1208  uint32_t consume_table_index(WasmModule* module, WasmTable** table) {
1209  return consume_index("table index", module->tables, table);
1210  }
1211 
1212  uint32_t consume_exception_index(WasmModule* module, WasmException** except) {
1213  return consume_index("exception index", module->exceptions, except);
1214  }
1215 
1216  template <typename T>
1217  uint32_t consume_index(const char* name, std::vector<T>& vector, T** ptr) {
1218  const byte* pos = pc_;
1219  uint32_t index = consume_u32v(name);
1220  if (index >= vector.size()) {
1221  errorf(pos, "%s %u out of bounds (%d entr%s)", name, index,
1222  static_cast<int>(vector.size()), vector.size() == 1 ? "y" : "ies");
1223  *ptr = nullptr;
1224  return 0;
1225  }
1226  *ptr = &vector[index];
1227  return index;
1228  }
1229 
1230  uint8_t validate_table_flags(const char* name) {
1231  uint8_t flags = consume_u8("resizable limits flags");
1232  const byte* pos = pc();
1233  if (flags & 0xFE) {
1234  errorf(pos - 1, "invalid %s limits flags", name);
1235  }
1236  return flags;
1237  }
1238 
1239  uint8_t validate_memory_flags(bool* has_shared_memory) {
1240  uint8_t flags = consume_u8("resizable limits flags");
1241  const byte* pos = pc();
1242  *has_shared_memory = false;
1243  if (enabled_features_.threads) {
1244  if (flags & 0xFC) {
1245  errorf(pos - 1, "invalid memory limits flags");
1246  } else if (flags == 3) {
1247  DCHECK_NOT_NULL(has_shared_memory);
1248  *has_shared_memory = true;
1249  } else if (flags == 2) {
1250  errorf(pos - 1,
1251  "memory limits flags should have maximum defined if shared is "
1252  "true");
1253  }
1254  } else {
1255  if (flags & 0xFE) {
1256  errorf(pos - 1, "invalid memory limits flags");
1257  }
1258  }
1259  return flags;
1260  }
1261 
1262  void consume_resizable_limits(const char* name, const char* units,
1263  uint32_t max_initial, uint32_t* initial,
1264  bool* has_max, uint32_t max_maximum,
1265  uint32_t* maximum, uint8_t flags) {
1266  const byte* pos = pc();
1267  *initial = consume_u32v("initial size");
1268  *has_max = false;
1269  if (*initial > max_initial) {
1270  errorf(pos,
1271  "initial %s size (%u %s) is larger than implementation limit (%u)",
1272  name, *initial, units, max_initial);
1273  }
1274  if (flags & 1) {
1275  *has_max = true;
1276  pos = pc();
1277  *maximum = consume_u32v("maximum size");
1278  if (*maximum > max_maximum) {
1279  errorf(
1280  pos,
1281  "maximum %s size (%u %s) is larger than implementation limit (%u)",
1282  name, *maximum, units, max_maximum);
1283  }
1284  if (*maximum < *initial) {
1285  errorf(pos, "maximum %s size (%u %s) is less than initial (%u %s)",
1286  name, *maximum, units, *initial, units);
1287  }
1288  } else {
1289  *has_max = false;
1290  *maximum = max_initial;
1291  }
1292  }
1293 
1294  bool expect_u8(const char* name, uint8_t expected) {
1295  const byte* pos = pc();
1296  uint8_t value = consume_u8(name);
1297  if (value != expected) {
1298  errorf(pos, "expected %s 0x%02x, got 0x%02x", name, expected, value);
1299  return false;
1300  }
1301  return true;
1302  }
1303 
1304  WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
1305  const byte* pos = pc();
1306  uint8_t opcode = consume_u8("opcode");
1307  WasmInitExpr expr;
1308  uint32_t len = 0;
1309  switch (opcode) {
1310  case kExprGetGlobal: {
1311  GlobalIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
1312  if (module->globals.size() <= imm.index) {
1313  error("global index is out of bounds");
1314  expr.kind = WasmInitExpr::kNone;
1315  expr.val.i32_const = 0;
1316  break;
1317  }
1318  WasmGlobal* global = &module->globals[imm.index];
1319  if (global->mutability || !global->imported) {
1320  error(
1321  "only immutable imported globals can be used in initializer "
1322  "expressions");
1323  expr.kind = WasmInitExpr::kNone;
1324  expr.val.i32_const = 0;
1325  break;
1326  }
1327  expr.kind = WasmInitExpr::kGlobalIndex;
1328  expr.val.global_index = imm.index;
1329  len = imm.length;
1330  break;
1331  }
1332  case kExprI32Const: {
1333  ImmI32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1334  expr.kind = WasmInitExpr::kI32Const;
1335  expr.val.i32_const = imm.value;
1336  len = imm.length;
1337  break;
1338  }
1339  case kExprF32Const: {
1340  ImmF32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1341  expr.kind = WasmInitExpr::kF32Const;
1342  expr.val.f32_const = imm.value;
1343  len = imm.length;
1344  break;
1345  }
1346  case kExprI64Const: {
1347  ImmI64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1348  expr.kind = WasmInitExpr::kI64Const;
1349  expr.val.i64_const = imm.value;
1350  len = imm.length;
1351  break;
1352  }
1353  case kExprF64Const: {
1354  ImmF64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1355  expr.kind = WasmInitExpr::kF64Const;
1356  expr.val.f64_const = imm.value;
1357  len = imm.length;
1358  break;
1359  }
1360  case kExprRefNull: {
1361  if (enabled_features_.anyref) {
1362  expr.kind = WasmInitExpr::kAnyRefConst;
1363  len = 0;
1364  break;
1365  }
1366  V8_FALLTHROUGH;
1367  }
1368  default: {
1369  error("invalid opcode in initialization expression");
1370  expr.kind = WasmInitExpr::kNone;
1371  expr.val.i32_const = 0;
1372  }
1373  }
1374  consume_bytes(len, "init code");
1375  if (!expect_u8("end opcode", kExprEnd)) {
1376  expr.kind = WasmInitExpr::kNone;
1377  }
1378  if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
1379  errorf(pos, "type error in init expression, expected %s, got %s",
1380  ValueTypes::TypeName(expected),
1381  ValueTypes::TypeName(TypeOf(module, expr)));
1382  }
1383  return expr;
1384  }
1385 
1386  // Read a mutability flag
1387  bool consume_mutability() {
1388  byte val = consume_u8("mutability");
1389  if (val > 1) error(pc_ - 1, "invalid mutability");
1390  return val != 0;
1391  }
1392 
1393  // Reads a single 8-bit integer, interpreting it as a local type.
1394  ValueType consume_value_type() {
1395  byte val = consume_u8("value type");
1396  ValueTypeCode t = static_cast<ValueTypeCode>(val);
1397  switch (t) {
1398  case kLocalI32:
1399  return kWasmI32;
1400  case kLocalI64:
1401  return kWasmI64;
1402  case kLocalF32:
1403  return kWasmF32;
1404  case kLocalF64:
1405  return kWasmF64;
1406  default:
1407  if (origin_ == kWasmOrigin) {
1408  switch (t) {
1409  case kLocalS128:
1410  if (enabled_features_.simd) return kWasmS128;
1411  break;
1412  case kLocalAnyFunc:
1413  if (enabled_features_.anyref) return kWasmAnyFunc;
1414  break;
1415  case kLocalAnyRef:
1416  if (enabled_features_.anyref) return kWasmAnyRef;
1417  break;
1418  default:
1419  break;
1420  }
1421  }
1422  error(pc_ - 1, "invalid local type");
1423  return kWasmStmt;
1424  }
1425  }
1426 
1427  // Reads a single 8-bit integer, interpreting it as a reference type.
1428  ValueType consume_reference_type() {
1429  byte val = consume_u8("reference type");
1430  ValueTypeCode t = static_cast<ValueTypeCode>(val);
1431  switch (t) {
1432  case kLocalAnyFunc:
1433  return kWasmAnyFunc;
1434  case kLocalAnyRef:
1435  if (!enabled_features_.anyref) {
1436  error(pc_ - 1,
1437  "Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
1438  }
1439  return kWasmAnyRef;
1440  default:
1441  break;
1442  }
1443  error(pc_ - 1, "invalid reference type");
1444  return kWasmStmt;
1445  }
1446 
1447  FunctionSig* consume_sig(Zone* zone) {
1448  if (!expect_u8("type form", kWasmFunctionTypeCode)) return nullptr;
1449  // parse parameter types
1450  uint32_t param_count =
1451  consume_count("param count", kV8MaxWasmFunctionParams);
1452  if (failed()) return nullptr;
1453  std::vector<ValueType> params;
1454  for (uint32_t i = 0; ok() && i < param_count; ++i) {
1455  ValueType param = consume_value_type();
1456  params.push_back(param);
1457  }
1458  std::vector<ValueType> returns;
1459  // parse return types
1460  const size_t max_return_count = enabled_features_.mv
1461  ? kV8MaxWasmFunctionMultiReturns
1462  : kV8MaxWasmFunctionReturns;
1463  uint32_t return_count = consume_count("return count", max_return_count);
1464  if (failed()) return nullptr;
1465  for (uint32_t i = 0; ok() && i < return_count; ++i) {
1466  ValueType ret = consume_value_type();
1467  returns.push_back(ret);
1468  }
1469 
1470  if (failed()) return nullptr;
1471 
1472  // FunctionSig stores the return types first.
1473  ValueType* buffer = zone->NewArray<ValueType>(param_count + return_count);
1474  uint32_t b = 0;
1475  for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
1476  for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
1477 
1478  return new (zone) FunctionSig(return_count, param_count, buffer);
1479  }
1480 
1481  // Consume the attribute field of an exception.
1482  uint32_t consume_exception_attribute() {
1483  const byte* pos = pc_;
1484  uint32_t attribute = consume_u32v("exception attribute");
1485  if (attribute != kExceptionAttribute) {
1486  errorf(pos, "exception attribute %u not supported", attribute);
1487  return 0;
1488  }
1489  return attribute;
1490  }
1491 
1492  void consume_segment_header(const char* name, bool* is_active,
1493  uint32_t* index, WasmInitExpr* offset) {
1494  const byte* pos = pc();
1495  // In the MVP, this is a table or memory index field that must be 0, but
1496  // we've repurposed it as a flags field in the bulk memory proposal.
1497  uint32_t flags;
1498  if (enabled_features_.bulk_memory) {
1499  flags = consume_u32v("flags");
1500  if (failed()) return;
1501  } else {
1502  flags = consume_u32v(name);
1503  if (failed()) return;
1504 
1505  if (flags != 0) {
1506  errorf(pos, "illegal %s %u != 0", name, flags);
1507  return;
1508  }
1509  }
1510 
1511  bool read_index;
1512  bool read_offset;
1513  if (flags == SegmentFlags::kActiveNoIndex) {
1514  *is_active = true;
1515  read_index = false;
1516  read_offset = true;
1517  } else if (flags == SegmentFlags::kPassive) {
1518  *is_active = false;
1519  read_index = false;
1520  read_offset = false;
1521  } else if (flags == SegmentFlags::kActiveWithIndex) {
1522  *is_active = true;
1523  read_index = true;
1524  read_offset = true;
1525  } else {
1526  errorf(pos, "illegal flag value %u. Must be 0, 1, or 2", flags);
1527  return;
1528  }
1529 
1530  if (read_index) {
1531  *index = consume_u32v(name);
1532  } else {
1533  *index = 0;
1534  }
1535 
1536  if (read_offset) {
1537  *offset = consume_init_expr(module_.get(), kWasmI32);
1538  }
1539  }
1540 };
1541 
1542 ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
1543  const byte* module_start, const byte* module_end,
1544  bool verify_functions, ModuleOrigin origin,
1545  Counters* counters,
1546  AccountingAllocator* allocator) {
1547  auto counter =
1548  SELECT_WASM_COUNTER(counters, origin, wasm_decode, module_time);
1549  TimedHistogramScope wasm_decode_module_time_scope(counter);
1550  size_t size = module_end - module_start;
1551  CHECK_LE(module_start, module_end);
1552  if (size >= kV8MaxWasmModuleSize) {
1553  return ModuleResult::Error(0, "size > maximum module size (%zu): %zu",
1554  kV8MaxWasmModuleSize, size);
1555  }
1556  // TODO(bradnelson): Improve histogram handling of size_t.
1557  auto size_counter =
1558  SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes);
1559  size_counter->AddSample(static_cast<int>(size));
1560  // Signatures are stored in zone memory, which have the same lifetime
1561  // as the {module}.
1562  ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
1563  ModuleResult result =
1564  decoder.DecodeModule(counters, allocator, verify_functions);
1565  // TODO(bradnelson): Improve histogram handling of size_t.
1566  // TODO(titzer): this isn't accurate, since it doesn't count the data
1567  // allocated on the C++ heap.
1568  // https://bugs.chromium.org/p/chromium/issues/detail?id=657320
1569  if (result.ok()) {
1570  auto peak_counter = SELECT_WASM_COUNTER(counters, origin, wasm_decode,
1571  module_peak_memory_bytes);
1572  peak_counter->AddSample(
1573  static_cast<int>(result.value()->signature_zone->allocation_size()));
1574  }
1575  return result;
1576 }
1577 
1578 ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
1579  : enabled_features_(enabled) {}
1580 
1581 ModuleDecoder::~ModuleDecoder() = default;
1582 
1583 const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
1584  return impl_->shared_module();
1585 }
1586 
1587 void ModuleDecoder::StartDecoding(Counters* counters,
1588  AccountingAllocator* allocator,
1589  ModuleOrigin origin) {
1590  DCHECK_NULL(impl_);
1591  impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
1592  impl_->StartDecoding(counters, allocator);
1593 }
1594 
1595 void ModuleDecoder::DecodeModuleHeader(Vector<const uint8_t> bytes,
1596  uint32_t offset) {
1597  impl_->DecodeModuleHeader(bytes, offset);
1598 }
1599 
1600 void ModuleDecoder::DecodeSection(SectionCode section_code,
1601  Vector<const uint8_t> bytes, uint32_t offset,
1602  bool verify_functions) {
1603  impl_->DecodeSection(section_code, bytes, offset, verify_functions);
1604 }
1605 
1606 void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length,
1607  uint32_t offset, bool verify_functions) {
1608  impl_->DecodeFunctionBody(index, length, offset, verify_functions);
1609 }
1610 
1611 bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count,
1612  uint32_t offset) {
1613  return impl_->CheckFunctionsCount(functions_count, offset);
1614 }
1615 
1616 ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
1617  return impl_->FinishDecoding(verify_functions);
1618 }
1619 
1620 SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder& decoder,
1621  const byte* end) {
1622  WireBytesRef string = consume_string(decoder, true, "section name");
1623  if (decoder.failed() || decoder.pc() > end) {
1624  return kUnknownSectionCode;
1625  }
1626  const byte* section_name_start =
1627  decoder.start() + decoder.GetBufferRelativeOffset(string.offset());
1628 
1629  TRACE(" +%d section name : \"%.*s\"\n",
1630  static_cast<int>(section_name_start - decoder.start()),
1631  string.length() < 20 ? string.length() : 20, section_name_start);
1632 
1633  if (string.length() == num_chars(kNameString) &&
1634  strncmp(reinterpret_cast<const char*>(section_name_start), kNameString,
1635  num_chars(kNameString)) == 0) {
1636  return kNameSectionCode;
1637  } else if (string.length() == num_chars(kSourceMappingURLString) &&
1638  strncmp(reinterpret_cast<const char*>(section_name_start),
1639  kSourceMappingURLString,
1640  num_chars(kSourceMappingURLString)) == 0) {
1641  return kSourceMappingURLSectionCode;
1642  }
1643  return kUnknownSectionCode;
1644 }
1645 
1646 bool ModuleDecoder::ok() { return impl_->ok(); }
1647 
1648 FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled,
1649  Zone* zone, const byte* start,
1650  const byte* end) {
1651  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1652  return decoder.DecodeFunctionSignature(zone, start);
1653 }
1654 
1655 WasmInitExpr DecodeWasmInitExprForTesting(const WasmFeatures& enabled,
1656  const byte* start, const byte* end) {
1657  AccountingAllocator allocator;
1658  ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1659  return decoder.DecodeInitExpr(start);
1660 }
1661 
1662 FunctionResult DecodeWasmFunctionForTesting(
1663  const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
1664  const WasmModule* module, const byte* function_start,
1665  const byte* function_end, Counters* counters) {
1666  size_t size = function_end - function_start;
1667  CHECK_LE(function_start, function_end);
1668  auto size_histogram = SELECT_WASM_COUNTER(counters, module->origin, wasm,
1669  function_size_bytes);
1670  // TODO(bradnelson): Improve histogram handling of ptrdiff_t.
1671  size_histogram->AddSample(static_cast<int>(size));
1672  if (size > kV8MaxWasmFunctionSize) {
1673  return FunctionResult::Error(0, "size > maximum function size (%zu): %zu",
1674  kV8MaxWasmFunctionSize, size);
1675  }
1676  ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
1677  decoder.SetCounters(counters);
1678  return decoder.DecodeSingleFunction(zone, wire_bytes, module,
1679  base::make_unique<WasmFunction>());
1680 }
1681 
1682 AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
1683  const byte* tables_end) {
1684  AsmJsOffsets table;
1685 
1686  Decoder decoder(tables_start, tables_end);
1687  uint32_t functions_count = decoder.consume_u32v("functions count");
1688  // Reserve space for the entries, taking care of invalid input.
1689  if (functions_count < static_cast<uint32_t>(tables_end - tables_start)) {
1690  table.reserve(functions_count);
1691  }
1692 
1693  for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
1694  uint32_t size = decoder.consume_u32v("table size");
1695  if (size == 0) {
1696  table.emplace_back();
1697  continue;
1698  }
1699  if (!decoder.checkAvailable(size)) {
1700  decoder.error("illegal asm function offset table size");
1701  }
1702  const byte* table_end = decoder.pc() + size;
1703  uint32_t locals_size = decoder.consume_u32v("locals size");
1704  int function_start_position = decoder.consume_u32v("function start pos");
1705  int last_byte_offset = locals_size;
1706  int last_asm_position = function_start_position;
1707  std::vector<AsmJsOffsetEntry> func_asm_offsets;
1708  func_asm_offsets.reserve(size / 4); // conservative estimation
1709  // Add an entry for the stack check, associated with position 0.
1710  func_asm_offsets.push_back(
1711  {0, function_start_position, function_start_position});
1712  while (decoder.ok() && decoder.pc() < table_end) {
1713  last_byte_offset += decoder.consume_u32v("byte offset delta");
1714  int call_position =
1715  last_asm_position + decoder.consume_i32v("call position delta");
1716  int to_number_position =
1717  call_position + decoder.consume_i32v("to_number position delta");
1718  last_asm_position = to_number_position;
1719  func_asm_offsets.push_back(
1720  {last_byte_offset, call_position, to_number_position});
1721  }
1722  if (decoder.pc() != table_end) {
1723  decoder.error("broken asm offset table");
1724  }
1725  table.push_back(std::move(func_asm_offsets));
1726  }
1727  if (decoder.more()) decoder.error("unexpected additional bytes");
1728 
1729  return decoder.toResult(std::move(table));
1730 }
1731 
1732 std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
1733  const byte* end) {
1734  Decoder decoder(start, end);
1735  decoder.consume_bytes(4, "wasm magic");
1736  decoder.consume_bytes(4, "wasm version");
1737 
1738  std::vector<CustomSectionOffset> result;
1739 
1740  while (decoder.more()) {
1741  byte section_code = decoder.consume_u8("section code");
1742  uint32_t section_length = decoder.consume_u32v("section length");
1743  uint32_t section_start = decoder.pc_offset();
1744  if (section_code != 0) {
1745  // Skip known sections.
1746  decoder.consume_bytes(section_length, "section bytes");
1747  continue;
1748  }
1749  uint32_t name_length = decoder.consume_u32v("name length");
1750  uint32_t name_offset = decoder.pc_offset();
1751  decoder.consume_bytes(name_length, "section name");
1752  uint32_t payload_offset = decoder.pc_offset();
1753  if (section_length < (payload_offset - section_start)) {
1754  decoder.error("invalid section length");
1755  break;
1756  }
1757  uint32_t payload_length = section_length - (payload_offset - section_start);
1758  decoder.consume_bytes(payload_length);
1759  if (decoder.failed()) break;
1760  result.push_back({{section_start, section_length},
1761  {name_offset, name_length},
1762  {payload_offset, payload_length}});
1763  }
1764 
1765  return result;
1766 }
1767 
1768 namespace {
1769 
1770 bool FindNameSection(Decoder& decoder) {
1771  static constexpr int kModuleHeaderSize = 8;
1772  decoder.consume_bytes(kModuleHeaderSize, "module header");
1773 
1774  WasmSectionIterator section_iter(decoder);
1775 
1776  while (decoder.ok() && section_iter.more() &&
1777  section_iter.section_code() != kNameSectionCode) {
1778  section_iter.advance(true);
1779  }
1780  if (!section_iter.more()) return false;
1781 
1782  // Reset the decoder to not read beyond the name section end.
1783  decoder.Reset(section_iter.payload(), decoder.pc_offset());
1784  return true;
1785 }
1786 
1787 } // namespace
1788 
1789 void DecodeFunctionNames(const byte* module_start, const byte* module_end,
1790  std::unordered_map<uint32_t, WireBytesRef>* names) {
1791  DCHECK_NOT_NULL(names);
1792  DCHECK(names->empty());
1793 
1794  Decoder decoder(module_start, module_end);
1795  if (!FindNameSection(decoder)) return;
1796 
1797  while (decoder.ok() && decoder.more()) {
1798  uint8_t name_type = decoder.consume_u8("name type");
1799  if (name_type & 0x80) break; // no varuint7
1800 
1801  uint32_t name_payload_len = decoder.consume_u32v("name payload length");
1802  if (!decoder.checkAvailable(name_payload_len)) break;
1803 
1804  if (name_type != NameSectionKindCode::kFunction) {
1805  decoder.consume_bytes(name_payload_len, "name subsection payload");
1806  continue;
1807  }
1808  uint32_t functions_count = decoder.consume_u32v("functions count");
1809 
1810  for (; decoder.ok() && functions_count > 0; --functions_count) {
1811  uint32_t function_index = decoder.consume_u32v("function index");
1812  WireBytesRef name = consume_string(decoder, false, "function name");
1813 
1814  // Be lenient with errors in the name section: Ignore non-UTF8 names. You
1815  // can even assign to the same function multiple times (last valid one
1816  // wins).
1817  if (decoder.ok() && validate_utf8(&decoder, name)) {
1818  names->insert(std::make_pair(function_index, name));
1819  }
1820  }
1821  }
1822 }
1823 
1824 void DecodeLocalNames(const byte* module_start, const byte* module_end,
1825  LocalNames* result) {
1826  DCHECK_NOT_NULL(result);
1827  DCHECK(result->names.empty());
1828 
1829  Decoder decoder(module_start, module_end);
1830  if (!FindNameSection(decoder)) return;
1831 
1832  while (decoder.ok() && decoder.more()) {
1833  uint8_t name_type = decoder.consume_u8("name type");
1834  if (name_type & 0x80) break; // no varuint7
1835 
1836  uint32_t name_payload_len = decoder.consume_u32v("name payload length");
1837  if (!decoder.checkAvailable(name_payload_len)) break;
1838 
1839  if (name_type != NameSectionKindCode::kLocal) {
1840  decoder.consume_bytes(name_payload_len, "name subsection payload");
1841  continue;
1842  }
1843 
1844  uint32_t local_names_count = decoder.consume_u32v("local names count");
1845  for (uint32_t i = 0; i < local_names_count; ++i) {
1846  uint32_t func_index = decoder.consume_u32v("function index");
1847  if (func_index > kMaxInt) continue;
1848  result->names.emplace_back(static_cast<int>(func_index));
1849  LocalNamesPerFunction& func_names = result->names.back();
1850  result->max_function_index =
1851  std::max(result->max_function_index, func_names.function_index);
1852  uint32_t num_names = decoder.consume_u32v("namings count");
1853  for (uint32_t k = 0; k < num_names; ++k) {
1854  uint32_t local_index = decoder.consume_u32v("local index");
1855  WireBytesRef name = consume_string(decoder, true, "local name");
1856  if (!decoder.ok()) break;
1857  if (local_index > kMaxInt) continue;
1858  func_names.max_local_index =
1859  std::max(func_names.max_local_index, static_cast<int>(local_index));
1860  func_names.names.emplace_back(static_cast<int>(local_index), name);
1861  }
1862  }
1863  }
1864 }
1865 
1866 #undef TRACE
1867 
1868 } // namespace wasm
1869 } // namespace internal
1870 } // namespace v8
Definition: libplatform.h:13