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/base/template-utils.h"
10 #include "src/counters.h"
11 #include "src/flags.h"
12 #include "src/macro-assembler.h"
13 #include "src/objects-inl.h"
14 #include "src/ostreams.h"
15 #include "src/v8.h"
16 #include "src/wasm/decoder.h"
17 #include "src/wasm/function-body-decoder-impl.h"
18 #include "src/wasm/wasm-engine.h"
19 #include "src/wasm/wasm-limits.h"
20
21 namespace v8 {
22 namespace internal {
23 namespace wasm {
24
25 #define TRACE(...) \
26 do { \
27 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
28 } while (false)
29
30 namespace {
31
32 constexpr char kNameString[] = "name";
33 constexpr char kExceptionString[] = "exception";
34 constexpr char kUnknownString[] = "<unknown>";
35
36 template <size_t N>
num_chars(const char (&)[N])37 constexpr size_t num_chars(const char (&)[N]) {
38 return N - 1; // remove null character at end.
39 }
40
ExternalKindName(ImportExportKindCode kind)41 const char* ExternalKindName(ImportExportKindCode kind) {
42 switch (kind) {
43 case kExternalFunction:
44 return "function";
45 case kExternalTable:
46 return "table";
47 case kExternalMemory:
48 return "memory";
49 case kExternalGlobal:
50 return "global";
51 }
52 return "unknown";
53 }
54
55 } // namespace
56
SectionName(SectionCode code)57 const char* SectionName(SectionCode code) {
58 switch (code) {
59 case kUnknownSectionCode:
60 return "Unknown";
61 case kTypeSectionCode:
62 return "Type";
63 case kImportSectionCode:
64 return "Import";
65 case kFunctionSectionCode:
66 return "Function";
67 case kTableSectionCode:
68 return "Table";
69 case kMemorySectionCode:
70 return "Memory";
71 case kGlobalSectionCode:
72 return "Global";
73 case kExportSectionCode:
74 return "Export";
75 case kStartSectionCode:
76 return "Start";
77 case kCodeSectionCode:
78 return "Code";
79 case kElementSectionCode:
80 return "Element";
81 case kDataSectionCode:
82 return "Data";
83 case kNameSectionCode:
84 return kNameString;
85 case kExceptionSectionCode:
86 return kExceptionString;
87 default:
88 return kUnknownString;
89 }
90 }
91
92 namespace {
93
validate_utf8(Decoder * decoder,WireBytesRef string)94 bool validate_utf8(Decoder* decoder, WireBytesRef string) {
95 return unibrow::Utf8::ValidateEncoding(
96 decoder->start() + decoder->GetBufferRelativeOffset(string.offset()),
97 string.length());
98 }
99
TypeOf(const WasmModule * module,const WasmInitExpr & expr)100 ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
101 switch (expr.kind) {
102 case WasmInitExpr::kNone:
103 return kWasmStmt;
104 case WasmInitExpr::kGlobalIndex:
105 return expr.val.global_index < module->globals.size()
106 ? module->globals[expr.val.global_index].type
107 : kWasmStmt;
108 case WasmInitExpr::kI32Const:
109 return kWasmI32;
110 case WasmInitExpr::kI64Const:
111 return kWasmI64;
112 case WasmInitExpr::kF32Const:
113 return kWasmF32;
114 case WasmInitExpr::kF64Const:
115 return kWasmF64;
116 case WasmInitExpr::kAnyRefConst:
117 return kWasmAnyRef;
118 default:
119 UNREACHABLE();
120 }
121 }
122
123 // Reads a length-prefixed string, checking that it is within bounds. Returns
124 // the offset of the string, and the length as an out parameter.
consume_string(Decoder & decoder,bool validate_utf8,const char * name)125 WireBytesRef consume_string(Decoder& decoder, bool validate_utf8,
126 const char* name) {
127 uint32_t length = decoder.consume_u32v("string length");
128 uint32_t offset = decoder.pc_offset();
129 const byte* string_start = decoder.pc();
130 // Consume bytes before validation to guarantee that the string is not oob.
131 if (length > 0) {
132 decoder.consume_bytes(length, name);
133 if (decoder.ok() && validate_utf8 &&
134 !unibrow::Utf8::ValidateEncoding(string_start, length)) {
135 decoder.errorf(string_start, "%s: no valid UTF-8 string", name);
136 }
137 }
138 return {offset, decoder.failed() ? 0 : length};
139 }
140
141 // An iterator over the sections in a wasm binary module.
142 // Automatically skips all unknown sections.
143 class WasmSectionIterator {
144 public:
WasmSectionIterator(Decoder & decoder)145 explicit WasmSectionIterator(Decoder& decoder)
146 : decoder_(decoder),
147 section_code_(kUnknownSectionCode),
148 section_start_(decoder.pc()),
149 section_end_(decoder.pc()) {
150 next();
151 }
152
more() const153 inline bool more() const { return decoder_.ok() && decoder_.more(); }
154
section_code() const155 inline SectionCode section_code() const { return section_code_; }
156
section_start() const157 inline const byte* section_start() const { return section_start_; }
158
section_length() const159 inline uint32_t section_length() const {
160 return static_cast<uint32_t>(section_end_ - section_start_);
161 }
162
payload() const163 inline Vector<const uint8_t> payload() const {
164 return {payload_start_, payload_length()};
165 }
166
payload_start() const167 inline const byte* payload_start() const { return payload_start_; }
168
payload_length() const169 inline uint32_t payload_length() const {
170 return static_cast<uint32_t>(section_end_ - payload_start_);
171 }
172
section_end() const173 inline const byte* section_end() const { return section_end_; }
174
175 // Advances to the next section, checking that decoding the current section
176 // stopped at {section_end_}.
advance(bool move_to_section_end=false)177 void advance(bool move_to_section_end = false) {
178 if (move_to_section_end && decoder_.pc() < section_end_) {
179 decoder_.consume_bytes(
180 static_cast<uint32_t>(section_end_ - decoder_.pc()));
181 }
182 if (decoder_.pc() != section_end_) {
183 const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
184 decoder_.errorf(decoder_.pc(),
185 "section was %s than expected size "
186 "(%u bytes expected, %zu decoded)",
187 msg, section_length(),
188 static_cast<size_t>(decoder_.pc() - section_start_));
189 }
190 next();
191 }
192
193 private:
194 Decoder& decoder_;
195 SectionCode section_code_;
196 const byte* section_start_;
197 const byte* payload_start_;
198 const byte* section_end_;
199
200 // Reads the section code/name at the current position and sets up
201 // the embedder fields.
next()202 void next() {
203 if (!decoder_.more()) {
204 section_code_ = kUnknownSectionCode;
205 return;
206 }
207 section_start_ = decoder_.pc();
208 uint8_t section_code = decoder_.consume_u8("section code");
209 // Read and check the section size.
210 uint32_t section_length = decoder_.consume_u32v("section length");
211
212 payload_start_ = decoder_.pc();
213 if (decoder_.checkAvailable(section_length)) {
214 // Get the limit of the section within the module.
215 section_end_ = payload_start_ + section_length;
216 } else {
217 // The section would extend beyond the end of the module.
218 section_end_ = payload_start_;
219 }
220
221 if (section_code == kUnknownSectionCode) {
222 // Check for the known "name" section.
223 section_code =
224 ModuleDecoder::IdentifyUnknownSection(decoder_, section_end_);
225 // As a side effect, the above function will forward the decoder to after
226 // the identifier string.
227 payload_start_ = decoder_.pc();
228 } else if (!IsValidSectionCode(section_code)) {
229 decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
230 section_code);
231 section_code = kUnknownSectionCode;
232 }
233 section_code_ = decoder_.failed() ? kUnknownSectionCode
234 : static_cast<SectionCode>(section_code);
235
236 if (section_code_ == kUnknownSectionCode && section_end_ > decoder_.pc()) {
237 // skip to the end of the unknown section.
238 uint32_t remaining = static_cast<uint32_t>(section_end_ - decoder_.pc());
239 decoder_.consume_bytes(remaining, "section payload");
240 }
241 }
242 };
243
244 } // namespace
245
246 // The main logic for decoding the bytes of a module.
247 class ModuleDecoderImpl : public Decoder {
248 public:
ModuleDecoderImpl(const WasmFeatures & enabled,ModuleOrigin origin)249 explicit ModuleDecoderImpl(const WasmFeatures& enabled, ModuleOrigin origin)
250 : Decoder(nullptr, nullptr),
251 enabled_features_(enabled),
252 origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {}
253
ModuleDecoderImpl(const WasmFeatures & enabled,const byte * module_start,const byte * module_end,ModuleOrigin origin)254 ModuleDecoderImpl(const WasmFeatures& enabled, const byte* module_start,
255 const byte* module_end, ModuleOrigin origin)
256 : Decoder(module_start, module_end),
257 enabled_features_(enabled),
258 origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
259 if (end_ < start_) {
260 error(start_, "end is less than start");
261 end_ = start_;
262 }
263 }
264
onFirstError()265 virtual void onFirstError() {
266 pc_ = end_; // On error, terminate section decoding loop.
267 }
268
DumpModule(const Vector<const byte> module_bytes)269 void DumpModule(const Vector<const byte> module_bytes) {
270 std::string path;
271 if (FLAG_dump_wasm_module_path) {
272 path = FLAG_dump_wasm_module_path;
273 if (path.size() &&
274 !base::OS::isDirectorySeparator(path[path.size() - 1])) {
275 path += base::OS::DirectorySeparator();
276 }
277 }
278 // File are named `HASH.{ok,failed}.wasm`.
279 size_t hash = base::hash_range(module_bytes.start(), module_bytes.end());
280 EmbeddedVector<char, 32> buf;
281 SNPrintF(buf, "%016zx.%s.wasm", hash, ok() ? "ok" : "failed");
282 std::string name(buf.start());
283 if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
284 if (fwrite(module_bytes.start(), module_bytes.length(), 1, wasm_file) !=
285 1) {
286 OFStream os(stderr);
287 os << "Error while dumping wasm file" << std::endl;
288 }
289 fclose(wasm_file);
290 }
291 }
292
StartDecoding(Counters * counters,AccountingAllocator * allocator)293 void StartDecoding(Counters* counters, AccountingAllocator* allocator) {
294 CHECK_NULL(module_);
295 SetCounters(counters);
296 module_.reset(
297 new WasmModule(base::make_unique<Zone>(allocator, "signatures")));
298 module_->initial_pages = 0;
299 module_->maximum_pages = 0;
300 module_->mem_export = false;
301 module_->origin = origin_;
302 }
303
DecodeModuleHeader(Vector<const uint8_t> bytes,uint8_t offset)304 void DecodeModuleHeader(Vector<const uint8_t> bytes, uint8_t offset) {
305 if (failed()) return;
306 Reset(bytes, offset);
307
308 const byte* pos = pc_;
309 uint32_t magic_word = consume_u32("wasm magic");
310 #define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF
311 if (magic_word != kWasmMagic) {
312 errorf(pos,
313 "expected magic word %02x %02x %02x %02x, "
314 "found %02x %02x %02x %02x",
315 BYTES(kWasmMagic), BYTES(magic_word));
316 }
317
318 pos = pc_;
319 {
320 uint32_t magic_version = consume_u32("wasm version");
321 if (magic_version != kWasmVersion) {
322 errorf(pos,
323 "expected version %02x %02x %02x %02x, "
324 "found %02x %02x %02x %02x",
325 BYTES(kWasmVersion), BYTES(magic_version));
326 }
327 }
328 #undef BYTES
329 }
330
DecodeSection(SectionCode section_code,Vector<const uint8_t> bytes,uint32_t offset,bool verify_functions=true)331 void DecodeSection(SectionCode section_code, Vector<const uint8_t> bytes,
332 uint32_t offset, bool verify_functions = true) {
333 if (failed()) return;
334 Reset(bytes, offset);
335 TRACE("Section: %s\n", SectionName(section_code));
336 TRACE("Decode Section %p - %p\n", static_cast<const void*>(bytes.begin()),
337 static_cast<const void*>(bytes.end()));
338
339 // Check if the section is out-of-order.
340 if (section_code < next_section_) {
341 errorf(pc(), "unexpected section: %s", SectionName(section_code));
342 return;
343 }
344
345 switch (section_code) {
346 case kUnknownSectionCode:
347 break;
348 case kExceptionSectionCode:
349 // Note: kExceptionSectionCode > kCodeSectionCode, but must appear
350 // before the code section. Hence, treat it as a special case.
351 if (++number_of_exception_sections > 1) {
352 errorf(pc(), "Multiple exception sections not allowed");
353 return;
354 } else if (next_section_ >= kCodeSectionCode) {
355 errorf(pc(), "Exception section must appear before the code section");
356 return;
357 }
358 break;
359 default:
360 next_section_ = section_code;
361 ++next_section_;
362 break;
363 }
364
365 switch (section_code) {
366 case kUnknownSectionCode:
367 break;
368 case kTypeSectionCode:
369 DecodeTypeSection();
370 break;
371 case kImportSectionCode:
372 DecodeImportSection();
373 break;
374 case kFunctionSectionCode:
375 DecodeFunctionSection();
376 break;
377 case kTableSectionCode:
378 DecodeTableSection();
379 break;
380 case kMemorySectionCode:
381 DecodeMemorySection();
382 break;
383 case kGlobalSectionCode:
384 DecodeGlobalSection();
385 break;
386 case kExportSectionCode:
387 DecodeExportSection();
388 break;
389 case kStartSectionCode:
390 DecodeStartSection();
391 break;
392 case kCodeSectionCode:
393 DecodeCodeSection(verify_functions);
394 break;
395 case kElementSectionCode:
396 DecodeElementSection();
397 break;
398 case kDataSectionCode:
399 DecodeDataSection();
400 break;
401 case kNameSectionCode:
402 DecodeNameSection();
403 break;
404 case kExceptionSectionCode:
405 if (enabled_features_.eh) {
406 DecodeExceptionSection();
407 } else {
408 errorf(pc(), "unexpected section: %s", SectionName(section_code));
409 }
410 break;
411 default:
412 errorf(pc(), "unexpected section: %s", SectionName(section_code));
413 return;
414 }
415
416 if (pc() != bytes.end()) {
417 const char* msg = pc() < bytes.end() ? "shorter" : "longer";
418 errorf(pc(),
419 "section was %s than expected size "
420 "(%zu bytes expected, %zu decoded)",
421 msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin()));
422 }
423 }
424
DecodeTypeSection()425 void DecodeTypeSection() {
426 uint32_t signatures_count = consume_count("types count", kV8MaxWasmTypes);
427 module_->signatures.reserve(signatures_count);
428 for (uint32_t i = 0; ok() && i < signatures_count; ++i) {
429 TRACE("DecodeSignature[%d] module+%d\n", i,
430 static_cast<int>(pc_ - start_));
431 FunctionSig* s = consume_sig(module_->signature_zone.get());
432 module_->signatures.push_back(s);
433 uint32_t id = s ? module_->signature_map.FindOrInsert(*s) : 0;
434 module_->signature_ids.push_back(id);
435 }
436 module_->signature_map.Freeze();
437 }
438
DecodeImportSection()439 void DecodeImportSection() {
440 uint32_t import_table_count =
441 consume_count("imports count", kV8MaxWasmImports);
442 module_->import_table.reserve(import_table_count);
443 for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
444 TRACE("DecodeImportTable[%d] module+%d\n", i,
445 static_cast<int>(pc_ - start_));
446
447 module_->import_table.push_back({
448 {0, 0}, // module_name
449 {0, 0}, // field_name
450 kExternalFunction, // kind
451 0 // index
452 });
453 WasmImport* import = &module_->import_table.back();
454 const byte* pos = pc_;
455 import->module_name = consume_string(*this, true, "module name");
456 import->field_name = consume_string(*this, true, "field name");
457 import->kind =
458 static_cast<ImportExportKindCode>(consume_u8("import kind"));
459 switch (import->kind) {
460 case kExternalFunction: {
461 // ===== Imported function =======================================
462 import->index = static_cast<uint32_t>(module_->functions.size());
463 module_->num_imported_functions++;
464 module_->functions.push_back({nullptr, // sig
465 import->index, // func_index
466 0, // sig_index
467 {0, 0}, // code
468 true, // imported
469 false}); // exported
470 WasmFunction* function = &module_->functions.back();
471 function->sig_index =
472 consume_sig_index(module_.get(), &function->sig);
473 break;
474 }
475 case kExternalTable: {
476 // ===== Imported table ==========================================
477 if (!AddTable(module_.get())) break;
478 import->index = static_cast<uint32_t>(module_->tables.size());
479 module_->tables.emplace_back();
480 WasmTable* table = &module_->tables.back();
481 table->imported = true;
482 ValueType type = consume_reference_type();
483 if (!enabled_features_.anyref) {
484 if (type != kWasmAnyFunc) {
485 error(pc_ - 1, "invalid table type");
486 break;
487 }
488 }
489 table->type = type;
490 uint8_t flags = validate_table_flags("element count");
491 consume_resizable_limits(
492 "element count", "elements", FLAG_wasm_max_table_size,
493 &table->initial_size, &table->has_maximum_size,
494 FLAG_wasm_max_table_size, &table->maximum_size, flags);
495 break;
496 }
497 case kExternalMemory: {
498 // ===== Imported memory =========================================
499 if (!AddMemory(module_.get())) break;
500 uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
501 consume_resizable_limits(
502 "memory", "pages", FLAG_wasm_max_mem_pages,
503 &module_->initial_pages, &module_->has_maximum_pages,
504 kSpecMaxWasmMemoryPages, &module_->maximum_pages, flags);
505 break;
506 }
507 case kExternalGlobal: {
508 // ===== Imported global =========================================
509 import->index = static_cast<uint32_t>(module_->globals.size());
510 module_->globals.push_back(
511 {kWasmStmt, false, WasmInitExpr(), {0}, true, false});
512 WasmGlobal* global = &module_->globals.back();
513 global->type = consume_value_type();
514 global->mutability = consume_mutability();
515 if (global->mutability) {
516 if (enabled_features_.mut_global) {
517 module_->num_imported_mutable_globals++;
518 } else {
519 error("mutable globals cannot be imported");
520 }
521 }
522 break;
523 }
524 default:
525 errorf(pos, "unknown import kind 0x%02x", import->kind);
526 break;
527 }
528 }
529 }
530
DecodeFunctionSection()531 void DecodeFunctionSection() {
532 uint32_t functions_count =
533 consume_count("functions count", kV8MaxWasmFunctions);
534 auto counter =
535 SELECT_WASM_COUNTER(GetCounters(), origin_, wasm_functions_per, module);
536 counter->AddSample(static_cast<int>(functions_count));
537 DCHECK_EQ(module_->functions.size(), module_->num_imported_functions);
538 uint32_t total_function_count =
539 module_->num_imported_functions + functions_count;
540 module_->functions.reserve(total_function_count);
541 module_->num_declared_functions = functions_count;
542 for (uint32_t i = 0; i < functions_count; ++i) {
543 uint32_t func_index = static_cast<uint32_t>(module_->functions.size());
544 module_->functions.push_back({nullptr, // sig
545 func_index, // func_index
546 0, // sig_index
547 {0, 0}, // code
548 false, // imported
549 false}); // exported
550 WasmFunction* function = &module_->functions.back();
551 function->sig_index = consume_sig_index(module_.get(), &function->sig);
552 if (!ok()) return;
553 }
554 DCHECK_EQ(module_->functions.size(), total_function_count);
555 }
556
DecodeTableSection()557 void DecodeTableSection() {
558 // TODO(ahaas): Set the correct limit to {kV8MaxWasmTables} once the
559 // implementation of AnyRef landed.
560 uint32_t max_count = enabled_features_.anyref ? 10 : kV8MaxWasmTables;
561 uint32_t table_count = consume_count("table count", max_count);
562
563 for (uint32_t i = 0; ok() && i < table_count; i++) {
564 if (!AddTable(module_.get())) break;
565 module_->tables.emplace_back();
566 WasmTable* table = &module_->tables.back();
567 table->type = consume_reference_type();
568 uint8_t flags = validate_table_flags("table elements");
569 consume_resizable_limits(
570 "table elements", "elements", FLAG_wasm_max_table_size,
571 &table->initial_size, &table->has_maximum_size,
572 FLAG_wasm_max_table_size, &table->maximum_size, flags);
573 }
574 }
575
DecodeMemorySection()576 void DecodeMemorySection() {
577 uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
578
579 for (uint32_t i = 0; ok() && i < memory_count; i++) {
580 if (!AddMemory(module_.get())) break;
581 uint8_t flags = validate_memory_flags(&module_->has_shared_memory);
582 consume_resizable_limits(
583 "memory", "pages", FLAG_wasm_max_mem_pages, &module_->initial_pages,
584 &module_->has_maximum_pages, kSpecMaxWasmMemoryPages,
585 &module_->maximum_pages, flags);
586 }
587 }
588
DecodeGlobalSection()589 void DecodeGlobalSection() {
590 uint32_t globals_count = consume_count("globals count", kV8MaxWasmGlobals);
591 uint32_t imported_globals = static_cast<uint32_t>(module_->globals.size());
592 module_->globals.reserve(imported_globals + globals_count);
593 for (uint32_t i = 0; ok() && i < globals_count; ++i) {
594 TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
595 // Add an uninitialized global and pass a pointer to it.
596 module_->globals.push_back(
597 {kWasmStmt, false, WasmInitExpr(), {0}, false, false});
598 WasmGlobal* global = &module_->globals.back();
599 DecodeGlobalInModule(module_.get(), i + imported_globals, global);
600 }
601 if (ok()) CalculateGlobalOffsets(module_.get());
602 }
603
DecodeExportSection()604 void DecodeExportSection() {
605 uint32_t export_table_count =
606 consume_count("exports count", kV8MaxWasmExports);
607 module_->export_table.reserve(export_table_count);
608 for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
609 TRACE("DecodeExportTable[%d] module+%d\n", i,
610 static_cast<int>(pc_ - start_));
611
612 module_->export_table.push_back({
613 {0, 0}, // name
614 kExternalFunction, // kind
615 0 // index
616 });
617 WasmExport* exp = &module_->export_table.back();
618
619 exp->name = consume_string(*this, true, "field name");
620
621 const byte* pos = pc();
622 exp->kind = static_cast<ImportExportKindCode>(consume_u8("export kind"));
623 switch (exp->kind) {
624 case kExternalFunction: {
625 WasmFunction* func = nullptr;
626 exp->index = consume_func_index(module_.get(), &func);
627 module_->num_exported_functions++;
628 if (func) func->exported = true;
629 break;
630 }
631 case kExternalTable: {
632 WasmTable* table = nullptr;
633 exp->index = consume_table_index(module_.get(), &table);
634 if (table) table->exported = true;
635 break;
636 }
637 case kExternalMemory: {
638 uint32_t index = consume_u32v("memory index");
639 // TODO(titzer): This should become more regular
640 // once we support multiple memories.
641 if (!module_->has_memory || index != 0) {
642 error("invalid memory index != 0");
643 }
644 module_->mem_export = true;
645 break;
646 }
647 case kExternalGlobal: {
648 WasmGlobal* global = nullptr;
649 exp->index = consume_global_index(module_.get(), &global);
650 if (global) {
651 if (!enabled_features_.mut_global && global->mutability) {
652 error("mutable globals cannot be exported");
653 }
654 global->exported = true;
655 }
656 break;
657 }
658 default:
659 errorf(pos, "invalid export kind 0x%02x", exp->kind);
660 break;
661 }
662 }
663 // Check for duplicate exports (except for asm.js).
664 if (ok() && origin_ != kAsmJsOrigin && module_->export_table.size() > 1) {
665 std::vector<WasmExport> sorted_exports(module_->export_table);
666
667 auto cmp_less = [this](const WasmExport& a, const WasmExport& b) {
668 // Return true if a < b.
669 if (a.name.length() != b.name.length()) {
670 return a.name.length() < b.name.length();
671 }
672 const byte* left = start() + GetBufferRelativeOffset(a.name.offset());
673 const byte* right = start() + GetBufferRelativeOffset(b.name.offset());
674 return memcmp(left, right, a.name.length()) < 0;
675 };
676 std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less);
677
678 auto it = sorted_exports.begin();
679 WasmExport* last = &*it++;
680 for (auto end = sorted_exports.end(); it != end; last = &*it++) {
681 DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
682 if (!cmp_less(*last, *it)) {
683 const byte* pc = start() + GetBufferRelativeOffset(it->name.offset());
684 TruncatedUserString<> name(pc, it->name.length());
685 errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d",
686 name.length(), name.start(), ExternalKindName(last->kind),
687 last->index, ExternalKindName(it->kind), it->index);
688 break;
689 }
690 }
691 }
692 }
693
DecodeStartSection()694 void DecodeStartSection() {
695 WasmFunction* func;
696 const byte* pos = pc_;
697 module_->start_function_index = consume_func_index(module_.get(), &func);
698 if (func &&
699 (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
700 error(pos, "invalid start function: non-zero parameter or return count");
701 }
702 }
703
DecodeElementSection()704 void DecodeElementSection() {
705 uint32_t element_count =
706 consume_count("element count", FLAG_wasm_max_table_size);
707
708 if (element_count > 0 && module_->tables.size() == 0) {
709 error(pc_, "The element section requires a table");
710 }
711 for (uint32_t i = 0; ok() && i < element_count; ++i) {
712 const byte* pos = pc();
713 uint32_t table_index = consume_u32v("table index");
714 if (!enabled_features_.anyref && table_index != 0) {
715 errorf(pos, "illegal table index %u != 0", table_index);
716 }
717 if (table_index >= module_->tables.size()) {
718 errorf(pos, "out of bounds table index %u", table_index);
719 break;
720 }
721 if (module_->tables[table_index].type != kWasmAnyFunc) {
722 errorf(pos, "Invalid element segment. Table %u is not of type AnyFunc",
723 table_index);
724 break;
725 }
726 WasmInitExpr offset = consume_init_expr(module_.get(), kWasmI32);
727 uint32_t num_elem =
728 consume_count("number of elements", kV8MaxWasmTableEntries);
729 module_->table_inits.emplace_back(table_index, offset);
730 WasmTableInit* init = &module_->table_inits.back();
731 for (uint32_t j = 0; j < num_elem; j++) {
732 WasmFunction* func = nullptr;
733 uint32_t index = consume_func_index(module_.get(), &func);
734 DCHECK_IMPLIES(ok(), func != nullptr);
735 if (!ok()) break;
736 DCHECK_EQ(index, func->func_index);
737 init->entries.push_back(index);
738 }
739 }
740 }
741
DecodeCodeSection(bool verify_functions)742 void DecodeCodeSection(bool verify_functions) {
743 uint32_t pos = pc_offset();
744 uint32_t functions_count = consume_u32v("functions count");
745 CheckFunctionsCount(functions_count, pos);
746 for (uint32_t i = 0; ok() && i < functions_count; ++i) {
747 const byte* pos = pc();
748 uint32_t size = consume_u32v("body size");
749 if (size > kV8MaxWasmFunctionSize) {
750 errorf(pos, "size %u > maximum function size %zu", size,
751 kV8MaxWasmFunctionSize);
752 return;
753 }
754 uint32_t offset = pc_offset();
755 consume_bytes(size, "function body");
756 if (failed()) break;
757 DecodeFunctionBody(i, size, offset, verify_functions);
758 }
759 }
760
CheckFunctionsCount(uint32_t functions_count,uint32_t offset)761 bool CheckFunctionsCount(uint32_t functions_count, uint32_t offset) {
762 if (functions_count != module_->num_declared_functions) {
763 Reset(nullptr, nullptr, offset);
764 errorf(nullptr, "function body count %u mismatch (%u expected)",
765 functions_count, module_->num_declared_functions);
766 return false;
767 }
768 return true;
769 }
770
DecodeFunctionBody(uint32_t index,uint32_t length,uint32_t offset,bool verify_functions)771 void DecodeFunctionBody(uint32_t index, uint32_t length, uint32_t offset,
772 bool verify_functions) {
773 WasmFunction* function =
774 &module_->functions[index + module_->num_imported_functions];
775 function->code = {offset, length};
776 if (verify_functions) {
777 ModuleWireBytes bytes(start_, end_);
778 VerifyFunctionBody(module_->signature_zone->allocator(),
779 index + module_->num_imported_functions, bytes,
780 module_.get(), function);
781 }
782 }
783
DecodeDataSection()784 void DecodeDataSection() {
785 uint32_t data_segments_count =
786 consume_count("data segments count", kV8MaxWasmDataSegments);
787 module_->data_segments.reserve(data_segments_count);
788 for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
789 if (!module_->has_memory) {
790 error("cannot load data without memory");
791 break;
792 }
793 TRACE("DecodeDataSegment[%d] module+%d\n", i,
794 static_cast<int>(pc_ - start_));
795 module_->data_segments.push_back({
796 WasmInitExpr(), // dest_addr
797 {0, 0} // source
798 });
799 WasmDataSegment* segment = &module_->data_segments.back();
800 DecodeDataSegmentInModule(module_.get(), segment);
801 }
802 }
803
DecodeNameSection()804 void DecodeNameSection() {
805 // TODO(titzer): find a way to report name errors as warnings.
806 // Use an inner decoder so that errors don't fail the outer decoder.
807 Decoder inner(start_, pc_, end_, buffer_offset_);
808 // Decode all name subsections.
809 // Be lenient with their order.
810 while (inner.ok() && inner.more()) {
811 uint8_t name_type = inner.consume_u8("name type");
812 if (name_type & 0x80) inner.error("name type if not varuint7");
813
814 uint32_t name_payload_len = inner.consume_u32v("name payload length");
815 if (!inner.checkAvailable(name_payload_len)) break;
816
817 // Decode module name, ignore the rest.
818 // Function and local names will be decoded when needed.
819 if (name_type == NameSectionKindCode::kModule) {
820 WireBytesRef name = consume_string(inner, false, "module name");
821 if (inner.ok() && validate_utf8(&inner, name)) module_->name = name;
822 } else {
823 inner.consume_bytes(name_payload_len, "name subsection payload");
824 }
825 }
826 // Skip the whole names section in the outer decoder.
827 consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
828 }
829
DecodeExceptionSection()830 void DecodeExceptionSection() {
831 uint32_t exception_count =
832 consume_count("exception count", kV8MaxWasmExceptions);
833 for (uint32_t i = 0; ok() && i < exception_count; ++i) {
834 TRACE("DecodeExceptionSignature[%d] module+%d\n", i,
835 static_cast<int>(pc_ - start_));
836 module_->exceptions.emplace_back(
837 consume_exception_sig(module_->signature_zone.get()));
838 }
839 }
840
FinishDecoding(bool verify_functions=true)841 ModuleResult FinishDecoding(bool verify_functions = true) {
842 if (ok()) {
843 CalculateGlobalOffsets(module_.get());
844 }
845 ModuleResult result = toResult(std::move(module_));
846 if (verify_functions && result.ok()) {
847 // Copy error code and location.
848 result.MoveErrorFrom(intermediate_result_);
849 }
850 return result;
851 }
852
853 // Decodes an entire module.
DecodeModule(Counters * counters,AccountingAllocator * allocator,bool verify_functions=true)854 ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator,
855 bool verify_functions = true) {
856 StartDecoding(counters, allocator);
857 uint32_t offset = 0;
858 Vector<const byte> orig_bytes(start(), end() - start());
859 DecodeModuleHeader(Vector<const uint8_t>(start(), end() - start()), offset);
860 if (failed()) {
861 return FinishDecoding(verify_functions);
862 }
863 // Size of the module header.
864 offset += 8;
865 Decoder decoder(start_ + offset, end_, offset);
866
867 WasmSectionIterator section_iter(decoder);
868
869 while (ok() && section_iter.more()) {
870 // Shift the offset by the section header length
871 offset += section_iter.payload_start() - section_iter.section_start();
872 if (section_iter.section_code() != SectionCode::kUnknownSectionCode) {
873 DecodeSection(section_iter.section_code(), section_iter.payload(),
874 offset, verify_functions);
875 }
876 // Shift the offset by the remaining section payload
877 offset += section_iter.payload_length();
878 section_iter.advance(true);
879 }
880
881 if (FLAG_dump_wasm_module) DumpModule(orig_bytes);
882
883 if (decoder.failed()) {
884 return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr);
885 }
886
887 return FinishDecoding(verify_functions);
888 }
889
890 // Decodes a single anonymous function starting at {start_}.
DecodeSingleFunction(Zone * zone,const ModuleWireBytes & wire_bytes,const WasmModule * module,std::unique_ptr<WasmFunction> function)891 FunctionResult DecodeSingleFunction(Zone* zone,
892 const ModuleWireBytes& wire_bytes,
893 const WasmModule* module,
894 std::unique_ptr<WasmFunction> function) {
895 pc_ = start_;
896 function->sig = consume_sig(zone);
897 function->code = {off(pc_), static_cast<uint32_t>(end_ - pc_)};
898
899 if (ok())
900 VerifyFunctionBody(zone->allocator(), 0, wire_bytes, module,
901 function.get());
902
903 FunctionResult result(std::move(function));
904 // Copy error code and location.
905 result.MoveErrorFrom(intermediate_result_);
906 return result;
907 }
908
909 // Decodes a single function signature at {start}.
DecodeFunctionSignature(Zone * zone,const byte * start)910 FunctionSig* DecodeFunctionSignature(Zone* zone, const byte* start) {
911 pc_ = start;
912 FunctionSig* result = consume_sig(zone);
913 return ok() ? result : nullptr;
914 }
915
DecodeInitExpr(const byte * start)916 WasmInitExpr DecodeInitExpr(const byte* start) {
917 pc_ = start;
918 return consume_init_expr(nullptr, kWasmStmt);
919 }
920
shared_module() const921 const std::shared_ptr<WasmModule>& shared_module() const { return module_; }
922
GetCounters() const923 Counters* GetCounters() const {
924 DCHECK_NOT_NULL(counters_);
925 return counters_;
926 }
927
SetCounters(Counters * counters)928 void SetCounters(Counters* counters) {
929 DCHECK_NULL(counters_);
930 counters_ = counters;
931 }
932
933 private:
934 const WasmFeatures enabled_features_;
935 std::shared_ptr<WasmModule> module_;
936 Counters* counters_ = nullptr;
937 // The type section is the first section in a module.
938 uint8_t next_section_ = kFirstSectionInModule;
939 uint32_t number_of_exception_sections = 0;
940 // We store next_section_ as uint8_t instead of SectionCode so that we can
941 // increment it. This static_assert should make sure that SectionCode does not
942 // get bigger than uint8_t accidentially.
943 static_assert(sizeof(ModuleDecoderImpl::next_section_) == sizeof(SectionCode),
944 "type mismatch");
945 Result<bool> intermediate_result_;
946 ModuleOrigin origin_;
947
off(const byte * ptr)948 uint32_t off(const byte* ptr) {
949 return static_cast<uint32_t>(ptr - start_) + buffer_offset_;
950 }
951
AddTable(WasmModule * module)952 bool AddTable(WasmModule* module) {
953 if (enabled_features_.anyref) return true;
954 if (module->tables.size() > 0) {
955 error("At most one table is supported");
956 return false;
957 } else {
958 return true;
959 }
960 }
961
AddMemory(WasmModule * module)962 bool AddMemory(WasmModule* module) {
963 if (module->has_memory) {
964 error("At most one memory is supported");
965 return false;
966 } else {
967 module->has_memory = true;
968 return true;
969 }
970 }
971
972 // Decodes a single global entry inside a module starting at {pc_}.
DecodeGlobalInModule(WasmModule * module,uint32_t index,WasmGlobal * global)973 void DecodeGlobalInModule(WasmModule* module, uint32_t index,
974 WasmGlobal* global) {
975 global->type = consume_value_type();
976 global->mutability = consume_mutability();
977 const byte* pos = pc();
978 global->init = consume_init_expr(module, kWasmStmt);
979 if (global->init.kind == WasmInitExpr::kGlobalIndex) {
980 uint32_t other_index = global->init.val.global_index;
981 if (other_index >= index) {
982 errorf(pos,
983 "invalid global index in init expression, "
984 "index %u, other_index %u",
985 index, other_index);
986 } else if (module->globals[other_index].type != global->type) {
987 errorf(pos,
988 "type mismatch in global initialization "
989 "(from global #%u), expected %s, got %s",
990 other_index, ValueTypes::TypeName(global->type),
991 ValueTypes::TypeName(module->globals[other_index].type));
992 }
993 } else {
994 if (global->type != TypeOf(module, global->init)) {
995 errorf(pos, "type error in global initialization, expected %s, got %s",
996 ValueTypes::TypeName(global->type),
997 ValueTypes::TypeName(TypeOf(module, global->init)));
998 }
999 }
1000 }
1001
1002 // Decodes a single data segment entry inside a module starting at {pc_}.
DecodeDataSegmentInModule(WasmModule * module,WasmDataSegment * segment)1003 void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
1004 expect_u8("linear memory index", 0);
1005 segment->dest_addr = consume_init_expr(module, kWasmI32);
1006 uint32_t source_length = consume_u32v("source size");
1007 uint32_t source_offset = pc_offset();
1008
1009 consume_bytes(source_length, "segment data");
1010 if (failed()) return;
1011
1012 segment->source = {source_offset, source_length};
1013 }
1014
1015 // Calculate individual global offsets and total size of globals table.
CalculateGlobalOffsets(WasmModule * module)1016 void CalculateGlobalOffsets(WasmModule* module) {
1017 uint32_t offset = 0;
1018 uint32_t num_imported_mutable_globals = 0;
1019 if (module->globals.size() == 0) {
1020 module->globals_buffer_size = 0;
1021 return;
1022 }
1023 for (WasmGlobal& global : module->globals) {
1024 byte size = ValueTypes::MemSize(ValueTypes::MachineTypeFor(global.type));
1025 if (global.mutability && global.imported) {
1026 DCHECK(enabled_features_.mut_global);
1027 global.index = num_imported_mutable_globals++;
1028 } else {
1029 offset = (offset + size - 1) & ~(size - 1); // align
1030 global.offset = offset;
1031 offset += size;
1032 }
1033 }
1034 module->globals_buffer_size = offset;
1035 }
1036
1037 // Verifies the body (code) of a given function.
VerifyFunctionBody(AccountingAllocator * allocator,uint32_t func_num,const ModuleWireBytes & wire_bytes,const WasmModule * module,WasmFunction * function)1038 void VerifyFunctionBody(AccountingAllocator* allocator, uint32_t func_num,
1039 const ModuleWireBytes& wire_bytes,
1040 const WasmModule* module, WasmFunction* function) {
1041 WasmFunctionName func_name(function,
1042 wire_bytes.GetNameOrNull(function, module));
1043 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
1044 StdoutStream os;
1045 os << "Verifying wasm function " << func_name << std::endl;
1046 }
1047 FunctionBody body = {
1048 function->sig, function->code.offset(),
1049 start_ + GetBufferRelativeOffset(function->code.offset()),
1050 start_ + GetBufferRelativeOffset(function->code.end_offset())};
1051
1052 DecodeResult result;
1053 {
1054 auto time_counter = SELECT_WASM_COUNTER(GetCounters(), origin_,
1055 wasm_decode, function_time);
1056
1057 TimedHistogramScope wasm_decode_function_time_scope(time_counter);
1058 WasmFeatures unused_detected_features;
1059 result = VerifyWasmCode(allocator, enabled_features_, module,
1060 &unused_detected_features, body);
1061 }
1062
1063 if (result.failed()) {
1064 // Wrap the error message from the function decoder.
1065 std::ostringstream wrapped;
1066 wrapped << "in function " << func_name << ": " << result.error_msg();
1067 result.error(result.error_offset(), wrapped.str());
1068
1069 // Set error code and location, if this is the first error.
1070 if (intermediate_result_.ok()) {
1071 intermediate_result_.MoveErrorFrom(result);
1072 }
1073 }
1074 }
1075
consume_sig_index(WasmModule * module,FunctionSig ** sig)1076 uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
1077 const byte* pos = pc_;
1078 uint32_t sig_index = consume_u32v("signature index");
1079 if (sig_index >= module->signatures.size()) {
1080 errorf(pos, "signature index %u out of bounds (%d signatures)", sig_index,
1081 static_cast<int>(module->signatures.size()));
1082 *sig = nullptr;
1083 return 0;
1084 }
1085 *sig = module->signatures[sig_index];
1086 return sig_index;
1087 }
1088
consume_count(const char * name,size_t maximum)1089 uint32_t consume_count(const char* name, size_t maximum) {
1090 const byte* p = pc_;
1091 uint32_t count = consume_u32v(name);
1092 if (count > maximum) {
1093 errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum);
1094 return static_cast<uint32_t>(maximum);
1095 }
1096 return count;
1097 }
1098
consume_func_index(WasmModule * module,WasmFunction ** func)1099 uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
1100 return consume_index("function index", module->functions, func);
1101 }
1102
consume_global_index(WasmModule * module,WasmGlobal ** global)1103 uint32_t consume_global_index(WasmModule* module, WasmGlobal** global) {
1104 return consume_index("global index", module->globals, global);
1105 }
1106
consume_table_index(WasmModule * module,WasmTable ** table)1107 uint32_t consume_table_index(WasmModule* module, WasmTable** table) {
1108 return consume_index("table index", module->tables, table);
1109 }
1110
1111 template <typename T>
consume_index(const char * name,std::vector<T> & vector,T ** ptr)1112 uint32_t consume_index(const char* name, std::vector<T>& vector, T** ptr) {
1113 const byte* pos = pc_;
1114 uint32_t index = consume_u32v(name);
1115 if (index >= vector.size()) {
1116 errorf(pos, "%s %u out of bounds (%d entr%s)", name, index,
1117 static_cast<int>(vector.size()), vector.size() == 1 ? "y" : "ies");
1118 *ptr = nullptr;
1119 return 0;
1120 }
1121 *ptr = &vector[index];
1122 return index;
1123 }
1124
validate_table_flags(const char * name)1125 uint8_t validate_table_flags(const char* name) {
1126 uint8_t flags = consume_u8("resizable limits flags");
1127 const byte* pos = pc();
1128 if (flags & 0xFE) {
1129 errorf(pos - 1, "invalid %s limits flags", name);
1130 }
1131 return flags;
1132 }
1133
validate_memory_flags(bool * has_shared_memory)1134 uint8_t validate_memory_flags(bool* has_shared_memory) {
1135 uint8_t flags = consume_u8("resizable limits flags");
1136 const byte* pos = pc();
1137 *has_shared_memory = false;
1138 if (enabled_features_.threads) {
1139 if (flags & 0xFC) {
1140 errorf(pos - 1, "invalid memory limits flags");
1141 } else if (flags == 3) {
1142 DCHECK_NOT_NULL(has_shared_memory);
1143 *has_shared_memory = true;
1144 } else if (flags == 2) {
1145 errorf(pos - 1,
1146 "memory limits flags should have maximum defined if shared is "
1147 "true");
1148 }
1149 } else {
1150 if (flags & 0xFE) {
1151 errorf(pos - 1, "invalid memory limits flags");
1152 }
1153 }
1154 return flags;
1155 }
1156
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,uint8_t flags)1157 void consume_resizable_limits(const char* name, const char* units,
1158 uint32_t max_initial, uint32_t* initial,
1159 bool* has_max, uint32_t max_maximum,
1160 uint32_t* maximum, uint8_t flags) {
1161 const byte* pos = pc();
1162 *initial = consume_u32v("initial size");
1163 *has_max = false;
1164 if (*initial > max_initial) {
1165 errorf(pos,
1166 "initial %s size (%u %s) is larger than implementation limit (%u)",
1167 name, *initial, units, max_initial);
1168 }
1169 if (flags & 1) {
1170 *has_max = true;
1171 pos = pc();
1172 *maximum = consume_u32v("maximum size");
1173 if (*maximum > max_maximum) {
1174 errorf(
1175 pos,
1176 "maximum %s size (%u %s) is larger than implementation limit (%u)",
1177 name, *maximum, units, max_maximum);
1178 }
1179 if (*maximum < *initial) {
1180 errorf(pos, "maximum %s size (%u %s) is less than initial (%u %s)",
1181 name, *maximum, units, *initial, units);
1182 }
1183 } else {
1184 *has_max = false;
1185 *maximum = max_initial;
1186 }
1187 }
1188
expect_u8(const char * name,uint8_t expected)1189 bool expect_u8(const char* name, uint8_t expected) {
1190 const byte* pos = pc();
1191 uint8_t value = consume_u8(name);
1192 if (value != expected) {
1193 errorf(pos, "expected %s 0x%02x, got 0x%02x", name, expected, value);
1194 return false;
1195 }
1196 return true;
1197 }
1198
consume_init_expr(WasmModule * module,ValueType expected)1199 WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
1200 const byte* pos = pc();
1201 uint8_t opcode = consume_u8("opcode");
1202 WasmInitExpr expr;
1203 unsigned len = 0;
1204 switch (opcode) {
1205 case kExprGetGlobal: {
1206 GlobalIndexImmediate<Decoder::kValidate> imm(this, pc() - 1);
1207 if (module->globals.size() <= imm.index) {
1208 error("global index is out of bounds");
1209 expr.kind = WasmInitExpr::kNone;
1210 expr.val.i32_const = 0;
1211 break;
1212 }
1213 WasmGlobal* global = &module->globals[imm.index];
1214 if (global->mutability || !global->imported) {
1215 error(
1216 "only immutable imported globals can be used in initializer "
1217 "expressions");
1218 expr.kind = WasmInitExpr::kNone;
1219 expr.val.i32_const = 0;
1220 break;
1221 }
1222 expr.kind = WasmInitExpr::kGlobalIndex;
1223 expr.val.global_index = imm.index;
1224 len = imm.length;
1225 break;
1226 }
1227 case kExprI32Const: {
1228 ImmI32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1229 expr.kind = WasmInitExpr::kI32Const;
1230 expr.val.i32_const = imm.value;
1231 len = imm.length;
1232 break;
1233 }
1234 case kExprF32Const: {
1235 ImmF32Immediate<Decoder::kValidate> imm(this, pc() - 1);
1236 expr.kind = WasmInitExpr::kF32Const;
1237 expr.val.f32_const = imm.value;
1238 len = imm.length;
1239 break;
1240 }
1241 case kExprI64Const: {
1242 ImmI64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1243 expr.kind = WasmInitExpr::kI64Const;
1244 expr.val.i64_const = imm.value;
1245 len = imm.length;
1246 break;
1247 }
1248 case kExprF64Const: {
1249 ImmF64Immediate<Decoder::kValidate> imm(this, pc() - 1);
1250 expr.kind = WasmInitExpr::kF64Const;
1251 expr.val.f64_const = imm.value;
1252 len = imm.length;
1253 break;
1254 }
1255 case kExprRefNull: {
1256 if (enabled_features_.anyref) {
1257 expr.kind = WasmInitExpr::kAnyRefConst;
1258 len = 0;
1259 break;
1260 }
1261 V8_FALLTHROUGH;
1262 }
1263 default: {
1264 error("invalid opcode in initialization expression");
1265 expr.kind = WasmInitExpr::kNone;
1266 expr.val.i32_const = 0;
1267 }
1268 }
1269 consume_bytes(len, "init code");
1270 if (!expect_u8("end opcode", kExprEnd)) {
1271 expr.kind = WasmInitExpr::kNone;
1272 }
1273 if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
1274 errorf(pos, "type error in init expression, expected %s, got %s",
1275 ValueTypes::TypeName(expected),
1276 ValueTypes::TypeName(TypeOf(module, expr)));
1277 }
1278 return expr;
1279 }
1280
1281 // Read a mutability flag
consume_mutability()1282 bool consume_mutability() {
1283 byte val = consume_u8("mutability");
1284 if (val > 1) error(pc_ - 1, "invalid mutability");
1285 return val != 0;
1286 }
1287
1288 // Reads a single 8-bit integer, interpreting it as a local type.
consume_value_type()1289 ValueType consume_value_type() {
1290 byte val = consume_u8("value type");
1291 ValueTypeCode t = static_cast<ValueTypeCode>(val);
1292 switch (t) {
1293 case kLocalI32:
1294 return kWasmI32;
1295 case kLocalI64:
1296 return kWasmI64;
1297 case kLocalF32:
1298 return kWasmF32;
1299 case kLocalF64:
1300 return kWasmF64;
1301 default:
1302 if (origin_ == kWasmOrigin) {
1303 switch (t) {
1304 case kLocalS128:
1305 if (enabled_features_.simd) return kWasmS128;
1306 break;
1307 case kLocalAnyFunc:
1308 if (enabled_features_.anyref) return kWasmAnyFunc;
1309 break;
1310 case kLocalAnyRef:
1311 if (enabled_features_.anyref) return kWasmAnyRef;
1312 break;
1313 default:
1314 break;
1315 }
1316 }
1317 error(pc_ - 1, "invalid local type");
1318 return kWasmStmt;
1319 }
1320 }
1321
1322 // Reads a single 8-bit integer, interpreting it as a reference type.
consume_reference_type()1323 ValueType consume_reference_type() {
1324 byte val = consume_u8("reference type");
1325 ValueTypeCode t = static_cast<ValueTypeCode>(val);
1326 switch (t) {
1327 case kLocalAnyFunc:
1328 return kWasmAnyFunc;
1329 case kLocalAnyRef:
1330 if (!enabled_features_.anyref) {
1331 error(pc_ - 1,
1332 "Invalid type. Set --experimental-wasm-anyref to use 'AnyRef'");
1333 }
1334 return kWasmAnyRef;
1335 default:
1336 break;
1337 }
1338 error(pc_ - 1, "invalid reference type");
1339 return kWasmStmt;
1340 }
1341
consume_sig(Zone * zone)1342 FunctionSig* consume_sig(Zone* zone) {
1343 constexpr bool has_return_values = true;
1344 return consume_sig_internal(zone, has_return_values);
1345 }
1346
consume_exception_sig(Zone * zone)1347 WasmExceptionSig* consume_exception_sig(Zone* zone) {
1348 constexpr bool has_return_values = true;
1349 return consume_sig_internal(zone, !has_return_values);
1350 }
1351
1352 private:
consume_sig_internal(Zone * zone,bool has_return_values)1353 FunctionSig* consume_sig_internal(Zone* zone, bool has_return_values) {
1354 if (has_return_values && !expect_u8("type form", kWasmFunctionTypeCode))
1355 return nullptr;
1356 // parse parameter types
1357 uint32_t param_count =
1358 consume_count("param count", kV8MaxWasmFunctionParams);
1359 if (failed()) return nullptr;
1360 std::vector<ValueType> params;
1361 for (uint32_t i = 0; ok() && i < param_count; ++i) {
1362 ValueType param = consume_value_type();
1363 params.push_back(param);
1364 }
1365 std::vector<ValueType> returns;
1366 uint32_t return_count = 0;
1367 if (has_return_values) {
1368 // parse return types
1369 const size_t max_return_count = enabled_features_.mv
1370 ? kV8MaxWasmFunctionMultiReturns
1371 : kV8MaxWasmFunctionReturns;
1372 return_count = consume_count("return count", max_return_count);
1373 if (failed()) return nullptr;
1374 for (uint32_t i = 0; ok() && i < return_count; ++i) {
1375 ValueType ret = consume_value_type();
1376 returns.push_back(ret);
1377 }
1378 }
1379
1380 if (failed()) return nullptr;
1381
1382 // FunctionSig stores the return types first.
1383 ValueType* buffer = zone->NewArray<ValueType>(param_count + return_count);
1384 uint32_t b = 0;
1385 for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
1386 for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
1387
1388 return new (zone) FunctionSig(return_count, param_count, buffer);
1389 }
1390 };
1391
DecodeWasmModule(const WasmFeatures & enabled,const byte * module_start,const byte * module_end,bool verify_functions,ModuleOrigin origin,Counters * counters,AccountingAllocator * allocator)1392 ModuleResult DecodeWasmModule(const WasmFeatures& enabled,
1393 const byte* module_start, const byte* module_end,
1394 bool verify_functions, ModuleOrigin origin,
1395 Counters* counters,
1396 AccountingAllocator* allocator) {
1397 auto counter =
1398 SELECT_WASM_COUNTER(counters, origin, wasm_decode, module_time);
1399 TimedHistogramScope wasm_decode_module_time_scope(counter);
1400 size_t size = module_end - module_start;
1401 if (module_start > module_end) return ModuleResult::Error("start > end");
1402 if (size >= kV8MaxWasmModuleSize)
1403 return ModuleResult::Error("size > maximum module size: %zu", size);
1404 // TODO(bradnelson): Improve histogram handling of size_t.
1405 auto size_counter =
1406 SELECT_WASM_COUNTER(counters, origin, wasm, module_size_bytes);
1407 size_counter->AddSample(static_cast<int>(size));
1408 // Signatures are stored in zone memory, which have the same lifetime
1409 // as the {module}.
1410 ModuleDecoderImpl decoder(enabled, module_start, module_end, origin);
1411 ModuleResult result =
1412 decoder.DecodeModule(counters, allocator, verify_functions);
1413 // TODO(bradnelson): Improve histogram handling of size_t.
1414 // TODO(titzer): this isn't accurate, since it doesn't count the data
1415 // allocated on the C++ heap.
1416 // https://bugs.chromium.org/p/chromium/issues/detail?id=657320
1417 if (result.ok()) {
1418 auto peak_counter = SELECT_WASM_COUNTER(counters, origin, wasm_decode,
1419 module_peak_memory_bytes);
1420 peak_counter->AddSample(
1421 static_cast<int>(result.val->signature_zone->allocation_size()));
1422 }
1423 return result;
1424 }
1425
ModuleDecoder(const WasmFeatures & enabled)1426 ModuleDecoder::ModuleDecoder(const WasmFeatures& enabled)
1427 : enabled_features_(enabled) {}
1428
1429 ModuleDecoder::~ModuleDecoder() = default;
1430
shared_module() const1431 const std::shared_ptr<WasmModule>& ModuleDecoder::shared_module() const {
1432 return impl_->shared_module();
1433 }
1434
StartDecoding(Counters * counters,AccountingAllocator * allocator,ModuleOrigin origin)1435 void ModuleDecoder::StartDecoding(Counters* counters,
1436 AccountingAllocator* allocator,
1437 ModuleOrigin origin) {
1438 DCHECK_NULL(impl_);
1439 impl_.reset(new ModuleDecoderImpl(enabled_features_, origin));
1440 impl_->StartDecoding(counters, allocator);
1441 }
1442
DecodeModuleHeader(Vector<const uint8_t> bytes,uint32_t offset)1443 void ModuleDecoder::DecodeModuleHeader(Vector<const uint8_t> bytes,
1444 uint32_t offset) {
1445 impl_->DecodeModuleHeader(bytes, offset);
1446 }
1447
DecodeSection(SectionCode section_code,Vector<const uint8_t> bytes,uint32_t offset,bool verify_functions)1448 void ModuleDecoder::DecodeSection(SectionCode section_code,
1449 Vector<const uint8_t> bytes, uint32_t offset,
1450 bool verify_functions) {
1451 impl_->DecodeSection(section_code, bytes, offset, verify_functions);
1452 }
1453
DecodeFunctionBody(uint32_t index,uint32_t length,uint32_t offset,bool verify_functions)1454 void ModuleDecoder::DecodeFunctionBody(uint32_t index, uint32_t length,
1455 uint32_t offset, bool verify_functions) {
1456 impl_->DecodeFunctionBody(index, length, offset, verify_functions);
1457 }
1458
CheckFunctionsCount(uint32_t functions_count,uint32_t offset)1459 bool ModuleDecoder::CheckFunctionsCount(uint32_t functions_count,
1460 uint32_t offset) {
1461 return impl_->CheckFunctionsCount(functions_count, offset);
1462 }
1463
FinishDecoding(bool verify_functions)1464 ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
1465 return impl_->FinishDecoding(verify_functions);
1466 }
1467
IdentifyUnknownSection(Decoder & decoder,const byte * end)1468 SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder& decoder,
1469 const byte* end) {
1470 WireBytesRef string = consume_string(decoder, true, "section name");
1471 if (decoder.failed() || decoder.pc() > end) {
1472 return kUnknownSectionCode;
1473 }
1474 const byte* section_name_start =
1475 decoder.start() + decoder.GetBufferRelativeOffset(string.offset());
1476
1477 TRACE(" +%d section name : \"%.*s\"\n",
1478 static_cast<int>(section_name_start - decoder.start()),
1479 string.length() < 20 ? string.length() : 20, section_name_start);
1480
1481 if (string.length() == num_chars(kNameString) &&
1482 strncmp(reinterpret_cast<const char*>(section_name_start), kNameString,
1483 num_chars(kNameString)) == 0) {
1484 return kNameSectionCode;
1485 }
1486 return kUnknownSectionCode;
1487 }
1488
ok()1489 bool ModuleDecoder::ok() { return impl_->ok(); }
1490
DecodeWasmSignatureForTesting(const WasmFeatures & enabled,Zone * zone,const byte * start,const byte * end)1491 FunctionSig* DecodeWasmSignatureForTesting(const WasmFeatures& enabled,
1492 Zone* zone, const byte* start,
1493 const byte* end) {
1494 ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1495 return decoder.DecodeFunctionSignature(zone, start);
1496 }
1497
DecodeWasmInitExprForTesting(const WasmFeatures & enabled,const byte * start,const byte * end)1498 WasmInitExpr DecodeWasmInitExprForTesting(const WasmFeatures& enabled,
1499 const byte* start, const byte* end) {
1500 AccountingAllocator allocator;
1501 ModuleDecoderImpl decoder(enabled, start, end, kWasmOrigin);
1502 return decoder.DecodeInitExpr(start);
1503 }
1504
DecodeWasmFunctionForTesting(const WasmFeatures & enabled,Zone * zone,const ModuleWireBytes & wire_bytes,const WasmModule * module,const byte * function_start,const byte * function_end,Counters * counters)1505 FunctionResult DecodeWasmFunctionForTesting(
1506 const WasmFeatures& enabled, Zone* zone, const ModuleWireBytes& wire_bytes,
1507 const WasmModule* module, const byte* function_start,
1508 const byte* function_end, Counters* counters) {
1509 size_t size = function_end - function_start;
1510 if (function_start > function_end)
1511 return FunctionResult::Error("start > end");
1512 auto size_histogram = SELECT_WASM_COUNTER(counters, module->origin, wasm,
1513 function_size_bytes);
1514 // TODO(bradnelson): Improve histogram handling of ptrdiff_t.
1515 size_histogram->AddSample(static_cast<int>(size));
1516 if (size > kV8MaxWasmFunctionSize)
1517 return FunctionResult::Error("size > maximum function size: %zu", size);
1518 ModuleDecoderImpl decoder(enabled, function_start, function_end, kWasmOrigin);
1519 decoder.SetCounters(counters);
1520 return decoder.DecodeSingleFunction(zone, wire_bytes, module,
1521 base::make_unique<WasmFunction>());
1522 }
1523
DecodeAsmJsOffsets(const byte * tables_start,const byte * tables_end)1524 AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
1525 const byte* tables_end) {
1526 AsmJsOffsets table;
1527
1528 Decoder decoder(tables_start, tables_end);
1529 uint32_t functions_count = decoder.consume_u32v("functions count");
1530 // Reserve space for the entries, taking care of invalid input.
1531 if (functions_count < static_cast<unsigned>(tables_end - tables_start)) {
1532 table.reserve(functions_count);
1533 }
1534
1535 for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
1536 uint32_t size = decoder.consume_u32v("table size");
1537 if (size == 0) {
1538 table.emplace_back();
1539 continue;
1540 }
1541 if (!decoder.checkAvailable(size)) {
1542 decoder.error("illegal asm function offset table size");
1543 }
1544 const byte* table_end = decoder.pc() + size;
1545 uint32_t locals_size = decoder.consume_u32v("locals size");
1546 int function_start_position = decoder.consume_u32v("function start pos");
1547 int last_byte_offset = locals_size;
1548 int last_asm_position = function_start_position;
1549 std::vector<AsmJsOffsetEntry> func_asm_offsets;
1550 func_asm_offsets.reserve(size / 4); // conservative estimation
1551 // Add an entry for the stack check, associated with position 0.
1552 func_asm_offsets.push_back(
1553 {0, function_start_position, function_start_position});
1554 while (decoder.ok() && decoder.pc() < table_end) {
1555 last_byte_offset += decoder.consume_u32v("byte offset delta");
1556 int call_position =
1557 last_asm_position + decoder.consume_i32v("call position delta");
1558 int to_number_position =
1559 call_position + decoder.consume_i32v("to_number position delta");
1560 last_asm_position = to_number_position;
1561 func_asm_offsets.push_back(
1562 {last_byte_offset, call_position, to_number_position});
1563 }
1564 if (decoder.pc() != table_end) {
1565 decoder.error("broken asm offset table");
1566 }
1567 table.push_back(std::move(func_asm_offsets));
1568 }
1569 if (decoder.more()) decoder.error("unexpected additional bytes");
1570
1571 return decoder.toResult(std::move(table));
1572 }
1573
DecodeCustomSections(const byte * start,const byte * end)1574 std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
1575 const byte* end) {
1576 Decoder decoder(start, end);
1577 decoder.consume_bytes(4, "wasm magic");
1578 decoder.consume_bytes(4, "wasm version");
1579
1580 std::vector<CustomSectionOffset> result;
1581
1582 while (decoder.more()) {
1583 byte section_code = decoder.consume_u8("section code");
1584 uint32_t section_length = decoder.consume_u32v("section length");
1585 uint32_t section_start = decoder.pc_offset();
1586 if (section_code != 0) {
1587 // Skip known sections.
1588 decoder.consume_bytes(section_length, "section bytes");
1589 continue;
1590 }
1591 uint32_t name_length = decoder.consume_u32v("name length");
1592 uint32_t name_offset = decoder.pc_offset();
1593 decoder.consume_bytes(name_length, "section name");
1594 uint32_t payload_offset = decoder.pc_offset();
1595 if (section_length < (payload_offset - section_start)) {
1596 decoder.error("invalid section length");
1597 break;
1598 }
1599 uint32_t payload_length = section_length - (payload_offset - section_start);
1600 decoder.consume_bytes(payload_length);
1601 if (decoder.failed()) break;
1602 result.push_back({{section_start, section_length},
1603 {name_offset, name_length},
1604 {payload_offset, payload_length}});
1605 }
1606
1607 return result;
1608 }
1609
1610 namespace {
1611
FindSection(Decoder & decoder,SectionCode section_code)1612 bool FindSection(Decoder& decoder, SectionCode section_code) {
1613 static constexpr int kModuleHeaderSize = 8;
1614 decoder.consume_bytes(kModuleHeaderSize, "module header");
1615
1616 WasmSectionIterator section_iter(decoder);
1617
1618 while (decoder.ok() && section_iter.more() &&
1619 section_iter.section_code() != kNameSectionCode) {
1620 section_iter.advance(true);
1621 }
1622 if (!section_iter.more()) return false;
1623
1624 // Reset the decoder to not read beyond the name section end.
1625 decoder.Reset(section_iter.payload(), decoder.pc_offset());
1626 return true;
1627 }
1628
1629 } // namespace
1630
DecodeFunctionNames(const byte * module_start,const byte * module_end,std::unordered_map<uint32_t,WireBytesRef> * names)1631 void DecodeFunctionNames(const byte* module_start, const byte* module_end,
1632 std::unordered_map<uint32_t, WireBytesRef>* names) {
1633 DCHECK_NOT_NULL(names);
1634 DCHECK(names->empty());
1635
1636 Decoder decoder(module_start, module_end);
1637 if (!FindSection(decoder, kNameSectionCode)) return;
1638
1639 while (decoder.ok() && decoder.more()) {
1640 uint8_t name_type = decoder.consume_u8("name type");
1641 if (name_type & 0x80) break; // no varuint7
1642
1643 uint32_t name_payload_len = decoder.consume_u32v("name payload length");
1644 if (!decoder.checkAvailable(name_payload_len)) break;
1645
1646 if (name_type != NameSectionKindCode::kFunction) {
1647 decoder.consume_bytes(name_payload_len, "name subsection payload");
1648 continue;
1649 }
1650 uint32_t functions_count = decoder.consume_u32v("functions count");
1651
1652 for (; decoder.ok() && functions_count > 0; --functions_count) {
1653 uint32_t function_index = decoder.consume_u32v("function index");
1654 WireBytesRef name = consume_string(decoder, false, "function name");
1655
1656 // Be lenient with errors in the name section: Ignore non-UTF8 names. You
1657 // can even assign to the same function multiple times (last valid one
1658 // wins).
1659 if (decoder.ok() && validate_utf8(&decoder, name)) {
1660 names->insert(std::make_pair(function_index, name));
1661 }
1662 }
1663 }
1664 }
1665
DecodeLocalNames(const byte * module_start,const byte * module_end,LocalNames * result)1666 void DecodeLocalNames(const byte* module_start, const byte* module_end,
1667 LocalNames* result) {
1668 DCHECK_NOT_NULL(result);
1669 DCHECK(result->names.empty());
1670
1671 Decoder decoder(module_start, module_end);
1672 if (!FindSection(decoder, kNameSectionCode)) return;
1673
1674 while (decoder.ok() && decoder.more()) {
1675 uint8_t name_type = decoder.consume_u8("name type");
1676 if (name_type & 0x80) break; // no varuint7
1677
1678 uint32_t name_payload_len = decoder.consume_u32v("name payload length");
1679 if (!decoder.checkAvailable(name_payload_len)) break;
1680
1681 if (name_type != NameSectionKindCode::kLocal) {
1682 decoder.consume_bytes(name_payload_len, "name subsection payload");
1683 continue;
1684 }
1685
1686 uint32_t local_names_count = decoder.consume_u32v("local names count");
1687 for (uint32_t i = 0; i < local_names_count; ++i) {
1688 uint32_t func_index = decoder.consume_u32v("function index");
1689 if (func_index > kMaxInt) continue;
1690 result->names.emplace_back(static_cast<int>(func_index));
1691 LocalNamesPerFunction& func_names = result->names.back();
1692 result->max_function_index =
1693 std::max(result->max_function_index, func_names.function_index);
1694 uint32_t num_names = decoder.consume_u32v("namings count");
1695 for (uint32_t k = 0; k < num_names; ++k) {
1696 uint32_t local_index = decoder.consume_u32v("local index");
1697 WireBytesRef name = consume_string(decoder, true, "local name");
1698 if (!decoder.ok()) break;
1699 if (local_index > kMaxInt) continue;
1700 func_names.max_local_index =
1701 std::max(func_names.max_local_index, static_cast<int>(local_index));
1702 func_names.names.emplace_back(static_cast<int>(local_index), name);
1703 }
1704 }
1705 }
1706 }
1707
1708 #undef TRACE
1709
1710 } // namespace wasm
1711 } // namespace internal
1712 } // namespace v8
1713