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