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