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