Home | History | Annotate | Download | only in wasm
      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/macro-assembler.h"
      6 #include "src/objects.h"
      7 #include "src/v8.h"
      8 
      9 #include "src/wasm/decoder.h"
     10 #include "src/wasm/module-decoder.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace wasm {
     15 
     16 #if DEBUG
     17 #define TRACE(...)                                    \
     18   do {                                                \
     19     if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
     20   } while (false)
     21 #else
     22 #define TRACE(...)
     23 #endif
     24 
     25 
     26 // The main logic for decoding the bytes of a module.
     27 class ModuleDecoder : public Decoder {
     28  public:
     29   ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
     30                 bool asm_js)
     31       : Decoder(module_start, module_end), module_zone(zone), asm_js_(asm_js) {
     32     result_.start = start_;
     33     if (limit_ < start_) {
     34       error(start_, "end is less than start");
     35       limit_ = start_;
     36     }
     37   }
     38 
     39   virtual void onFirstError() {
     40     pc_ = limit_;  // On error, terminate section decoding loop.
     41   }
     42 
     43   // Decodes an entire module.
     44   ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
     45     pc_ = start_;
     46     module->module_start = start_;
     47     module->module_end = limit_;
     48     module->min_mem_size_log2 = 0;
     49     module->max_mem_size_log2 = 0;
     50     module->mem_export = false;
     51     module->mem_external = false;
     52     module->globals = new std::vector<WasmGlobal>();
     53     module->signatures = new std::vector<FunctionSig*>();
     54     module->functions = new std::vector<WasmFunction>();
     55     module->data_segments = new std::vector<WasmDataSegment>();
     56     module->function_table = new std::vector<uint16_t>();
     57 
     58     bool sections[kMaxModuleSectionCode];
     59     memset(sections, 0, sizeof(sections));
     60 
     61     // Decode the module sections.
     62     while (pc_ < limit_) {
     63       TRACE("DecodeSection\n");
     64       WasmSectionDeclCode section =
     65           static_cast<WasmSectionDeclCode>(u8("section"));
     66       // Each section should appear at most once.
     67       if (section < kMaxModuleSectionCode) {
     68         CheckForPreviousSection(sections, section, false);
     69         sections[section] = true;
     70       }
     71 
     72       switch (section) {
     73         case kDeclEnd:
     74           // Terminate section decoding.
     75           limit_ = pc_;
     76           break;
     77         case kDeclMemory:
     78           module->min_mem_size_log2 = u8("min memory");
     79           module->max_mem_size_log2 = u8("max memory");
     80           module->mem_export = u8("export memory") != 0;
     81           break;
     82         case kDeclSignatures: {
     83           int length;
     84           uint32_t signatures_count = u32v(&length, "signatures count");
     85           module->signatures->reserve(SafeReserve(signatures_count));
     86           // Decode signatures.
     87           for (uint32_t i = 0; i < signatures_count; i++) {
     88             if (failed()) break;
     89             TRACE("DecodeSignature[%d] module+%d\n", i,
     90                   static_cast<int>(pc_ - start_));
     91             FunctionSig* s = sig();  // read function sig.
     92             module->signatures->push_back(s);
     93           }
     94           break;
     95         }
     96         case kDeclFunctions: {
     97           // Functions require a signature table first.
     98           CheckForPreviousSection(sections, kDeclSignatures, true);
     99           int length;
    100           uint32_t functions_count = u32v(&length, "functions count");
    101           module->functions->reserve(SafeReserve(functions_count));
    102           // Set up module environment for verification.
    103           ModuleEnv menv;
    104           menv.module = module;
    105           menv.globals_area = 0;
    106           menv.mem_start = 0;
    107           menv.mem_end = 0;
    108           menv.function_code = nullptr;
    109           menv.asm_js = asm_js_;
    110           // Decode functions.
    111           for (uint32_t i = 0; i < functions_count; i++) {
    112             if (failed()) break;
    113             TRACE("DecodeFunction[%d] module+%d\n", i,
    114                   static_cast<int>(pc_ - start_));
    115 
    116             module->functions->push_back(
    117                 {nullptr, 0, 0, 0, 0, 0, 0, false, false});
    118             WasmFunction* function = &module->functions->back();
    119             DecodeFunctionInModule(module, function, false);
    120           }
    121           if (ok() && verify_functions) {
    122             for (uint32_t i = 0; i < functions_count; i++) {
    123               if (failed()) break;
    124               WasmFunction* function = &module->functions->at(i);
    125               if (!function->external) {
    126                 VerifyFunctionBody(i, &menv, function);
    127                 if (result_.failed())
    128                   error(result_.error_pc, result_.error_msg.get());
    129               }
    130             }
    131           }
    132           break;
    133         }
    134         case kDeclGlobals: {
    135           int length;
    136           uint32_t globals_count = u32v(&length, "globals count");
    137           module->globals->reserve(SafeReserve(globals_count));
    138           // Decode globals.
    139           for (uint32_t i = 0; i < globals_count; i++) {
    140             if (failed()) break;
    141             TRACE("DecodeGlobal[%d] module+%d\n", i,
    142                   static_cast<int>(pc_ - start_));
    143             module->globals->push_back({0, MachineType::Int32(), 0, false});
    144             WasmGlobal* global = &module->globals->back();
    145             DecodeGlobalInModule(global);
    146           }
    147           break;
    148         }
    149         case kDeclDataSegments: {
    150           int length;
    151           uint32_t data_segments_count = u32v(&length, "data segments count");
    152           module->data_segments->reserve(SafeReserve(data_segments_count));
    153           // Decode data segments.
    154           for (uint32_t i = 0; i < data_segments_count; i++) {
    155             if (failed()) break;
    156             TRACE("DecodeDataSegment[%d] module+%d\n", i,
    157                   static_cast<int>(pc_ - start_));
    158             module->data_segments->push_back({0, 0, 0});
    159             WasmDataSegment* segment = &module->data_segments->back();
    160             DecodeDataSegmentInModule(segment);
    161           }
    162           break;
    163         }
    164         case kDeclFunctionTable: {
    165           // An indirect function table requires functions first.
    166           CheckForPreviousSection(sections, kDeclFunctions, true);
    167           int length;
    168           uint32_t function_table_count = u32v(&length, "function table count");
    169           module->function_table->reserve(SafeReserve(function_table_count));
    170           // Decode function table.
    171           for (uint32_t i = 0; i < function_table_count; i++) {
    172             if (failed()) break;
    173             TRACE("DecodeFunctionTable[%d] module+%d\n", i,
    174                   static_cast<int>(pc_ - start_));
    175             uint16_t index = u16();
    176             if (index >= module->functions->size()) {
    177               error(pc_ - 2, "invalid function index");
    178               break;
    179             }
    180             module->function_table->push_back(index);
    181           }
    182           break;
    183         }
    184         case kDeclWLL: {
    185           // Reserved for experimentation by the Web Low-level Language project
    186           // which is augmenting the binary encoding with source code meta
    187           // information. This section does not affect the semantics of the code
    188           // and can be ignored by the runtime. https://github.com/JSStats/wll
    189           int length = 0;
    190           uint32_t section_size = u32v(&length, "section size");
    191           if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
    192             error(pc_ - length, "invalid section size");
    193             break;
    194           }
    195           pc_ += section_size;
    196           break;
    197         }
    198         default:
    199           error(pc_ - 1, nullptr, "unrecognized section 0x%02x", section);
    200           break;
    201       }
    202     }
    203 
    204     return toResult(module);
    205   }
    206 
    207   uint32_t SafeReserve(uint32_t count) {
    208     // Avoid OOM by only reserving up to a certain size.
    209     const uint32_t kMaxReserve = 20000;
    210     return count < kMaxReserve ? count : kMaxReserve;
    211   }
    212 
    213   void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section,
    214                                bool present) {
    215     if (section >= kMaxModuleSectionCode) return;
    216     if (sections[section] == present) return;
    217     const char* name = "";
    218     switch (section) {
    219       case kDeclMemory:
    220         name = "memory";
    221         break;
    222       case kDeclSignatures:
    223         name = "signatures";
    224         break;
    225       case kDeclFunctions:
    226         name = "function declaration";
    227         break;
    228       case kDeclGlobals:
    229         name = "global variable";
    230         break;
    231       case kDeclDataSegments:
    232         name = "data segment";
    233         break;
    234       case kDeclFunctionTable:
    235         name = "function table";
    236         break;
    237       default:
    238         name = "";
    239         break;
    240     }
    241     if (present) {
    242       error(pc_ - 1, nullptr, "required %s section missing", name);
    243     } else {
    244       error(pc_ - 1, nullptr, "%s section already present", name);
    245     }
    246   }
    247 
    248   // Decodes a single anonymous function starting at {start_}.
    249   FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
    250                                       WasmFunction* function) {
    251     pc_ = start_;
    252     function->sig = sig();                       // read signature
    253     function->name_offset = 0;                   // ---- name
    254     function->code_start_offset = off(pc_ + 8);  // ---- code start
    255     function->code_end_offset = off(limit_);     // ---- code end
    256     function->local_int32_count = u16();         // read u16
    257     function->local_int64_count = u16();         // read u16
    258     function->local_float32_count = u16();       // read u16
    259     function->local_float64_count = u16();       // read u16
    260     function->exported = false;                  // ---- exported
    261     function->external = false;                  // ---- external
    262 
    263     if (ok()) VerifyFunctionBody(0, module_env, function);
    264 
    265     FunctionResult result;
    266     result.CopyFrom(result_);  // Copy error code and location.
    267     result.val = function;
    268     return result;
    269   }
    270 
    271   // Decodes a single function signature at {start}.
    272   FunctionSig* DecodeFunctionSignature(const byte* start) {
    273     pc_ = start;
    274     FunctionSig* result = sig();
    275     return ok() ? result : nullptr;
    276   }
    277 
    278  private:
    279   Zone* module_zone;
    280   ModuleResult result_;
    281   bool asm_js_;
    282 
    283   uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
    284 
    285   // Decodes a single global entry inside a module starting at {pc_}.
    286   void DecodeGlobalInModule(WasmGlobal* global) {
    287     global->name_offset = string("global name");
    288     global->type = mem_type();
    289     global->offset = 0;
    290     global->exported = u8("exported") != 0;
    291   }
    292 
    293   // Decodes a single function entry inside a module starting at {pc_}.
    294   void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
    295                               bool verify_body = true) {
    296     byte decl_bits = u8("function decl");
    297 
    298     const byte* sigpos = pc_;
    299     function->sig_index = u16("signature index");
    300 
    301     if (function->sig_index >= module->signatures->size()) {
    302       return error(sigpos, "invalid signature index");
    303     } else {
    304       function->sig = module->signatures->at(function->sig_index);
    305     }
    306 
    307     TRACE("  +%d  <function attributes:%s%s%s%s%s>\n",
    308           static_cast<int>(pc_ - start_),
    309           decl_bits & kDeclFunctionName ? " name" : "",
    310           decl_bits & kDeclFunctionImport ? " imported" : "",
    311           decl_bits & kDeclFunctionLocals ? " locals" : "",
    312           decl_bits & kDeclFunctionExport ? " exported" : "",
    313           (decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
    314 
    315     if (decl_bits & kDeclFunctionName) {
    316       function->name_offset = string("function name");
    317     }
    318 
    319     function->exported = decl_bits & kDeclFunctionExport;
    320 
    321     // Imported functions have no locals or body.
    322     if (decl_bits & kDeclFunctionImport) {
    323       function->external = true;
    324       return;
    325     }
    326 
    327     if (decl_bits & kDeclFunctionLocals) {
    328       function->local_int32_count = u16("int32 count");
    329       function->local_int64_count = u16("int64 count");
    330       function->local_float32_count = u16("float32 count");
    331       function->local_float64_count = u16("float64 count");
    332     }
    333 
    334     uint16_t size = u16("body size");
    335     if (ok()) {
    336       if ((pc_ + size) > limit_) {
    337         return error(pc_, limit_,
    338                      "expected %d bytes for function body, fell off end", size);
    339       }
    340       function->code_start_offset = static_cast<uint32_t>(pc_ - start_);
    341       function->code_end_offset = function->code_start_offset + size;
    342       TRACE("  +%d  %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_),
    343             "function body", size);
    344       pc_ += size;
    345     }
    346   }
    347 
    348   // Decodes a single data segment entry inside a module starting at {pc_}.
    349   void DecodeDataSegmentInModule(WasmDataSegment* segment) {
    350     segment->dest_addr =
    351         u32("destination");  // TODO(titzer): check it's within the memory size.
    352     segment->source_offset = offset("source offset");
    353     segment->source_size =
    354         u32("source size");  // TODO(titzer): check the size is reasonable.
    355     segment->init = u8("init");
    356   }
    357 
    358   // Verifies the body (code) of a given function.
    359   void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
    360                           WasmFunction* function) {
    361     if (FLAG_trace_wasm_decode_time) {
    362       // TODO(titzer): clean me up a bit.
    363       OFStream os(stdout);
    364       os << "Verifying WASM function:";
    365       if (function->name_offset > 0) {
    366         os << menv->module->GetName(function->name_offset);
    367       }
    368       os << std::endl;
    369     }
    370     FunctionEnv fenv;
    371     fenv.module = menv;
    372     fenv.sig = function->sig;
    373     fenv.local_int32_count = function->local_int32_count;
    374     fenv.local_int64_count = function->local_int64_count;
    375     fenv.local_float32_count = function->local_float32_count;
    376     fenv.local_float64_count = function->local_float64_count;
    377     fenv.SumLocals();
    378 
    379     TreeResult result =
    380         VerifyWasmCode(&fenv, start_, start_ + function->code_start_offset,
    381                        start_ + function->code_end_offset);
    382     if (result.failed()) {
    383       // Wrap the error message from the function decoder.
    384       std::ostringstream str;
    385       str << "in function #" << func_num << ": ";
    386       // TODO(titzer): add function name for the user?
    387       str << result;
    388       std::string strval = str.str();
    389       const char* raw = strval.c_str();
    390       size_t len = strlen(raw);
    391       char* buffer = new char[len];
    392       strncpy(buffer, raw, len);
    393       buffer[len - 1] = 0;
    394 
    395       // Copy error code and location.
    396       result_.CopyFrom(result);
    397       result_.error_msg.Reset(buffer);
    398     }
    399   }
    400 
    401   // Reads a single 32-bit unsigned integer interpreted as an offset, checking
    402   // the offset is within bounds and advances.
    403   uint32_t offset(const char* name = nullptr) {
    404     uint32_t offset = u32(name ? name : "offset");
    405     if (offset > static_cast<uint32_t>(limit_ - start_)) {
    406       error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
    407     }
    408     return offset;
    409   }
    410 
    411   // Reads a single 32-bit unsigned integer interpreted as an offset into the
    412   // data and validating the string there and advances.
    413   uint32_t string(const char* name = nullptr) {
    414     return offset(name ? name : "string");  // TODO(titzer): validate string
    415   }
    416 
    417   // Reads a single 8-bit integer, interpreting it as a local type.
    418   LocalType local_type() {
    419     byte val = u8("local type");
    420     LocalTypeCode t = static_cast<LocalTypeCode>(val);
    421     switch (t) {
    422       case kLocalVoid:
    423         return kAstStmt;
    424       case kLocalI32:
    425         return kAstI32;
    426       case kLocalI64:
    427         return kAstI64;
    428       case kLocalF32:
    429         return kAstF32;
    430       case kLocalF64:
    431         return kAstF64;
    432       default:
    433         error(pc_ - 1, "invalid local type");
    434         return kAstStmt;
    435     }
    436   }
    437 
    438   // Reads a single 8-bit integer, interpreting it as a memory type.
    439   MachineType mem_type() {
    440     byte val = u8("memory type");
    441     MemTypeCode t = static_cast<MemTypeCode>(val);
    442     switch (t) {
    443       case kMemI8:
    444         return MachineType::Int8();
    445       case kMemU8:
    446         return MachineType::Uint8();
    447       case kMemI16:
    448         return MachineType::Int16();
    449       case kMemU16:
    450         return MachineType::Uint16();
    451       case kMemI32:
    452         return MachineType::Int32();
    453       case kMemU32:
    454         return MachineType::Uint32();
    455       case kMemI64:
    456         return MachineType::Int64();
    457       case kMemU64:
    458         return MachineType::Uint64();
    459       case kMemF32:
    460         return MachineType::Float32();
    461       case kMemF64:
    462         return MachineType::Float64();
    463       default:
    464         error(pc_ - 1, "invalid memory type");
    465         return MachineType::None();
    466     }
    467   }
    468 
    469   // Parses an inline function signature.
    470   FunctionSig* sig() {
    471     byte count = u8("param count");
    472     LocalType ret = local_type();
    473     FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
    474     if (ret != kAstStmt) builder.AddReturn(ret);
    475 
    476     for (int i = 0; i < count; i++) {
    477       LocalType param = local_type();
    478       if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
    479       builder.AddParam(param);
    480     }
    481     return builder.Build();
    482   }
    483 };
    484 
    485 
    486 // Helpers for nice error messages.
    487 class ModuleError : public ModuleResult {
    488  public:
    489   explicit ModuleError(const char* msg) {
    490     error_code = kError;
    491     size_t len = strlen(msg) + 1;
    492     char* result = new char[len];
    493     strncpy(result, msg, len);
    494     result[len - 1] = 0;
    495     error_msg.Reset(result);
    496   }
    497 };
    498 
    499 
    500 // Helpers for nice error messages.
    501 class FunctionError : public FunctionResult {
    502  public:
    503   explicit FunctionError(const char* msg) {
    504     error_code = kError;
    505     size_t len = strlen(msg) + 1;
    506     char* result = new char[len];
    507     strncpy(result, msg, len);
    508     result[len - 1] = 0;
    509     error_msg.Reset(result);
    510   }
    511 };
    512 
    513 
    514 ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
    515                               const byte* module_start, const byte* module_end,
    516                               bool verify_functions, bool asm_js) {
    517   size_t size = module_end - module_start;
    518   if (module_start > module_end) return ModuleError("start > end");
    519   if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
    520   WasmModule* module = new WasmModule();
    521   ModuleDecoder decoder(zone, module_start, module_end, asm_js);
    522   return decoder.DecodeModule(module, verify_functions);
    523 }
    524 
    525 
    526 FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
    527                                            const byte* end) {
    528   ModuleDecoder decoder(zone, start, end, false);
    529   return decoder.DecodeFunctionSignature(start);
    530 }
    531 
    532 
    533 FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
    534                                   ModuleEnv* module_env,
    535                                   const byte* function_start,
    536                                   const byte* function_end) {
    537   size_t size = function_end - function_start;
    538   if (function_start > function_end) return FunctionError("start > end");
    539   if (size > kMaxFunctionSize)
    540     return FunctionError("size > maximum function size");
    541   WasmFunction* function = new WasmFunction();
    542   ModuleDecoder decoder(zone, function_start, function_end, false);
    543   return decoder.DecodeSingleFunction(module_env, function);
    544 }
    545 }  // namespace wasm
    546 }  // namespace internal
    547 }  // namespace v8
    548