blob: f7d26a5f85645835a23965d52e4cc45db8bd9f3e [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 Murdoch4a90d5f2016-03-22 12:00:34 +000028// The main logic for decoding the bytes of a module.
29class ModuleDecoder : public Decoder {
30 public:
31 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
Ben Murdochda12d292016-06-02 14:46:10 +010032 ModuleOrigin origin)
33 : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000034 result_.start = start_;
35 if (limit_ < start_) {
36 error(start_, "end is less than start");
37 limit_ = start_;
38 }
39 }
40
41 virtual void onFirstError() {
42 pc_ = limit_; // On error, terminate section decoding loop.
43 }
44
Ben Murdochda12d292016-06-02 14:46:10 +010045 static void DumpModule(WasmModule* module, ModuleResult result) {
46 std::string path;
47 if (FLAG_dump_wasm_module_path) {
48 path = FLAG_dump_wasm_module_path;
49 if (path.size() &&
50 !base::OS::isDirectorySeparator(path[path.size() - 1])) {
51 path += base::OS::DirectorySeparator();
52 }
53 }
54 // File are named `HASH.{ok,failed}.wasm`.
55 size_t hash = base::hash_range(module->module_start, module->module_end);
56 char buf[32] = {'\0'};
57#if V8_OS_WIN && _MSC_VER < 1900
58#define snprintf sprintf_s
59#endif
60 snprintf(buf, sizeof(buf) - 1, "%016zx.%s.wasm", hash,
61 result.ok() ? "ok" : "failed");
62 std::string name(buf);
63 if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
64 fwrite(module->module_start, module->module_end - module->module_start, 1,
65 wasm_file);
66 fclose(wasm_file);
67 }
68 }
69
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070 // Decodes an entire module.
71 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
72 pc_ = start_;
73 module->module_start = start_;
74 module->module_end = limit_;
Ben Murdochda12d292016-06-02 14:46:10 +010075 module->min_mem_pages = 0;
76 module->max_mem_pages = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 module->mem_export = false;
78 module->mem_external = false;
Ben Murdochda12d292016-06-02 14:46:10 +010079 module->origin = origin_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080
Ben Murdochda12d292016-06-02 14:46:10 +010081 const byte* pos = pc_;
Ben Murdochc5610432016-08-08 18:44:38 +010082 int current_order = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010083 uint32_t magic_word = consume_u32("wasm magic");
84#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
85 if (magic_word != kWasmMagic) {
86 error(pos, pos,
87 "expected magic word %02x %02x %02x %02x, "
88 "found %02x %02x %02x %02x",
89 BYTES(kWasmMagic), BYTES(magic_word));
90 goto done;
91 }
92
93 pos = pc_;
94 {
95 uint32_t magic_version = consume_u32("wasm version");
96 if (magic_version != kWasmVersion) {
97 error(pos, pos,
98 "expected version %02x %02x %02x %02x, "
99 "found %02x %02x %02x %02x",
100 BYTES(kWasmVersion), BYTES(magic_version));
101 goto done;
102 }
103 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000104
105 // Decode the module sections.
106 while (pc_ < limit_) {
107 TRACE("DecodeSection\n");
Ben Murdochda12d292016-06-02 14:46:10 +0100108 pos = pc_;
109
Ben Murdochc5610432016-08-08 18:44:38 +0100110 // Read the section name.
111 int string_leb_length = 0;
112 uint32_t string_length =
113 consume_u32v(&string_leb_length, "section name length");
114 const byte* section_name_start = pc_;
115 consume_bytes(string_length);
116 if (failed()) {
117 TRACE("Section name of length %u couldn't be read\n", string_length);
Ben Murdochda12d292016-06-02 14:46:10 +0100118 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119 }
120
Ben Murdochc5610432016-08-08 18:44:38 +0100121 WasmSection::Code section =
122 WasmSection::lookup(section_name_start, string_length);
Ben Murdochda12d292016-06-02 14:46:10 +0100123
Ben Murdochc5610432016-08-08 18:44:38 +0100124 // Read and check the section size.
125 int section_leb_length = 0;
126 uint32_t section_length =
127 consume_u32v(&section_leb_length, "section length");
128 if (!checkAvailable(section_length)) {
129 // The section would extend beyond the end of the module.
130 break;
131 }
132 const byte* section_start = pc_;
133 const byte* expected_section_end = pc_ + section_length;
134
135 current_order = CheckSectionOrder(current_order, section);
Ben Murdochda12d292016-06-02 14:46:10 +0100136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 switch (section) {
Ben Murdochda12d292016-06-02 14:46:10 +0100138 case WasmSection::Code::End:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139 // Terminate section decoding.
140 limit_ = pc_;
141 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100142 case WasmSection::Code::Memory: {
Ben Murdochda12d292016-06-02 14:46:10 +0100143 int length;
144 module->min_mem_pages = consume_u32v(&length, "min memory");
145 module->max_mem_pages = consume_u32v(&length, "max memory");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100146 module->mem_export = consume_u8("export memory") != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147 break;
Ben Murdochc5610432016-08-08 18:44:38 +0100148 }
Ben Murdochda12d292016-06-02 14:46:10 +0100149 case WasmSection::Code::Signatures: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000150 int length;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100151 uint32_t signatures_count = consume_u32v(&length, "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.
154 for (uint32_t i = 0; i < signatures_count; i++) {
155 if (failed()) break;
156 TRACE("DecodeSignature[%d] module+%d\n", i,
157 static_cast<int>(pc_ - start_));
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 Murdoch4a90d5f2016-03-22 12:00:34 +0000164 int length;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100165 uint32_t functions_count = consume_u32v(&length, "functions count");
Ben Murdochda12d292016-06-02 14:46:10 +0100166 module->functions.reserve(SafeReserve(functions_count));
167 for (uint32_t i = 0; i < functions_count; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100168 module->functions.push_back({nullptr, // sig
169 i, // func_index
170 0, // sig_index
171 0, // name_offset
172 0, // name_length
173 0, // code_start_offset
174 0, // code_end_offset
175 false}); // exported
Ben Murdochda12d292016-06-02 14:46:10 +0100176 WasmFunction* function = &module->functions.back();
177 function->sig_index = consume_sig_index(module, &function->sig);
178 }
179 break;
180 }
181 case WasmSection::Code::FunctionBodies: {
Ben Murdochda12d292016-06-02 14:46:10 +0100182 int length;
183 const byte* pos = pc_;
184 uint32_t functions_count = consume_u32v(&length, "functions count");
185 if (functions_count != module->functions.size()) {
186 error(pos, pos, "function body count %u mismatch (%u expected)",
187 functions_count,
188 static_cast<uint32_t>(module->functions.size()));
189 break;
190 }
191 for (uint32_t i = 0; i < functions_count; i++) {
192 WasmFunction* function = &module->functions[i];
193 int length;
194 uint32_t size = consume_u32v(&length, "body size");
195 function->code_start_offset = pc_offset();
196 function->code_end_offset = pc_offset() + size;
197
198 TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body",
199 size);
200 pc_ += size;
201 if (pc_ > limit_) {
202 error(pc_, "function body extends beyond end of file");
203 }
204 }
205 break;
206 }
Ben Murdochc5610432016-08-08 18:44:38 +0100207 case WasmSection::Code::OldFunctions: {
Ben Murdochda12d292016-06-02 14:46:10 +0100208 int length;
209 uint32_t functions_count = consume_u32v(&length, "functions count");
210 module->functions.reserve(SafeReserve(functions_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 // Set up module environment for verification.
212 ModuleEnv menv;
213 menv.module = module;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 menv.instance = nullptr;
Ben Murdochda12d292016-06-02 14:46:10 +0100215 menv.origin = origin_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 // Decode functions.
217 for (uint32_t i = 0; i < functions_count; i++) {
218 if (failed()) break;
219 TRACE("DecodeFunction[%d] module+%d\n", i,
220 static_cast<int>(pc_ - start_));
221
Ben Murdochc5610432016-08-08 18:44:38 +0100222 module->functions.push_back({nullptr, // sig
223 i, // func_index
224 0, // sig_index
225 0, // name_offset
226 0, // name_length
227 0, // code_start_offset
228 0, // code_end_offset
229 false}); // exported
Ben Murdochda12d292016-06-02 14:46:10 +0100230 WasmFunction* function = &module->functions.back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 DecodeFunctionInModule(module, function, false);
232 }
233 if (ok() && verify_functions) {
234 for (uint32_t i = 0; i < functions_count; i++) {
235 if (failed()) break;
Ben Murdochda12d292016-06-02 14:46:10 +0100236 WasmFunction* function = &module->functions[i];
Ben Murdochc5610432016-08-08 18:44:38 +0100237 VerifyFunctionBody(i, &menv, function);
238 if (result_.failed()) {
239 error(result_.error_pc, result_.error_msg.get());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 }
241 }
242 }
243 break;
244 }
Ben Murdochda12d292016-06-02 14:46:10 +0100245 case WasmSection::Code::Names: {
Ben Murdochda12d292016-06-02 14:46:10 +0100246 int length;
247 const byte* pos = pc_;
248 uint32_t functions_count = consume_u32v(&length, "functions count");
249 if (functions_count != module->functions.size()) {
250 error(pos, pos, "function name count %u mismatch (%u expected)",
251 functions_count,
252 static_cast<uint32_t>(module->functions.size()));
253 break;
254 }
255
256 for (uint32_t i = 0; i < functions_count; i++) {
257 WasmFunction* function = &module->functions[i];
258 function->name_offset =
Ben Murdochc5610432016-08-08 18:44:38 +0100259 consume_string(&function->name_length, false);
Ben Murdochda12d292016-06-02 14:46:10 +0100260
261 uint32_t local_names_count =
262 consume_u32v(&length, "local names count");
263 for (uint32_t j = 0; j < local_names_count; j++) {
264 uint32_t unused = 0;
Ben Murdochc5610432016-08-08 18:44:38 +0100265 uint32_t offset = consume_string(&unused, false);
Ben Murdochda12d292016-06-02 14:46:10 +0100266 USE(unused);
267 USE(offset);
268 }
269 }
270 break;
271 }
272 case WasmSection::Code::Globals: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 int length;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100274 uint32_t globals_count = consume_u32v(&length, "globals count");
Ben Murdochda12d292016-06-02 14:46:10 +0100275 module->globals.reserve(SafeReserve(globals_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 // Decode globals.
277 for (uint32_t i = 0; i < globals_count; i++) {
278 if (failed()) break;
279 TRACE("DecodeGlobal[%d] module+%d\n", i,
280 static_cast<int>(pc_ - start_));
Ben Murdochda12d292016-06-02 14:46:10 +0100281 module->globals.push_back({0, 0, MachineType::Int32(), 0, false});
282 WasmGlobal* global = &module->globals.back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000283 DecodeGlobalInModule(global);
284 }
285 break;
286 }
Ben Murdochda12d292016-06-02 14:46:10 +0100287 case WasmSection::Code::DataSegments: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 int length;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 uint32_t data_segments_count =
290 consume_u32v(&length, "data segments count");
Ben Murdochda12d292016-06-02 14:46:10 +0100291 module->data_segments.reserve(SafeReserve(data_segments_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 // Decode data segments.
293 for (uint32_t i = 0; i < data_segments_count; i++) {
294 if (failed()) break;
295 TRACE("DecodeDataSegment[%d] module+%d\n", i,
296 static_cast<int>(pc_ - start_));
Ben Murdochc5610432016-08-08 18:44:38 +0100297 module->data_segments.push_back({0, // dest_addr
298 0, // source_offset
299 0, // source_size
300 false}); // init
Ben Murdochda12d292016-06-02 14:46:10 +0100301 WasmDataSegment* segment = &module->data_segments.back();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 DecodeDataSegmentInModule(module, segment);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 }
304 break;
305 }
Ben Murdochda12d292016-06-02 14:46:10 +0100306 case WasmSection::Code::FunctionTable: {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 // An indirect function table requires functions first.
Ben Murdochda12d292016-06-02 14:46:10 +0100308 CheckForFunctions(module, section);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309 int length;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100310 uint32_t function_table_count =
311 consume_u32v(&length, "function table count");
Ben Murdochda12d292016-06-02 14:46:10 +0100312 module->function_table.reserve(SafeReserve(function_table_count));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000313 // Decode function table.
314 for (uint32_t i = 0; i < function_table_count; i++) {
315 if (failed()) break;
316 TRACE("DecodeFunctionTable[%d] module+%d\n", i,
317 static_cast<int>(pc_ - start_));
Ben Murdochda12d292016-06-02 14:46:10 +0100318 uint16_t index = consume_u32v(&length);
319 if (index >= module->functions.size()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320 error(pc_ - 2, "invalid function index");
321 break;
322 }
Ben Murdochda12d292016-06-02 14:46:10 +0100323 module->function_table.push_back(index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 }
325 break;
326 }
Ben Murdochda12d292016-06-02 14:46:10 +0100327 case WasmSection::Code::StartFunction: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100328 // Declares a start function for a module.
Ben Murdochda12d292016-06-02 14:46:10 +0100329 CheckForFunctions(module, section);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100330 if (module->start_function_index >= 0) {
331 error("start function already declared");
332 break;
333 }
Ben Murdochda12d292016-06-02 14:46:10 +0100334 WasmFunction* func;
335 const byte* pos = pc_;
336 module->start_function_index = consume_func_index(module, &func);
337 if (func && func->sig->parameter_count() > 0) {
338 error(pos, "invalid start function: non-zero parameter count");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100339 break;
340 }
341 break;
342 }
Ben Murdochda12d292016-06-02 14:46:10 +0100343 case WasmSection::Code::ImportTable: {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100344 int length;
345 uint32_t import_table_count =
346 consume_u32v(&length, "import table count");
Ben Murdochda12d292016-06-02 14:46:10 +0100347 module->import_table.reserve(SafeReserve(import_table_count));
Ben Murdoch097c5b22016-05-18 11:27:45 +0100348 // Decode import table.
349 for (uint32_t i = 0; i < import_table_count; i++) {
350 if (failed()) break;
351 TRACE("DecodeImportTable[%d] module+%d\n", i,
352 static_cast<int>(pc_ - start_));
353
Ben Murdochc5610432016-08-08 18:44:38 +0100354 module->import_table.push_back({nullptr, // sig
355 0, // sig_index
356 0, // module_name_offset
357 0, // module_name_length
358 0, // function_name_offset
359 0}); // function_name_length
Ben Murdochda12d292016-06-02 14:46:10 +0100360 WasmImport* import = &module->import_table.back();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100361
Ben Murdochda12d292016-06-02 14:46:10 +0100362 import->sig_index = consume_sig_index(module, &import->sig);
363 const byte* pos = pc_;
Ben Murdochc5610432016-08-08 18:44:38 +0100364 import->module_name_offset =
365 consume_string(&import->module_name_length, true);
Ben Murdochda12d292016-06-02 14:46:10 +0100366 if (import->module_name_length == 0) {
367 error(pos, "import module name cannot be NULL");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100368 }
Ben Murdochc5610432016-08-08 18:44:38 +0100369 import->function_name_offset =
370 consume_string(&import->function_name_length, true);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100371 }
372 break;
373 }
Ben Murdochda12d292016-06-02 14:46:10 +0100374 case WasmSection::Code::ExportTable: {
375 // Declares an export table.
376 CheckForFunctions(module, section);
377 int length;
378 uint32_t export_table_count =
379 consume_u32v(&length, "export table count");
380 module->export_table.reserve(SafeReserve(export_table_count));
381 // Decode export table.
382 for (uint32_t i = 0; i < export_table_count; i++) {
383 if (failed()) break;
384 TRACE("DecodeExportTable[%d] module+%d\n", i,
385 static_cast<int>(pc_ - start_));
386
Ben Murdochc5610432016-08-08 18:44:38 +0100387 module->export_table.push_back({0, // func_index
388 0, // name_offset
389 0}); // name_length
Ben Murdochda12d292016-06-02 14:46:10 +0100390 WasmExport* exp = &module->export_table.back();
391
392 WasmFunction* func;
393 exp->func_index = consume_func_index(module, &func);
Ben Murdochc5610432016-08-08 18:44:38 +0100394 exp->name_offset = consume_string(&exp->name_length, true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 break;
397 }
Ben Murdochda12d292016-06-02 14:46:10 +0100398 case WasmSection::Code::Max:
Ben Murdochc5610432016-08-08 18:44:38 +0100399 // Skip unknown sections.
400 TRACE("Unknown section: '");
401 for (uint32_t i = 0; i != string_length; ++i) {
402 TRACE("%c", *(section_name_start + i));
403 }
404 TRACE("'\n");
405 consume_bytes(section_length);
406 break;
407 }
408
409 if (pc_ != expected_section_end) {
410 const char* diff = pc_ < expected_section_end ? "shorter" : "longer";
411 size_t expected_length = static_cast<size_t>(section_length);
412 size_t actual_length = static_cast<size_t>(pc_ - section_start);
413 error(pc_, pc_,
414 "section \"%s\" %s (%zu bytes) than specified (%zu bytes)",
415 WasmSection::getName(section), diff, actual_length,
416 expected_length);
417 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 }
419 }
420
Ben Murdochda12d292016-06-02 14:46:10 +0100421 done:
422 ModuleResult result = toResult(module);
423 if (FLAG_dump_wasm_module) {
424 DumpModule(module, result);
425 }
426 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 }
428
429 uint32_t SafeReserve(uint32_t count) {
430 // Avoid OOM by only reserving up to a certain size.
431 const uint32_t kMaxReserve = 20000;
432 return count < kMaxReserve ? count : kMaxReserve;
433 }
434
Ben Murdochda12d292016-06-02 14:46:10 +0100435 void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
436 if (module->functions.size() == 0) {
437 error(pc_ - 1, nullptr, "functions must appear before section %s",
438 WasmSection::getName(section));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000439 }
Ben Murdochda12d292016-06-02 14:46:10 +0100440 }
441
Ben Murdochc5610432016-08-08 18:44:38 +0100442 int CheckSectionOrder(int current_order, WasmSection::Code section) {
443 int next_order = WasmSection::getOrder(section);
444 if (next_order == 0) return current_order;
445 if (next_order == current_order) {
446 error(pc_, pc_, "section \"%s\" already defined",
Ben Murdochda12d292016-06-02 14:46:10 +0100447 WasmSection::getName(section));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 }
Ben Murdochc5610432016-08-08 18:44:38 +0100449 if (next_order < current_order) {
450 error(pc_, pc_, "section \"%s\" out of order",
451 WasmSection::getName(section));
452 }
453 return next_order;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000454 }
455
456 // Decodes a single anonymous function starting at {start_}.
457 FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
458 WasmFunction* function) {
459 pc_ = start_;
Ben Murdochda12d292016-06-02 14:46:10 +0100460 function->sig = consume_sig(); // read signature
461 function->name_offset = 0; // ---- name
462 function->name_length = 0; // ---- name length
463 function->code_start_offset = off(pc_); // ---- code start
464 function->code_end_offset = off(limit_); // ---- code end
465 function->exported = false; // ---- exported
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000466
467 if (ok()) VerifyFunctionBody(0, module_env, function);
468
469 FunctionResult result;
470 result.CopyFrom(result_); // Copy error code and location.
471 result.val = function;
472 return result;
473 }
474
475 // Decodes a single function signature at {start}.
476 FunctionSig* DecodeFunctionSignature(const byte* start) {
477 pc_ = start;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100478 FunctionSig* result = consume_sig();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 return ok() ? result : nullptr;
480 }
481
482 private:
483 Zone* module_zone;
484 ModuleResult result_;
Ben Murdochda12d292016-06-02 14:46:10 +0100485 ModuleOrigin origin_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000486
487 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
488
489 // Decodes a single global entry inside a module starting at {pc_}.
490 void DecodeGlobalInModule(WasmGlobal* global) {
Ben Murdochc5610432016-08-08 18:44:38 +0100491 global->name_offset = consume_string(&global->name_length, false);
492 DCHECK(unibrow::Utf8::Validate(start_ + global->name_offset,
493 global->name_length));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 global->type = mem_type();
495 global->offset = 0;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100496 global->exported = consume_u8("exported") != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 }
498
499 // Decodes a single function entry inside a module starting at {pc_}.
Ben Murdochda12d292016-06-02 14:46:10 +0100500 // TODO(titzer): legacy function body; remove
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000501 void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
502 bool verify_body = true) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100503 byte decl_bits = consume_u8("function decl");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000504
505 const byte* sigpos = pc_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100506 function->sig_index = consume_u16("signature index");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507
Ben Murdochda12d292016-06-02 14:46:10 +0100508 if (function->sig_index >= module->signatures.size()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000509 return error(sigpos, "invalid signature index");
510 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100511 function->sig = module->signatures[function->sig_index];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512 }
513
Ben Murdochc5610432016-08-08 18:44:38 +0100514 TRACE(" +%d <function attributes:%s%s>\n", static_cast<int>(pc_ - start_),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 decl_bits & kDeclFunctionName ? " name" : "",
Ben Murdochc5610432016-08-08 18:44:38 +0100516 decl_bits & kDeclFunctionExport ? " exported" : "");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517
518 function->exported = decl_bits & kDeclFunctionExport;
519
Ben Murdochc5610432016-08-08 18:44:38 +0100520 if (decl_bits & kDeclFunctionName) {
521 function->name_offset =
522 consume_string(&function->name_length, function->exported);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 }
524
Ben Murdoch097c5b22016-05-18 11:27:45 +0100525 uint16_t size = consume_u16("body size");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000526 if (ok()) {
527 if ((pc_ + size) > limit_) {
528 return error(pc_, limit_,
529 "expected %d bytes for function body, fell off end", size);
530 }
531 function->code_start_offset = static_cast<uint32_t>(pc_ - start_);
532 function->code_end_offset = function->code_start_offset + size;
533 TRACE(" +%d %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_),
534 "function body", size);
535 pc_ += size;
536 }
537 }
538
Ben Murdoch097c5b22016-05-18 11:27:45 +0100539 bool IsWithinLimit(uint32_t limit, uint32_t offset, uint32_t size) {
540 if (offset > limit) return false;
541 if ((offset + size) < offset) return false; // overflow
542 return (offset + size) <= limit;
543 }
544
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 // Decodes a single data segment entry inside a module starting at {pc_}.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100546 void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
Ben Murdochda12d292016-06-02 14:46:10 +0100547 const byte* start = pc_;
548 int length;
549 segment->dest_addr = consume_u32v(&length, "destination");
550 segment->source_size = consume_u32v(&length, "source size");
551 segment->source_offset = static_cast<uint32_t>(pc_ - start_);
552 segment->init = true;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100553
554 // Validate the data is in the module.
555 uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
556 if (!IsWithinLimit(module_limit, segment->source_offset,
557 segment->source_size)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100558 error(start, "segment out of bounds of module");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100559 }
560
561 // Validate that the segment will fit into the (minimum) memory.
562 uint32_t memory_limit =
Ben Murdochda12d292016-06-02 14:46:10 +0100563 WasmModule::kPageSize * (module ? module->min_mem_pages
564 : WasmModule::kMaxMemPages);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 if (!IsWithinLimit(memory_limit, segment->dest_addr,
566 segment->source_size)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100567 error(start, "segment out of bounds of memory");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100568 }
Ben Murdochda12d292016-06-02 14:46:10 +0100569
570 consume_bytes(segment->source_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571 }
572
573 // Verifies the body (code) of a given function.
574 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
575 WasmFunction* function) {
Ben Murdochc5610432016-08-08 18:44:38 +0100576 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000577 OFStream os(stdout);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100578 os << "Verifying WASM function " << WasmFunctionName(function, menv)
579 << std::endl;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580 }
Ben Murdochda12d292016-06-02 14:46:10 +0100581 FunctionBody body = {menv, function->sig, start_,
582 start_ + function->code_start_offset,
583 start_ + function->code_end_offset};
584 TreeResult result = VerifyWasmCode(module_zone->allocator(), body);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000585 if (result.failed()) {
586 // Wrap the error message from the function decoder.
587 std::ostringstream str;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100588 str << "in function " << WasmFunctionName(function, menv) << ": ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589 str << result;
590 std::string strval = str.str();
591 const char* raw = strval.c_str();
592 size_t len = strlen(raw);
593 char* buffer = new char[len];
594 strncpy(buffer, raw, len);
595 buffer[len - 1] = 0;
596
597 // Copy error code and location.
598 result_.CopyFrom(result);
599 result_.error_msg.Reset(buffer);
600 }
601 }
602
603 // Reads a single 32-bit unsigned integer interpreted as an offset, checking
604 // the offset is within bounds and advances.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100605 uint32_t consume_offset(const char* name = nullptr) {
606 uint32_t offset = consume_u32(name ? name : "offset");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000607 if (offset > static_cast<uint32_t>(limit_ - start_)) {
608 error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
609 }
610 return offset;
611 }
612
Ben Murdochda12d292016-06-02 14:46:10 +0100613 // Reads a length-prefixed string, checking that it is within bounds. Returns
614 // the offset of the string, and the length as an out parameter.
Ben Murdochc5610432016-08-08 18:44:38 +0100615 uint32_t consume_string(uint32_t* length, bool validate_utf8) {
Ben Murdochda12d292016-06-02 14:46:10 +0100616 int varint_length;
617 *length = consume_u32v(&varint_length, "string length");
618 uint32_t offset = pc_offset();
619 TRACE(" +%u %-20s: (%u bytes)\n", offset, "string", *length);
Ben Murdochc5610432016-08-08 18:44:38 +0100620 if (validate_utf8 && !unibrow::Utf8::Validate(pc_, *length)) {
621 error(pc_, "no valid UTF-8 string");
622 }
Ben Murdochda12d292016-06-02 14:46:10 +0100623 consume_bytes(*length);
624 return offset;
625 }
626
627 uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) {
628 const byte* pos = pc_;
629 int length;
630 uint32_t sig_index = consume_u32v(&length, "signature index");
631 if (sig_index >= module->signatures.size()) {
632 error(pos, pos, "signature index %u out of bounds (%d signatures)",
633 sig_index, static_cast<int>(module->signatures.size()));
634 *sig = nullptr;
635 return 0;
636 }
637 *sig = module->signatures[sig_index];
638 return sig_index;
639 }
640
641 uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
642 const byte* pos = pc_;
643 int length;
644 uint32_t func_index = consume_u32v(&length, "function index");
645 if (func_index >= module->functions.size()) {
646 error(pos, pos, "function index %u out of bounds (%d functions)",
647 func_index, static_cast<int>(module->functions.size()));
648 *func = nullptr;
649 return 0;
650 }
651 *func = &module->functions[func_index];
652 return func_index;
653 }
654
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000655 // Reads a single 8-bit integer, interpreting it as a local type.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100656 LocalType consume_local_type() {
657 byte val = consume_u8("local type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 LocalTypeCode t = static_cast<LocalTypeCode>(val);
659 switch (t) {
660 case kLocalVoid:
661 return kAstStmt;
662 case kLocalI32:
663 return kAstI32;
664 case kLocalI64:
665 return kAstI64;
666 case kLocalF32:
667 return kAstF32;
668 case kLocalF64:
669 return kAstF64;
670 default:
671 error(pc_ - 1, "invalid local type");
672 return kAstStmt;
673 }
674 }
675
676 // Reads a single 8-bit integer, interpreting it as a memory type.
677 MachineType mem_type() {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100678 byte val = consume_u8("memory type");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 MemTypeCode t = static_cast<MemTypeCode>(val);
680 switch (t) {
681 case kMemI8:
682 return MachineType::Int8();
683 case kMemU8:
684 return MachineType::Uint8();
685 case kMemI16:
686 return MachineType::Int16();
687 case kMemU16:
688 return MachineType::Uint16();
689 case kMemI32:
690 return MachineType::Int32();
691 case kMemU32:
692 return MachineType::Uint32();
693 case kMemI64:
694 return MachineType::Int64();
695 case kMemU64:
696 return MachineType::Uint64();
697 case kMemF32:
698 return MachineType::Float32();
699 case kMemF64:
700 return MachineType::Float64();
701 default:
702 error(pc_ - 1, "invalid memory type");
703 return MachineType::None();
704 }
705 }
706
Ben Murdochc5610432016-08-08 18:44:38 +0100707 // Parses a type entry, which is currently limited to functions only.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100708 FunctionSig* consume_sig() {
Ben Murdochc5610432016-08-08 18:44:38 +0100709 const byte* pos = pc_;
710 byte form = consume_u8("type form");
711 if (form != kWasmFunctionTypeForm) {
712 error(pos, pos, "expected function type form (0x%02x), got: 0x%02x",
713 kWasmFunctionTypeForm, form);
714 return nullptr;
715 }
Ben Murdochda12d292016-06-02 14:46:10 +0100716 int length;
Ben Murdochc5610432016-08-08 18:44:38 +0100717 // parse parameter types
718 uint32_t param_count = consume_u32v(&length, "param count");
719 std::vector<LocalType> params;
720 for (uint32_t i = 0; i < param_count; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100721 LocalType param = consume_local_type();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
Ben Murdochc5610432016-08-08 18:44:38 +0100723 params.push_back(param);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 }
Ben Murdochc5610432016-08-08 18:44:38 +0100725
726 // parse return types
727 const byte* pt = pc_;
728 uint32_t return_count = consume_u32v(&length, "return count");
729 if (return_count > kMaxReturnCount) {
730 error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
731 kMaxReturnCount);
732 return nullptr;
733 }
734 std::vector<LocalType> returns;
735 for (uint32_t i = 0; i < return_count; i++) {
736 LocalType ret = consume_local_type();
737 if (ret == kAstStmt) error(pc_ - 1, "invalid void return type");
738 returns.push_back(ret);
739 }
740
741 // FunctionSig stores the return types first.
742 LocalType* buffer =
743 module_zone->NewArray<LocalType>(param_count + return_count);
744 uint32_t b = 0;
745 for (uint32_t i = 0; i < return_count; i++) buffer[b++] = returns[i];
746 for (uint32_t i = 0; i < param_count; i++) buffer[b++] = params[i];
747
748 return new (module_zone) FunctionSig(return_count, param_count, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 }
750};
751
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000752// Helpers for nice error messages.
753class ModuleError : public ModuleResult {
754 public:
755 explicit ModuleError(const char* msg) {
756 error_code = kError;
757 size_t len = strlen(msg) + 1;
758 char* result = new char[len];
759 strncpy(result, msg, len);
760 result[len - 1] = 0;
761 error_msg.Reset(result);
762 }
763};
764
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000765// Helpers for nice error messages.
766class FunctionError : public FunctionResult {
767 public:
768 explicit FunctionError(const char* msg) {
769 error_code = kError;
770 size_t len = strlen(msg) + 1;
771 char* result = new char[len];
772 strncpy(result, msg, len);
773 result[len - 1] = 0;
774 error_msg.Reset(result);
775 }
776};
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}
821} // namespace wasm
822} // namespace internal
823} // namespace v8