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