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