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