blob: c356eb8f55ad32612f37e75ba0f145cd33ea0490 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
Ben Murdochda12d292016-06-02 14:46:10 +01005#include "src/wasm/module-decoder.h"
6
7#include "src/base/functional.h"
8#include "src/base/platform/platform.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/macro-assembler.h"
10#include "src/objects.h"
11#include "src/v8.h"
12
13#include "src/wasm/decoder.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014
15namespace v8 {
16namespace internal {
17namespace wasm {
18
19#if DEBUG
20#define TRACE(...) \
21 do { \
22 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
23 } while (false)
24#else
25#define TRACE(...)
26#endif
27
Ben Murdoch61f157c2016-09-16 13:49:30 +010028namespace {
29
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030// The main logic for decoding the bytes of a module.
31class ModuleDecoder : public Decoder {
32 public:
33 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
Ben Murdochda12d292016-06-02 14:46:10 +010034 ModuleOrigin origin)
35 : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 result_.start = start_;
37 if (limit_ < start_) {
38 error(start_, "end is less than start");
39 limit_ = start_;
40 }
41 }
42
43 virtual void onFirstError() {
44 pc_ = limit_; // On error, terminate section decoding loop.
45 }
46
Ben Murdochda12d292016-06-02 14:46:10 +010047 static void DumpModule(WasmModule* module, ModuleResult result) {
48 std::string path;
49 if (FLAG_dump_wasm_module_path) {
50 path = FLAG_dump_wasm_module_path;
51 if (path.size() &&
52 !base::OS::isDirectorySeparator(path[path.size() - 1])) {
53 path += base::OS::DirectorySeparator();
54 }
55 }
56 // File are named `HASH.{ok,failed}.wasm`.
57 size_t hash = base::hash_range(module->module_start, module->module_end);
58 char buf[32] = {'\0'};
59#if V8_OS_WIN && _MSC_VER < 1900
60#define snprintf sprintf_s
61#endif
62 snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash,
63 result.ok() ? "ok" : "failed");
64 std::string name(buf);
65 if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
66 fwrite(module->module_start, module->module_end - module->module_start, 1,
67 wasm_file);
68 fclose(wasm_file);
69 }
70 }
71
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 // Decodes an entire module.
73 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
74 pc_ = start_;
75 module->module_start = start_;
76 module->module_end = limit_;
Ben Murdochda12d292016-06-02 14:46:10 +010077 module->min_mem_pages = 0;
78 module->max_mem_pages = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 module->mem_export = false;
80 module->mem_external = false;
Ben Murdochda12d292016-06-02 14:46:10 +010081 module->origin = origin_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082
Ben Murdochda12d292016-06-02 14:46:10 +010083 const byte* pos = pc_;
Ben Murdochc5610432016-08-08 18:44:38 +010084 int current_order = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010085 uint32_t magic_word = consume_u32("wasm magic");
86#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
87 if (magic_word != kWasmMagic) {
88 error(pos, pos,
89 "expected magic word %02x %02x %02x %02x, "
90 "found %02x %02x %02x %02x",
91 BYTES(kWasmMagic), BYTES(magic_word));
92 goto done;
93 }
94
95 pos = pc_;
96 {
97 uint32_t magic_version = consume_u32("wasm version");
98 if (magic_version != kWasmVersion) {
99 error(pos, pos,
100 "expected version %02x %02x %02x %02x, "
101 "found %02x %02x %02x %02x",
102 BYTES(kWasmVersion), BYTES(magic_version));
103 goto done;
104 }
105 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106
107 // Decode the module sections.
108 while (pc_ < limit_) {
109 TRACE("DecodeSection\n");
Ben Murdochda12d292016-06-02 14:46:10 +0100110 pos = pc_;
111
Ben Murdochc5610432016-08-08 18:44:38 +0100112 // Read the section name.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100113 uint32_t string_length = consume_u32v("section name length");
Ben Murdochc5610432016-08-08 18:44:38 +0100114 const byte* section_name_start = pc_;
115 consume_bytes(string_length);
116 if (failed()) {
117 TRACE("Section name of length %u couldn't be read\n", string_length);
Ben Murdochda12d292016-06-02 14:46:10 +0100118 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 }
120
Ben Murdoch61f157c2016-09-16 13:49:30 +0100121 TRACE(" +%d section name : \"%.*s\"\n",
122 static_cast<int>(section_name_start - start_),
123 string_length < 20 ? string_length : 20, section_name_start);
124
Ben Murdochc5610432016-08-08 18:44:38 +0100125 WasmSection::Code section =
126 WasmSection::lookup(section_name_start, string_length);
Ben Murdochda12d292016-06-02 14:46:10 +0100127
Ben Murdochc5610432016-08-08 18:44:38 +0100128 // Read and check the section size.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100129 uint32_t section_length = consume_u32v("section length");
Ben Murdochc5610432016-08-08 18:44:38 +0100130 if (!checkAvailable(section_length)) {
131 // The section would extend beyond the end of the module.
132 break;
133 }
134 const byte* section_start = pc_;
135 const byte* expected_section_end = pc_ + section_length;
136
137 current_order = CheckSectionOrder(current_order, section);
Ben Murdochda12d292016-06-02 14:46:10 +0100138
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 switch (section) {
Ben Murdochda12d292016-06-02 14:46:10 +0100140 case WasmSection::Code::End:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000141 // Terminate section decoding.
142 limit_ = pc_;
143 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100144 case WasmSection::Code::Memory: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100145 module->min_mem_pages = consume_u32v("min memory");
146 module->max_mem_pages = consume_u32v("max memory");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100147 module->mem_export = consume_u8("export memory") != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100149 }
Ben Murdochda12d292016-06-02 14:46:10 +0100150 case WasmSection::Code::Signatures: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100151 uint32_t signatures_count = consume_u32v("signatures count");
Ben Murdochda12d292016-06-02 14:46:10 +0100152 module->signatures.reserve(SafeReserve(signatures_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 // Decode signatures.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100154 for (uint32_t i = 0; i < signatures_count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 if (failed()) break;
156 TRACE("DecodeSignature[%d] module+%d\n", i,
157 static_cast<int>(pc_ - start_));
Ben Murdochc5610432016-08-08 18:44:38 +0100158 FunctionSig* s = consume_sig();
Ben Murdochda12d292016-06-02 14:46:10 +0100159 module->signatures.push_back(s);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 }
161 break;
162 }
Ben Murdochda12d292016-06-02 14:46:10 +0100163 case WasmSection::Code::FunctionSignatures: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100164 uint32_t functions_count = consume_u32v("functions count");
Ben Murdochda12d292016-06-02 14:46:10 +0100165 module->functions.reserve(SafeReserve(functions_count));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100166 for (uint32_t i = 0; i < functions_count; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +0100167 module->functions.push_back({nullptr, // sig
168 i, // func_index
169 0, // sig_index
170 0, // name_offset
171 0, // name_length
172 0, // code_start_offset
Ben Murdoch61f157c2016-09-16 13:49:30 +0100173 0}); // code_end_offset
Ben Murdochda12d292016-06-02 14:46:10 +0100174 WasmFunction* function = &module->functions.back();
175 function->sig_index = consume_sig_index(module, &function->sig);
176 }
177 break;
178 }
179 case WasmSection::Code::FunctionBodies: {
Ben Murdochda12d292016-06-02 14:46:10 +0100180 const byte* pos = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100181 uint32_t functions_count = consume_u32v("functions count");
Ben Murdochda12d292016-06-02 14:46:10 +0100182 if (functions_count != module->functions.size()) {
183 error(pos, pos, "function body count %u mismatch (%u expected)",
184 functions_count,
185 static_cast<uint32_t>(module->functions.size()));
186 break;
187 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100188 for (uint32_t i = 0; i < functions_count; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100189 WasmFunction* function = &module->functions[i];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100190 uint32_t size = consume_u32v("body size");
Ben Murdochda12d292016-06-02 14:46:10 +0100191 function->code_start_offset = pc_offset();
192 function->code_end_offset = pc_offset() + size;
193
194 TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body",
195 size);
196 pc_ += size;
197 if (pc_ > limit_) {
198 error(pc_, "function body extends beyond end of file");
199 }
200 }
201 break;
202 }
Ben Murdochda12d292016-06-02 14:46:10 +0100203 case WasmSection::Code::Names: {
Ben Murdochda12d292016-06-02 14:46:10 +0100204 const byte* pos = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100205 uint32_t functions_count = consume_u32v("functions count");
Ben Murdochda12d292016-06-02 14:46:10 +0100206 if (functions_count != module->functions.size()) {
207 error(pos, pos, "function name count %u mismatch (%u expected)",
208 functions_count,
209 static_cast<uint32_t>(module->functions.size()));
210 break;
211 }
212
Ben Murdoch61f157c2016-09-16 13:49:30 +0100213 for (uint32_t i = 0; i < functions_count; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100214 WasmFunction* function = &module->functions[i];
215 function->name_offset =
Ben Murdochc5610432016-08-08 18:44:38 +0100216 consume_string(&function->name_length, false);
Ben Murdochda12d292016-06-02 14:46:10 +0100217
Ben Murdoch61f157c2016-09-16 13:49:30 +0100218 uint32_t local_names_count = consume_u32v("local names count");
Ben Murdochda12d292016-06-02 14:46:10 +0100219 for (uint32_t j = 0; j < local_names_count; j++) {
220 uint32_t unused = 0;
Ben Murdochc5610432016-08-08 18:44:38 +0100221 uint32_t offset = consume_string(&unused, false);
Ben Murdochda12d292016-06-02 14:46:10 +0100222 USE(unused);
223 USE(offset);
224 }
225 }
226 break;
227 }
228 case WasmSection::Code::Globals: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100229 uint32_t globals_count = consume_u32v("globals count");
Ben Murdochda12d292016-06-02 14:46:10 +0100230 module->globals.reserve(SafeReserve(globals_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 // Decode globals.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100232 for (uint32_t i = 0; i < globals_count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 if (failed()) break;
234 TRACE("DecodeGlobal[%d] module+%d\n", i,
235 static_cast<int>(pc_ - start_));
Ben Murdochda12d292016-06-02 14:46:10 +0100236 module->globals.push_back({0, 0, MachineType::Int32(), 0, false});
237 WasmGlobal* global = &module->globals.back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 DecodeGlobalInModule(global);
239 }
240 break;
241 }
Ben Murdochda12d292016-06-02 14:46:10 +0100242 case WasmSection::Code::DataSegments: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100243 uint32_t data_segments_count = consume_u32v("data segments count");
Ben Murdochda12d292016-06-02 14:46:10 +0100244 module->data_segments.reserve(SafeReserve(data_segments_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 // Decode data segments.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100246 for (uint32_t i = 0; i < data_segments_count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 if (failed()) break;
248 TRACE("DecodeDataSegment[%d] module+%d\n", i,
249 static_cast<int>(pc_ - start_));
Ben Murdochc5610432016-08-08 18:44:38 +0100250 module->data_segments.push_back({0, // dest_addr
251 0, // source_offset
252 0, // source_size
253 false}); // init
Ben Murdochda12d292016-06-02 14:46:10 +0100254 WasmDataSegment* segment = &module->data_segments.back();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100255 DecodeDataSegmentInModule(module, segment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 }
257 break;
258 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100259 case WasmSection::Code::FunctionTablePad: {
260 if (!FLAG_wasm_jit_prototype) {
261 error("FunctionTablePad section without jiting enabled");
262 }
263 // An indirect function table requires functions first.
264 module->indirect_table_size = consume_u32v("indirect entry count");
265 if (module->indirect_table_size > 0 &&
266 module->indirect_table_size < module->function_table.size()) {
267 error("more predefined indirect entries than table can hold");
268 }
269 break;
270 }
Ben Murdochda12d292016-06-02 14:46:10 +0100271 case WasmSection::Code::FunctionTable: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 // An indirect function table requires functions first.
Ben Murdochda12d292016-06-02 14:46:10 +0100273 CheckForFunctions(module, section);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100274 uint32_t function_table_count = consume_u32v("function table count");
Ben Murdochda12d292016-06-02 14:46:10 +0100275 module->function_table.reserve(SafeReserve(function_table_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 // Decode function table.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100277 for (uint32_t i = 0; i < function_table_count; ++i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 if (failed()) break;
279 TRACE("DecodeFunctionTable[%d] module+%d\n", i,
280 static_cast<int>(pc_ - start_));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100281 uint16_t index = consume_u32v();
Ben Murdochda12d292016-06-02 14:46:10 +0100282 if (index >= module->functions.size()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 error(pc_ - 2, "invalid function index");
284 break;
285 }
Ben Murdochda12d292016-06-02 14:46:10 +0100286 module->function_table.push_back(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100288 if (module->indirect_table_size > 0 &&
289 module->indirect_table_size < module->function_table.size()) {
290 error("more predefined indirect entries than table can hold");
291 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 break;
293 }
Ben Murdochda12d292016-06-02 14:46:10 +0100294 case WasmSection::Code::StartFunction: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100295 // Declares a start function for a module.
Ben Murdochda12d292016-06-02 14:46:10 +0100296 CheckForFunctions(module, section);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297 if (module->start_function_index >= 0) {
298 error("start function already declared");
299 break;
300 }
Ben Murdochda12d292016-06-02 14:46:10 +0100301 WasmFunction* func;
302 const byte* pos = pc_;
303 module->start_function_index = consume_func_index(module, &func);
304 if (func && func->sig->parameter_count() > 0) {
305 error(pos, "invalid start function: non-zero parameter count");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100306 break;
307 }
308 break;
309 }
Ben Murdochda12d292016-06-02 14:46:10 +0100310 case WasmSection::Code::ImportTable: {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100311 uint32_t import_table_count = consume_u32v("import table count");
Ben Murdochda12d292016-06-02 14:46:10 +0100312 module->import_table.reserve(SafeReserve(import_table_count));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100313 // Decode import table.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100314 for (uint32_t i = 0; i < import_table_count; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 if (failed()) break;
316 TRACE("DecodeImportTable[%d] module+%d\n", i,
317 static_cast<int>(pc_ - start_));
318
Ben Murdochc5610432016-08-08 18:44:38 +0100319 module->import_table.push_back({nullptr, // sig
320 0, // sig_index
321 0, // module_name_offset
322 0, // module_name_length
323 0, // function_name_offset
324 0}); // function_name_length
Ben Murdochda12d292016-06-02 14:46:10 +0100325 WasmImport* import = &module->import_table.back();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100326
Ben Murdochda12d292016-06-02 14:46:10 +0100327 import->sig_index = consume_sig_index(module, &import->sig);
328 const byte* pos = pc_;
Ben Murdochc5610432016-08-08 18:44:38 +0100329 import->module_name_offset =
330 consume_string(&import->module_name_length, true);
Ben Murdochda12d292016-06-02 14:46:10 +0100331 if (import->module_name_length == 0) {
332 error(pos, "import module name cannot be NULL");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100333 }
Ben Murdochc5610432016-08-08 18:44:38 +0100334 import->function_name_offset =
335 consume_string(&import->function_name_length, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100336 }
337 break;
338 }
Ben Murdochda12d292016-06-02 14:46:10 +0100339 case WasmSection::Code::ExportTable: {
340 // Declares an export table.
341 CheckForFunctions(module, section);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100342 uint32_t export_table_count = consume_u32v("export table count");
Ben Murdochda12d292016-06-02 14:46:10 +0100343 module->export_table.reserve(SafeReserve(export_table_count));
344 // Decode export table.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100345 for (uint32_t i = 0; i < export_table_count; ++i) {
Ben Murdochda12d292016-06-02 14:46:10 +0100346 if (failed()) break;
347 TRACE("DecodeExportTable[%d] module+%d\n", i,
348 static_cast<int>(pc_ - start_));
349
Ben Murdochc5610432016-08-08 18:44:38 +0100350 module->export_table.push_back({0, // func_index
351 0, // name_offset
352 0}); // name_length
Ben Murdochda12d292016-06-02 14:46:10 +0100353 WasmExport* exp = &module->export_table.back();
354
355 WasmFunction* func;
356 exp->func_index = consume_func_index(module, &func);
Ben Murdochc5610432016-08-08 18:44:38 +0100357 exp->name_offset = consume_string(&exp->name_length, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000358 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100359 // Check for duplicate exports.
360 if (ok() && module->export_table.size() > 1) {
361 std::vector<WasmExport> sorted_exports(module->export_table);
362 const byte* base = start_;
363 auto cmp_less = [base](const WasmExport& a, const WasmExport& b) {
364 // Return true if a < b.
365 uint32_t len = a.name_length;
366 if (len != b.name_length) return len < b.name_length;
367 return memcmp(base + a.name_offset, base + b.name_offset, len) <
368 0;
369 };
370 std::stable_sort(sorted_exports.begin(), sorted_exports.end(),
371 cmp_less);
372 auto it = sorted_exports.begin();
373 WasmExport* last = &*it++;
374 for (auto end = sorted_exports.end(); it != end; last = &*it++) {
375 DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
376 if (!cmp_less(*last, *it)) {
377 const byte* pc = start_ + it->name_offset;
378 error(pc, pc,
379 "Duplicate export name '%.*s' for functions %d and %d",
380 it->name_length, pc, last->func_index, it->func_index);
381 break;
382 }
383 }
384 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000385 break;
386 }
Ben Murdochda12d292016-06-02 14:46:10 +0100387 case WasmSection::Code::Max:
Ben Murdochc5610432016-08-08 18:44:38 +0100388 // Skip unknown sections.
389 TRACE("Unknown section: '");
390 for (uint32_t i = 0; i != string_length; ++i) {
391 TRACE("%c", *(section_name_start + i));
392 }
393 TRACE("'\n");
394 consume_bytes(section_length);
395 break;
396 }
397
398 if (pc_ != expected_section_end) {
399 const char* diff = pc_ < expected_section_end ? "shorter" : "longer";
400 size_t expected_length = static_cast<size_t>(section_length);
401 size_t actual_length = static_cast<size_t>(pc_ - section_start);
402 error(pc_, pc_,
403 "section \"%s\" %s (%zu bytes) than specified (%zu bytes)",
404 WasmSection::getName(section), diff, actual_length,
405 expected_length);
406 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000407 }
408 }
409
Ben Murdochda12d292016-06-02 14:46:10 +0100410 done:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100411 if (ok()) CalculateGlobalsOffsets(module);
412 const WasmModule* finished_module = module;
413 ModuleResult result = toResult(finished_module);
Ben Murdochda12d292016-06-02 14:46:10 +0100414 if (FLAG_dump_wasm_module) {
415 DumpModule(module, result);
416 }
417 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 }
419
420 uint32_t SafeReserve(uint32_t count) {
421 // Avoid OOM by only reserving up to a certain size.
422 const uint32_t kMaxReserve = 20000;
423 return count < kMaxReserve ? count : kMaxReserve;
424 }
425
Ben Murdochda12d292016-06-02 14:46:10 +0100426 void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
427 if (module->functions.size() == 0) {
428 error(pc_ - 1, nullptr, "functions must appear before section %s",
429 WasmSection::getName(section));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430 }
Ben Murdochda12d292016-06-02 14:46:10 +0100431 }
432
Ben Murdochc5610432016-08-08 18:44:38 +0100433 int CheckSectionOrder(int current_order, WasmSection::Code section) {
434 int next_order = WasmSection::getOrder(section);
435 if (next_order == 0) return current_order;
436 if (next_order == current_order) {
437 error(pc_, pc_, "section \"%s\" already defined",
Ben Murdochda12d292016-06-02 14:46:10 +0100438 WasmSection::getName(section));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 }
Ben Murdochc5610432016-08-08 18:44:38 +0100440 if (next_order < current_order) {
441 error(pc_, pc_, "section \"%s\" out of order",
442 WasmSection::getName(section));
443 }
444 return next_order;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445 }
446
447 // Decodes a single anonymous function starting at {start_}.
448 FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
449 WasmFunction* function) {
450 pc_ = start_;
Ben Murdochda12d292016-06-02 14:46:10 +0100451 function->sig = consume_sig(); // read signature
452 function->name_offset = 0; // ---- name
453 function->name_length = 0; // ---- name length
454 function->code_start_offset = off(pc_); // ---- code start
455 function->code_end_offset = off(limit_); // ---- code end
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000456
457 if (ok()) VerifyFunctionBody(0, module_env, function);
458
459 FunctionResult result;
460 result.CopyFrom(result_); // Copy error code and location.
461 result.val = function;
462 return result;
463 }
464
465 // Decodes a single function signature at {start}.
466 FunctionSig* DecodeFunctionSignature(const byte* start) {
467 pc_ = start;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100468 FunctionSig* result = consume_sig();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000469 return ok() ? result : nullptr;
470 }
471
472 private:
473 Zone* module_zone;
474 ModuleResult result_;
Ben Murdochda12d292016-06-02 14:46:10 +0100475 ModuleOrigin origin_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000476
477 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
478
479 // Decodes a single global entry inside a module starting at {pc_}.
480 void DecodeGlobalInModule(WasmGlobal* global) {
Ben Murdochc5610432016-08-08 18:44:38 +0100481 global->name_offset = consume_string(&global->name_length, false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100482 if (!unibrow::Utf8::Validate(start_ + global->name_offset,
483 global->name_length)) {
484 error("global name is not valid utf8");
485 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486 global->type = mem_type();
487 global->offset = 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100488 global->exported = consume_u8("exported") != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000489 }
490
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491 bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
492 if (offset > limit) return false;
493 if ((offset + size) < offset) return false; // overflow
494 return (offset + size) <= limit;
495 }
496
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 // Decodes a single data segment entry inside a module starting at {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100498 void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
Ben Murdochda12d292016-06-02 14:46:10 +0100499 const byte* start = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100500 segment->dest_addr = consume_u32v("destination");
501 segment->source_size = consume_u32v("source size");
Ben Murdochda12d292016-06-02 14:46:10 +0100502 segment->source_offset = static_cast<uint32_t>(pc_ - start_);
503 segment->init = true;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100504
505 // Validate the data is in the module.
506 uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
507 if (!IsWithinLimit(module_limit, segment->source_offset,
508 segment->source_size)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100509 error(start, "segment out of bounds of module");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100510 }
511
512 // Validate that the segment will fit into the (minimum) memory.
513 uint32_t memory_limit =
Ben Murdochda12d292016-06-02 14:46:10 +0100514 WasmModule::kPageSize * (module ? module->min_mem_pages
515 : WasmModule::kMaxMemPages);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100516 if (!IsWithinLimit(memory_limit, segment->dest_addr,
517 segment->source_size)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100518 error(start, "segment out of bounds of memory");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100519 }
Ben Murdochda12d292016-06-02 14:46:10 +0100520
521 consume_bytes(segment->source_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 }
523
Ben Murdoch61f157c2016-09-16 13:49:30 +0100524 // Calculate individual global offsets and total size of globals table.
525 void CalculateGlobalsOffsets(WasmModule* module) {
526 uint32_t offset = 0;
527 if (module->globals.size() == 0) {
528 module->globals_size = 0;
529 return;
530 }
531 for (WasmGlobal& global : module->globals) {
532 byte size = WasmOpcodes::MemSize(global.type);
533 offset = (offset + size - 1) & ~(size - 1); // align
534 global.offset = offset;
535 offset += size;
536 }
537 module->globals_size = offset;
538 }
539
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 // Verifies the body (code) of a given function.
541 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
542 WasmFunction* function) {
Ben Murdochc5610432016-08-08 18:44:38 +0100543 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000544 OFStream os(stdout);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100545 os << "Verifying WASM function " << WasmFunctionName(function, menv)
546 << std::endl;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 }
Ben Murdochda12d292016-06-02 14:46:10 +0100548 FunctionBody body = {menv, function->sig, start_,
549 start_ + function->code_start_offset,
550 start_ + function->code_end_offset};
551 TreeResult result = VerifyWasmCode(module_zone->allocator(), body);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 if (result.failed()) {
553 // Wrap the error message from the function decoder.
554 std::ostringstream str;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100555 str << "in function " << WasmFunctionName(function, menv) << ": ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000556 str << result;
557 std::string strval = str.str();
558 const char* raw = strval.c_str();
559 size_t len = strlen(raw);
560 char* buffer = new char[len];
561 strncpy(buffer, raw, len);
562 buffer[len - 1] = 0;
563
564 // Copy error code and location.
565 result_.CopyFrom(result);
566 result_.error_msg.Reset(buffer);
567 }
568 }
569
570 // Reads a single 32-bit unsigned integer interpreted as an offset, checking
571 // the offset is within bounds and advances.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100572 uint32_t consume_offset(const char* name = nullptr) {
573 uint32_t offset = consume_u32(name ? name : "offset");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000574 if (offset > static_cast<uint32_t>(limit_ - start_)) {
575 error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
576 }
577 return offset;
578 }
579
Ben Murdochda12d292016-06-02 14:46:10 +0100580 // Reads a length-prefixed string, checking that it is within bounds. Returns
581 // the offset of the string, and the length as an out parameter.
Ben Murdochc5610432016-08-08 18:44:38 +0100582 uint32_t consume_string(uint32_t* length, bool validate_utf8) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100583 *length = consume_u32v("string length");
Ben Murdochda12d292016-06-02 14:46:10 +0100584 uint32_t offset = pc_offset();
585 TRACE(" +%u %-20s: (%u bytes)\n", offset, "string", *length);
Ben Murdochc5610432016-08-08 18:44:38 +0100586 if (validate_utf8 && !unibrow::Utf8::Validate(pc_, *length)) {
587 error(pc_, "no valid UTF-8 string");
588 }
Ben Murdochda12d292016-06-02 14:46:10 +0100589 consume_bytes(*length);
590 return offset;
591 }
592
593 uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
594 const byte* pos = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100595 uint32_t sig_index = consume_u32v("signature index");
Ben Murdochda12d292016-06-02 14:46:10 +0100596 if (sig_index >= module->signatures.size()) {
597 error(pos, pos, "signature index %u out of bounds (%d signatures)",
598 sig_index, static_cast<int>(module->signatures.size()));
599 *sig = nullptr;
600 return 0;
601 }
602 *sig = module->signatures[sig_index];
603 return sig_index;
604 }
605
606 uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
607 const byte* pos = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100608 uint32_t func_index = consume_u32v("function index");
Ben Murdochda12d292016-06-02 14:46:10 +0100609 if (func_index >= module->functions.size()) {
610 error(pos, pos, "function index %u out of bounds (%d functions)",
611 func_index, static_cast<int>(module->functions.size()));
612 *func = nullptr;
613 return 0;
614 }
615 *func = &module->functions[func_index];
616 return func_index;
617 }
618
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 // Reads a single 8-bit integer, interpreting it as a local type.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100620 LocalType consume_local_type() {
621 byte val = consume_u8("local type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000622 LocalTypeCode t = static_cast<LocalTypeCode>(val);
623 switch (t) {
624 case kLocalVoid:
625 return kAstStmt;
626 case kLocalI32:
627 return kAstI32;
628 case kLocalI64:
629 return kAstI64;
630 case kLocalF32:
631 return kAstF32;
632 case kLocalF64:
633 return kAstF64;
634 default:
635 error(pc_ - 1, "invalid local type");
636 return kAstStmt;
637 }
638 }
639
640 // Reads a single 8-bit integer, interpreting it as a memory type.
641 MachineType mem_type() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100642 byte val = consume_u8("memory type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643 MemTypeCode t = static_cast<MemTypeCode>(val);
644 switch (t) {
645 case kMemI8:
646 return MachineType::Int8();
647 case kMemU8:
648 return MachineType::Uint8();
649 case kMemI16:
650 return MachineType::Int16();
651 case kMemU16:
652 return MachineType::Uint16();
653 case kMemI32:
654 return MachineType::Int32();
655 case kMemU32:
656 return MachineType::Uint32();
657 case kMemI64:
658 return MachineType::Int64();
659 case kMemU64:
660 return MachineType::Uint64();
661 case kMemF32:
662 return MachineType::Float32();
663 case kMemF64:
664 return MachineType::Float64();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100665 case kMemS128:
666 return MachineType::Simd128();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000667 default:
668 error(pc_ - 1, "invalid memory type");
669 return MachineType::None();
670 }
671 }
672
Ben Murdochc5610432016-08-08 18:44:38 +0100673 // Parses a type entry, which is currently limited to functions only.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 FunctionSig* consume_sig() {
Ben Murdochc5610432016-08-08 18:44:38 +0100675 const byte* pos = pc_;
676 byte form = consume_u8("type form");
677 if (form != kWasmFunctionTypeForm) {
678 error(pos, pos, "expected function type form (0x%02x), got: 0x%02x",
679 kWasmFunctionTypeForm, form);
680 return nullptr;
681 }
Ben Murdochc5610432016-08-08 18:44:38 +0100682 // parse parameter types
Ben Murdoch61f157c2016-09-16 13:49:30 +0100683 uint32_t param_count = consume_u32v("param count");
Ben Murdochc5610432016-08-08 18:44:38 +0100684 std::vector<LocalType> params;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100685 for (uint32_t i = 0; i < param_count; ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100686 LocalType param = consume_local_type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
Ben Murdochc5610432016-08-08 18:44:38 +0100688 params.push_back(param);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 }
Ben Murdochc5610432016-08-08 18:44:38 +0100690
691 // parse return types
692 const byte* pt = pc_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100693 uint32_t return_count = consume_u32v("return count");
Ben Murdochc5610432016-08-08 18:44:38 +0100694 if (return_count > kMaxReturnCount) {
695 error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
696 kMaxReturnCount);
697 return nullptr;
698 }
699 std::vector<LocalType> returns;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100700 for (uint32_t i = 0; i < return_count; ++i) {
Ben Murdochc5610432016-08-08 18:44:38 +0100701 LocalType ret = consume_local_type();
702 if (ret == kAstStmt) error(pc_ - 1, "invalid void return type");
703 returns.push_back(ret);
704 }
705
706 // FunctionSig stores the return types first.
707 LocalType* buffer =
708 module_zone->NewArray<LocalType>(param_count + return_count);
709 uint32_t b = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100710 for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
711 for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
Ben Murdochc5610432016-08-08 18:44:38 +0100712
713 return new (module_zone) FunctionSig(return_count, param_count, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 }
715};
716
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000717// Helpers for nice error messages.
718class ModuleError : public ModuleResult {
719 public:
720 explicit ModuleError(const char* msg) {
721 error_code = kError;
722 size_t len = strlen(msg) + 1;
723 char* result = new char[len];
724 strncpy(result, msg, len);
725 result[len - 1] = 0;
726 error_msg.Reset(result);
727 }
728};
729
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000730// Helpers for nice error messages.
731class FunctionError : public FunctionResult {
732 public:
733 explicit FunctionError(const char* msg) {
734 error_code = kError;
735 size_t len = strlen(msg) + 1;
736 char* result = new char[len];
737 strncpy(result, msg, len);
738 result[len - 1] = 0;
739 error_msg.Reset(result);
740 }
741};
742
Ben Murdoch61f157c2016-09-16 13:49:30 +0100743Vector<const byte> FindSection(const byte* module_start, const byte* module_end,
744 WasmSection::Code code) {
745 Decoder decoder(module_start, module_end);
746
747 uint32_t magic_word = decoder.consume_u32("wasm magic");
748 if (magic_word != kWasmMagic) decoder.error("wrong magic word");
749
750 uint32_t magic_version = decoder.consume_u32("wasm version");
751 if (magic_version != kWasmVersion) decoder.error("wrong wasm version");
752
753 while (decoder.more() && decoder.ok()) {
754 // Read the section name.
755 uint32_t string_length = decoder.consume_u32v("section name length");
756 const byte* section_name_start = decoder.pc();
757 decoder.consume_bytes(string_length);
758 if (decoder.failed()) break;
759
760 WasmSection::Code section =
761 WasmSection::lookup(section_name_start, string_length);
762
763 // Read and check the section size.
764 uint32_t section_length = decoder.consume_u32v("section length");
765
766 const byte* section_start = decoder.pc();
767 decoder.consume_bytes(section_length);
768 if (section == code && decoder.ok()) {
769 return Vector<const uint8_t>(section_start, section_length);
770 }
771 }
772
773 return Vector<const uint8_t>();
774}
775
776} // namespace
777
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000778ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
779 const byte* module_start, const byte* module_end,
Ben Murdochda12d292016-06-02 14:46:10 +0100780 bool verify_functions, ModuleOrigin origin) {
Ben Murdochc5610432016-08-08 18:44:38 +0100781 size_t decode_memory_start = zone->allocation_size();
782 HistogramTimerScope wasm_decode_module_time_scope(
783 isolate->counters()->wasm_decode_module_time());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 size_t size = module_end - module_start;
785 if (module_start > module_end) return ModuleError("start > end");
786 if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
Ben Murdochc5610432016-08-08 18:44:38 +0100787 // TODO(bradnelson): Improve histogram handling of size_t.
788 isolate->counters()->wasm_module_size_bytes()->AddSample(
789 static_cast<int>(size));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000790 WasmModule* module = new WasmModule();
Ben Murdochda12d292016-06-02 14:46:10 +0100791 ModuleDecoder decoder(zone, module_start, module_end, origin);
Ben Murdochc5610432016-08-08 18:44:38 +0100792 ModuleResult result = decoder.DecodeModule(module, verify_functions);
793 // TODO(bradnelson): Improve histogram handling of size_t.
794 isolate->counters()->wasm_decode_module_peak_memory_bytes()->AddSample(
795 static_cast<int>(zone->allocation_size() - decode_memory_start));
796 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000797}
798
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000799FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
800 const byte* end) {
Ben Murdochda12d292016-06-02 14:46:10 +0100801 ModuleDecoder decoder(zone, start, end, kWasmOrigin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000802 return decoder.DecodeFunctionSignature(start);
803}
804
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000805FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
806 ModuleEnv* module_env,
807 const byte* function_start,
808 const byte* function_end) {
Ben Murdochc5610432016-08-08 18:44:38 +0100809 HistogramTimerScope wasm_decode_function_time_scope(
810 isolate->counters()->wasm_decode_function_time());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000811 size_t size = function_end - function_start;
812 if (function_start > function_end) return FunctionError("start > end");
813 if (size > kMaxFunctionSize)
814 return FunctionError("size > maximum function size");
Ben Murdochc5610432016-08-08 18:44:38 +0100815 isolate->counters()->wasm_function_size_bytes()->AddSample(
816 static_cast<int>(size));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000817 WasmFunction* function = new WasmFunction();
Ben Murdochda12d292016-06-02 14:46:10 +0100818 ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000819 return decoder.DecodeSingleFunction(module_env, function);
820}
Ben Murdoch61f157c2016-09-16 13:49:30 +0100821
822FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start,
823 const byte* module_end) {
824 Vector<const byte> code_section =
825 FindSection(module_start, module_end, WasmSection::Code::FunctionBodies);
826 Decoder decoder(code_section.start(), code_section.end());
827 if (!code_section.start()) decoder.error("no code section");
828
829 uint32_t functions_count = decoder.consume_u32v("functions count");
830 FunctionOffsets table;
831 // Take care of invalid input here.
832 if (functions_count < static_cast<unsigned>(code_section.length()) / 2)
833 table.reserve(functions_count);
834 int section_offset = static_cast<int>(code_section.start() - module_start);
835 DCHECK_LE(0, section_offset);
836 for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
837 uint32_t size = decoder.consume_u32v("body size");
838 int offset = static_cast<int>(section_offset + decoder.pc_offset());
839 table.push_back(std::make_pair(offset, static_cast<int>(size)));
840 DCHECK(table.back().first >= 0 && table.back().second >= 0);
841 decoder.consume_bytes(size);
842 }
843 if (decoder.more()) decoder.error("unexpected additional bytes");
844
845 return decoder.toResult(std::move(table));
846}
847
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848} // namespace wasm
849} // namespace internal
850} // namespace v8