blob: 24f39822f9d68bed2675509f6f730a8090901ae6 [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
5#include "src/macro-assembler.h"
6#include "src/objects.h"
7#include "src/v8.h"
8
9#include "src/wasm/decoder.h"
10#include "src/wasm/module-decoder.h"
11
12namespace v8 {
13namespace internal {
14namespace wasm {
15
16#if DEBUG
17#define TRACE(...) \
18 do { \
19 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
20 } while (false)
21#else
22#define TRACE(...)
23#endif
24
25
26// The main logic for decoding the bytes of a module.
27class ModuleDecoder : public Decoder {
28 public:
29 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
30 bool asm_js)
31 : Decoder(module_start, module_end), module_zone(zone), asm_js_(asm_js) {
32 result_.start = start_;
33 if (limit_ < start_) {
34 error(start_, "end is less than start");
35 limit_ = start_;
36 }
37 }
38
39 virtual void onFirstError() {
40 pc_ = limit_; // On error, terminate section decoding loop.
41 }
42
43 // Decodes an entire module.
44 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
45 pc_ = start_;
46 module->module_start = start_;
47 module->module_end = limit_;
48 module->min_mem_size_log2 = 0;
49 module->max_mem_size_log2 = 0;
50 module->mem_export = false;
51 module->mem_external = false;
52 module->globals = new std::vector<WasmGlobal>();
53 module->signatures = new std::vector<FunctionSig*>();
54 module->functions = new std::vector<WasmFunction>();
55 module->data_segments = new std::vector<WasmDataSegment>();
56 module->function_table = new std::vector<uint16_t>();
57
58 bool sections[kMaxModuleSectionCode];
59 memset(sections, 0, sizeof(sections));
60
61 // Decode the module sections.
62 while (pc_ < limit_) {
63 TRACE("DecodeSection\n");
64 WasmSectionDeclCode section =
65 static_cast<WasmSectionDeclCode>(u8("section"));
66 // Each section should appear at most once.
67 if (section < kMaxModuleSectionCode) {
68 CheckForPreviousSection(sections, section, false);
69 sections[section] = true;
70 }
71
72 switch (section) {
73 case kDeclEnd:
74 // Terminate section decoding.
75 limit_ = pc_;
76 break;
77 case kDeclMemory:
78 module->min_mem_size_log2 = u8("min memory");
79 module->max_mem_size_log2 = u8("max memory");
80 module->mem_export = u8("export memory") != 0;
81 break;
82 case kDeclSignatures: {
83 int length;
84 uint32_t signatures_count = u32v(&length, "signatures count");
85 module->signatures->reserve(SafeReserve(signatures_count));
86 // Decode signatures.
87 for (uint32_t i = 0; i < signatures_count; i++) {
88 if (failed()) break;
89 TRACE("DecodeSignature[%d] module+%d\n", i,
90 static_cast<int>(pc_ - start_));
91 FunctionSig* s = sig(); // read function sig.
92 module->signatures->push_back(s);
93 }
94 break;
95 }
96 case kDeclFunctions: {
97 // Functions require a signature table first.
98 CheckForPreviousSection(sections, kDeclSignatures, true);
99 int length;
100 uint32_t functions_count = u32v(&length, "functions count");
101 module->functions->reserve(SafeReserve(functions_count));
102 // Set up module environment for verification.
103 ModuleEnv menv;
104 menv.module = module;
105 menv.globals_area = 0;
106 menv.mem_start = 0;
107 menv.mem_end = 0;
108 menv.function_code = nullptr;
109 menv.asm_js = asm_js_;
110 // Decode functions.
111 for (uint32_t i = 0; i < functions_count; i++) {
112 if (failed()) break;
113 TRACE("DecodeFunction[%d] module+%d\n", i,
114 static_cast<int>(pc_ - start_));
115
116 module->functions->push_back(
117 {nullptr, 0, 0, 0, 0, 0, 0, false, false});
118 WasmFunction* function = &module->functions->back();
119 DecodeFunctionInModule(module, function, false);
120 }
121 if (ok() && verify_functions) {
122 for (uint32_t i = 0; i < functions_count; i++) {
123 if (failed()) break;
124 WasmFunction* function = &module->functions->at(i);
125 if (!function->external) {
126 VerifyFunctionBody(i, &menv, function);
127 if (result_.failed())
128 error(result_.error_pc, result_.error_msg.get());
129 }
130 }
131 }
132 break;
133 }
134 case kDeclGlobals: {
135 int length;
136 uint32_t globals_count = u32v(&length, "globals count");
137 module->globals->reserve(SafeReserve(globals_count));
138 // Decode globals.
139 for (uint32_t i = 0; i < globals_count; i++) {
140 if (failed()) break;
141 TRACE("DecodeGlobal[%d] module+%d\n", i,
142 static_cast<int>(pc_ - start_));
143 module->globals->push_back({0, MachineType::Int32(), 0, false});
144 WasmGlobal* global = &module->globals->back();
145 DecodeGlobalInModule(global);
146 }
147 break;
148 }
149 case kDeclDataSegments: {
150 int length;
151 uint32_t data_segments_count = u32v(&length, "data segments count");
152 module->data_segments->reserve(SafeReserve(data_segments_count));
153 // Decode data segments.
154 for (uint32_t i = 0; i < data_segments_count; i++) {
155 if (failed()) break;
156 TRACE("DecodeDataSegment[%d] module+%d\n", i,
157 static_cast<int>(pc_ - start_));
158 module->data_segments->push_back({0, 0, 0});
159 WasmDataSegment* segment = &module->data_segments->back();
160 DecodeDataSegmentInModule(segment);
161 }
162 break;
163 }
164 case kDeclFunctionTable: {
165 // An indirect function table requires functions first.
166 CheckForPreviousSection(sections, kDeclFunctions, true);
167 int length;
168 uint32_t function_table_count = u32v(&length, "function table count");
169 module->function_table->reserve(SafeReserve(function_table_count));
170 // Decode function table.
171 for (uint32_t i = 0; i < function_table_count; i++) {
172 if (failed()) break;
173 TRACE("DecodeFunctionTable[%d] module+%d\n", i,
174 static_cast<int>(pc_ - start_));
175 uint16_t index = u16();
176 if (index >= module->functions->size()) {
177 error(pc_ - 2, "invalid function index");
178 break;
179 }
180 module->function_table->push_back(index);
181 }
182 break;
183 }
184 case kDeclWLL: {
185 // Reserved for experimentation by the Web Low-level Language project
186 // which is augmenting the binary encoding with source code meta
187 // information. This section does not affect the semantics of the code
188 // and can be ignored by the runtime. https://github.com/JSStats/wll
189 int length = 0;
190 uint32_t section_size = u32v(&length, "section size");
191 if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
192 error(pc_ - length, "invalid section size");
193 break;
194 }
195 pc_ += section_size;
196 break;
197 }
198 default:
199 error(pc_ - 1, nullptr, "unrecognized section 0x%02x", section);
200 break;
201 }
202 }
203
204 return toResult(module);
205 }
206
207 uint32_t SafeReserve(uint32_t count) {
208 // Avoid OOM by only reserving up to a certain size.
209 const uint32_t kMaxReserve = 20000;
210 return count < kMaxReserve ? count : kMaxReserve;
211 }
212
213 void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section,
214 bool present) {
215 if (section >= kMaxModuleSectionCode) return;
216 if (sections[section] == present) return;
217 const char* name = "";
218 switch (section) {
219 case kDeclMemory:
220 name = "memory";
221 break;
222 case kDeclSignatures:
223 name = "signatures";
224 break;
225 case kDeclFunctions:
226 name = "function declaration";
227 break;
228 case kDeclGlobals:
229 name = "global variable";
230 break;
231 case kDeclDataSegments:
232 name = "data segment";
233 break;
234 case kDeclFunctionTable:
235 name = "function table";
236 break;
237 default:
238 name = "";
239 break;
240 }
241 if (present) {
242 error(pc_ - 1, nullptr, "required %s section missing", name);
243 } else {
244 error(pc_ - 1, nullptr, "%s section already present", name);
245 }
246 }
247
248 // Decodes a single anonymous function starting at {start_}.
249 FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
250 WasmFunction* function) {
251 pc_ = start_;
252 function->sig = sig(); // read signature
253 function->name_offset = 0; // ---- name
254 function->code_start_offset = off(pc_ + 8); // ---- code start
255 function->code_end_offset = off(limit_); // ---- code end
256 function->local_int32_count = u16(); // read u16
257 function->local_int64_count = u16(); // read u16
258 function->local_float32_count = u16(); // read u16
259 function->local_float64_count = u16(); // read u16
260 function->exported = false; // ---- exported
261 function->external = false; // ---- external
262
263 if (ok()) VerifyFunctionBody(0, module_env, function);
264
265 FunctionResult result;
266 result.CopyFrom(result_); // Copy error code and location.
267 result.val = function;
268 return result;
269 }
270
271 // Decodes a single function signature at {start}.
272 FunctionSig* DecodeFunctionSignature(const byte* start) {
273 pc_ = start;
274 FunctionSig* result = sig();
275 return ok() ? result : nullptr;
276 }
277
278 private:
279 Zone* module_zone;
280 ModuleResult result_;
281 bool asm_js_;
282
283 uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
284
285 // Decodes a single global entry inside a module starting at {pc_}.
286 void DecodeGlobalInModule(WasmGlobal* global) {
287 global->name_offset = string("global name");
288 global->type = mem_type();
289 global->offset = 0;
290 global->exported = u8("exported") != 0;
291 }
292
293 // Decodes a single function entry inside a module starting at {pc_}.
294 void DecodeFunctionInModule(WasmModule* module, WasmFunction* function,
295 bool verify_body = true) {
296 byte decl_bits = u8("function decl");
297
298 const byte* sigpos = pc_;
299 function->sig_index = u16("signature index");
300
301 if (function->sig_index >= module->signatures->size()) {
302 return error(sigpos, "invalid signature index");
303 } else {
304 function->sig = module->signatures->at(function->sig_index);
305 }
306
307 TRACE(" +%d <function attributes:%s%s%s%s%s>\n",
308 static_cast<int>(pc_ - start_),
309 decl_bits & kDeclFunctionName ? " name" : "",
310 decl_bits & kDeclFunctionImport ? " imported" : "",
311 decl_bits & kDeclFunctionLocals ? " locals" : "",
312 decl_bits & kDeclFunctionExport ? " exported" : "",
313 (decl_bits & kDeclFunctionImport) == 0 ? " body" : "");
314
315 if (decl_bits & kDeclFunctionName) {
316 function->name_offset = string("function name");
317 }
318
319 function->exported = decl_bits & kDeclFunctionExport;
320
321 // Imported functions have no locals or body.
322 if (decl_bits & kDeclFunctionImport) {
323 function->external = true;
324 return;
325 }
326
327 if (decl_bits & kDeclFunctionLocals) {
328 function->local_int32_count = u16("int32 count");
329 function->local_int64_count = u16("int64 count");
330 function->local_float32_count = u16("float32 count");
331 function->local_float64_count = u16("float64 count");
332 }
333
334 uint16_t size = u16("body size");
335 if (ok()) {
336 if ((pc_ + size) > limit_) {
337 return error(pc_, limit_,
338 "expected %d bytes for function body, fell off end", size);
339 }
340 function->code_start_offset = static_cast<uint32_t>(pc_ - start_);
341 function->code_end_offset = function->code_start_offset + size;
342 TRACE(" +%d %-20s: (%d bytes)\n", static_cast<int>(pc_ - start_),
343 "function body", size);
344 pc_ += size;
345 }
346 }
347
348 // Decodes a single data segment entry inside a module starting at {pc_}.
349 void DecodeDataSegmentInModule(WasmDataSegment* segment) {
350 segment->dest_addr =
351 u32("destination"); // TODO(titzer): check it's within the memory size.
352 segment->source_offset = offset("source offset");
353 segment->source_size =
354 u32("source size"); // TODO(titzer): check the size is reasonable.
355 segment->init = u8("init");
356 }
357
358 // Verifies the body (code) of a given function.
359 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
360 WasmFunction* function) {
361 if (FLAG_trace_wasm_decode_time) {
362 // TODO(titzer): clean me up a bit.
363 OFStream os(stdout);
364 os << "Verifying WASM function:";
365 if (function->name_offset > 0) {
366 os << menv->module->GetName(function->name_offset);
367 }
368 os << std::endl;
369 }
370 FunctionEnv fenv;
371 fenv.module = menv;
372 fenv.sig = function->sig;
373 fenv.local_int32_count = function->local_int32_count;
374 fenv.local_int64_count = function->local_int64_count;
375 fenv.local_float32_count = function->local_float32_count;
376 fenv.local_float64_count = function->local_float64_count;
377 fenv.SumLocals();
378
379 TreeResult result =
380 VerifyWasmCode(&fenv, start_, start_ + function->code_start_offset,
381 start_ + function->code_end_offset);
382 if (result.failed()) {
383 // Wrap the error message from the function decoder.
384 std::ostringstream str;
385 str << "in function #" << func_num << ": ";
386 // TODO(titzer): add function name for the user?
387 str << result;
388 std::string strval = str.str();
389 const char* raw = strval.c_str();
390 size_t len = strlen(raw);
391 char* buffer = new char[len];
392 strncpy(buffer, raw, len);
393 buffer[len - 1] = 0;
394
395 // Copy error code and location.
396 result_.CopyFrom(result);
397 result_.error_msg.Reset(buffer);
398 }
399 }
400
401 // Reads a single 32-bit unsigned integer interpreted as an offset, checking
402 // the offset is within bounds and advances.
403 uint32_t offset(const char* name = nullptr) {
404 uint32_t offset = u32(name ? name : "offset");
405 if (offset > static_cast<uint32_t>(limit_ - start_)) {
406 error(pc_ - sizeof(uint32_t), "offset out of bounds of module");
407 }
408 return offset;
409 }
410
411 // Reads a single 32-bit unsigned integer interpreted as an offset into the
412 // data and validating the string there and advances.
413 uint32_t string(const char* name = nullptr) {
414 return offset(name ? name : "string"); // TODO(titzer): validate string
415 }
416
417 // Reads a single 8-bit integer, interpreting it as a local type.
418 LocalType local_type() {
419 byte val = u8("local type");
420 LocalTypeCode t = static_cast<LocalTypeCode>(val);
421 switch (t) {
422 case kLocalVoid:
423 return kAstStmt;
424 case kLocalI32:
425 return kAstI32;
426 case kLocalI64:
427 return kAstI64;
428 case kLocalF32:
429 return kAstF32;
430 case kLocalF64:
431 return kAstF64;
432 default:
433 error(pc_ - 1, "invalid local type");
434 return kAstStmt;
435 }
436 }
437
438 // Reads a single 8-bit integer, interpreting it as a memory type.
439 MachineType mem_type() {
440 byte val = u8("memory type");
441 MemTypeCode t = static_cast<MemTypeCode>(val);
442 switch (t) {
443 case kMemI8:
444 return MachineType::Int8();
445 case kMemU8:
446 return MachineType::Uint8();
447 case kMemI16:
448 return MachineType::Int16();
449 case kMemU16:
450 return MachineType::Uint16();
451 case kMemI32:
452 return MachineType::Int32();
453 case kMemU32:
454 return MachineType::Uint32();
455 case kMemI64:
456 return MachineType::Int64();
457 case kMemU64:
458 return MachineType::Uint64();
459 case kMemF32:
460 return MachineType::Float32();
461 case kMemF64:
462 return MachineType::Float64();
463 default:
464 error(pc_ - 1, "invalid memory type");
465 return MachineType::None();
466 }
467 }
468
469 // Parses an inline function signature.
470 FunctionSig* sig() {
471 byte count = u8("param count");
472 LocalType ret = local_type();
473 FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
474 if (ret != kAstStmt) builder.AddReturn(ret);
475
476 for (int i = 0; i < count; i++) {
477 LocalType param = local_type();
478 if (param == kAstStmt) error(pc_ - 1, "invalid void parameter type");
479 builder.AddParam(param);
480 }
481 return builder.Build();
482 }
483};
484
485
486// Helpers for nice error messages.
487class ModuleError : public ModuleResult {
488 public:
489 explicit ModuleError(const char* msg) {
490 error_code = kError;
491 size_t len = strlen(msg) + 1;
492 char* result = new char[len];
493 strncpy(result, msg, len);
494 result[len - 1] = 0;
495 error_msg.Reset(result);
496 }
497};
498
499
500// Helpers for nice error messages.
501class FunctionError : public FunctionResult {
502 public:
503 explicit FunctionError(const char* msg) {
504 error_code = kError;
505 size_t len = strlen(msg) + 1;
506 char* result = new char[len];
507 strncpy(result, msg, len);
508 result[len - 1] = 0;
509 error_msg.Reset(result);
510 }
511};
512
513
514ModuleResult DecodeWasmModule(Isolate* isolate, Zone* zone,
515 const byte* module_start, const byte* module_end,
516 bool verify_functions, bool asm_js) {
517 size_t size = module_end - module_start;
518 if (module_start > module_end) return ModuleError("start > end");
519 if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
520 WasmModule* module = new WasmModule();
521 ModuleDecoder decoder(zone, module_start, module_end, asm_js);
522 return decoder.DecodeModule(module, verify_functions);
523}
524
525
526FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
527 const byte* end) {
528 ModuleDecoder decoder(zone, start, end, false);
529 return decoder.DecodeFunctionSignature(start);
530}
531
532
533FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
534 ModuleEnv* module_env,
535 const byte* function_start,
536 const byte* function_end) {
537 size_t size = function_end - function_start;
538 if (function_start > function_end) return FunctionError("start > end");
539 if (size > kMaxFunctionSize)
540 return FunctionError("size > maximum function size");
541 WasmFunction* function = new WasmFunction();
542 ModuleDecoder decoder(zone, function_start, function_end, false);
543 return decoder.DecodeSingleFunction(module_env, function);
544}
545} // namespace wasm
546} // namespace internal
547} // namespace v8