Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(629)

Side by Side Diff: src/wasm/module-decoder.cc

Issue 1900153002: [wasm] Enforce strict ordering of WASM module sections. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/wasm/module-decoder.h" 5 #include "src/wasm/module-decoder.h"
6 6
7 #include "src/base/functional.h" 7 #include "src/base/functional.h"
8 #include "src/base/platform/platform.h" 8 #include "src/base/platform/platform.h"
9 #include "src/macro-assembler.h" 9 #include "src/macro-assembler.h"
10 #include "src/objects.h" 10 #include "src/objects.h"
11 #include "src/v8.h" 11 #include "src/v8.h"
12 12
13 #include "src/wasm/decoder.h" 13 #include "src/wasm/decoder.h"
14 14
15 namespace v8 { 15 namespace v8 {
16 namespace internal { 16 namespace internal {
17 namespace wasm { 17 namespace wasm {
18 18
19 #if DEBUG 19 #if DEBUG
20 #define TRACE(...) \ 20 #define TRACE(...) \
21 do { \ 21 do { \
22 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ 22 if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
23 } while (false) 23 } while (false)
24 #else 24 #else
25 #define TRACE(...) 25 #define TRACE(...)
26 #endif 26 #endif
27 27
28
29 // The main logic for decoding the bytes of a module. 28 // The main logic for decoding the bytes of a module.
30 class ModuleDecoder : public Decoder { 29 class ModuleDecoder : public Decoder {
31 public: 30 public:
32 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end, 31 ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
33 ModuleOrigin origin) 32 ModuleOrigin origin)
34 : Decoder(module_start, module_end), module_zone(zone), origin_(origin) { 33 : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
35 result_.start = start_; 34 result_.start = start_;
36 if (limit_ < start_) { 35 if (limit_ < start_) {
37 error(start_, "end is less than start"); 36 error(start_, "end is less than start");
38 limit_ = start_; 37 limit_ = start_;
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) { 71 ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
73 pc_ = start_; 72 pc_ = start_;
74 module->module_start = start_; 73 module->module_start = start_;
75 module->module_end = limit_; 74 module->module_end = limit_;
76 module->min_mem_pages = 0; 75 module->min_mem_pages = 0;
77 module->max_mem_pages = 0; 76 module->max_mem_pages = 0;
78 module->mem_export = false; 77 module->mem_export = false;
79 module->mem_external = false; 78 module->mem_external = false;
80 module->origin = origin_; 79 module->origin = origin_;
81 80
82 bool sections[(size_t)WasmSection::Code::Max] = {false};
83
84 const byte* pos = pc_; 81 const byte* pos = pc_;
82 int current_order = 0;
85 uint32_t magic_word = consume_u32("wasm magic"); 83 uint32_t magic_word = consume_u32("wasm magic");
86 #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff 84 #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
87 if (magic_word != kWasmMagic) { 85 if (magic_word != kWasmMagic) {
88 error(pos, pos, 86 error(pos, pos,
89 "expected magic word %02x %02x %02x %02x, " 87 "expected magic word %02x %02x %02x %02x, "
90 "found %02x %02x %02x %02x", 88 "found %02x %02x %02x %02x",
91 BYTES(kWasmMagic), BYTES(magic_word)); 89 BYTES(kWasmMagic), BYTES(magic_word));
92 goto done; 90 goto done;
93 } 91 }
94 92
95 pos = pc_; 93 pos = pc_;
96 { 94 {
97 uint32_t magic_version = consume_u32("wasm version"); 95 uint32_t magic_version = consume_u32("wasm version");
98 if (magic_version != kWasmVersion) { 96 if (magic_version != kWasmVersion) {
99 error(pos, pos, 97 error(pos, pos,
100 "expected version %02x %02x %02x %02x, " 98 "expected version %02x %02x %02x %02x, "
101 "found %02x %02x %02x %02x", 99 "found %02x %02x %02x %02x",
102 BYTES(kWasmVersion), BYTES(magic_version)); 100 BYTES(kWasmVersion), BYTES(magic_version));
103 goto done; 101 goto done;
104 } 102 }
105 } 103 }
106 104
107 // Decode the module sections. 105 // Decode the module sections.
108 while (pc_ < limit_) { 106 while (pc_ < limit_) {
109 TRACE("DecodeSection\n"); 107 TRACE("DecodeSection\n");
110 pos = pc_; 108 pos = pc_;
111 109
112 int length; 110 // Read and check the section size.
113 uint32_t section_length = consume_u32v(&length, "section size"); 111 int section_leb_length = 0;
114 112 uint32_t section_length =
115 int section_string_leb_length = 0; 113 consume_u32v(&section_leb_length, "section length");
116 uint32_t section_string_length = 0; 114 if (!checkAvailable(section_length)) {
117 WasmSection::Code section = consume_section_name( 115 // The section would extend beyond the end of the module.
118 &section_string_leb_length, &section_string_length);
119 uint32_t string_and_leb_length =
120 section_string_leb_length + section_string_length;
121 if (string_and_leb_length > section_length) {
122 error(pos, pos,
123 "section string of size %u longer than total section bytes %u",
124 string_and_leb_length, section_length);
125 break; 116 break;
126 } 117 }
127 118
119 // Read the section name.
120 int string_leb_length = 0;
121 uint32_t string_length =
122 consume_u32v(&string_leb_length, "section name length");
123 if (static_cast<uint32_t>(string_leb_length) + string_length >
124 section_length) {
JF 2016/04/19 15:48:47 This seems pretty impossible to cause to overflow,
titzer 2016/04/20 08:51:24 Done. (I've refactored this a bit so the check is
125 error(pc_, pc_,
126 "section name string %u longer than total section bytes %u",
127 string_length, section_length);
128 break;
129 }
130
131 const byte* section_name_start = pc_;
132 consume_bytes(string_length);
133 if (failed()) {
134 TRACE("Section name of length %u couldn't be read\n", string_length);
135 break;
136 }
137
138 WasmSection::Code section =
139 WasmSection::lookup(section_name_start, string_length);
140 // TODO(jfb) Linear search, it may be better to do a common-prefix search.
141 for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end();
142 i = WasmSection::next(i)) {
143 if (WasmSection::getNameLength(i) == string_length &&
144 0 == memcmp(WasmSection::getName(i), section_name_start,
145 string_length)) {
146 section = i;
147 break;
148 }
149 }
JF 2016/04/19 15:48:47 Duplicate.
titzer 2016/04/20 08:51:24 Done.
150
128 if (section == WasmSection::Code::Max) { 151 if (section == WasmSection::Code::Max) {
129 // Skip unknown section. 152 // Skip unknown sections.
130 uint32_t skip = section_length - string_and_leb_length; 153 TRACE("Unknown section: '");
131 TRACE("skipping %u bytes from unknown section\n", skip); 154 for (uint32_t i = 0; i != string_length; ++i) {
132 consume_bytes(skip); 155 TRACE("%c", *(section_name_start + i));
156 }
157 TRACE("'\n");
158 consume_bytes(section_length - string_length - string_leb_length);
133 continue; 159 continue;
134 } 160 }
135 161
136 // Each section should appear at most once. 162 current_order = CheckSectionOrder(current_order, section);
137 CheckForPreviousSection(sections, section, false);
138 sections[(size_t)section] = true;
139 163
140 switch (section) { 164 switch (section) {
141 case WasmSection::Code::End: 165 case WasmSection::Code::End:
142 // Terminate section decoding. 166 // Terminate section decoding.
143 limit_ = pc_; 167 limit_ = pc_;
144 break; 168 break;
145 case WasmSection::Code::Memory: 169 case WasmSection::Code::Memory:
146 int length; 170 int length;
147 module->min_mem_pages = consume_u32v(&length, "min memory"); 171 module->min_mem_pages = consume_u32v(&length, "min memory");
148 module->max_mem_pages = consume_u32v(&length, "max memory"); 172 module->max_mem_pages = consume_u32v(&length, "max memory");
149 module->mem_export = consume_u8("export memory") != 0; 173 module->mem_export = consume_u8("export memory") != 0;
150 break; 174 break;
151 case WasmSection::Code::Signatures: { 175 case WasmSection::Code::Signatures: {
152 int length; 176 int length;
153 uint32_t signatures_count = consume_u32v(&length, "signatures count"); 177 uint32_t signatures_count = consume_u32v(&length, "signatures count");
154 module->signatures.reserve(SafeReserve(signatures_count)); 178 module->signatures.reserve(SafeReserve(signatures_count));
155 // Decode signatures. 179 // Decode signatures.
156 for (uint32_t i = 0; i < signatures_count; i++) { 180 for (uint32_t i = 0; i < signatures_count; i++) {
157 if (failed()) break; 181 if (failed()) break;
158 TRACE("DecodeSignature[%d] module+%d\n", i, 182 TRACE("DecodeSignature[%d] module+%d\n", i,
159 static_cast<int>(pc_ - start_)); 183 static_cast<int>(pc_ - start_));
160 FunctionSig* s = consume_sig(); // read function sig. 184 FunctionSig* s = consume_sig(); // read function sig.
161 module->signatures.push_back(s); 185 module->signatures.push_back(s);
162 } 186 }
163 break; 187 break;
164 } 188 }
165 case WasmSection::Code::FunctionSignatures: { 189 case WasmSection::Code::FunctionSignatures: {
166 // Functions require a signature table first.
167 CheckForPreviousSection(sections, WasmSection::Code::Signatures,
168 true);
169 int length; 190 int length;
170 uint32_t functions_count = consume_u32v(&length, "functions count"); 191 uint32_t functions_count = consume_u32v(&length, "functions count");
171 module->functions.reserve(SafeReserve(functions_count)); 192 module->functions.reserve(SafeReserve(functions_count));
172 for (uint32_t i = 0; i < functions_count; i++) { 193 for (uint32_t i = 0; i < functions_count; i++) {
173 module->functions.push_back( 194 module->functions.push_back(
174 {nullptr, i, 0, 0, 0, 0, 0, 0, false, false}); 195 {nullptr, i, 0, 0, 0, 0, 0, 0, false, false});
175 WasmFunction* function = &module->functions.back(); 196 WasmFunction* function = &module->functions.back();
176 function->sig_index = consume_sig_index(module, &function->sig); 197 function->sig_index = consume_sig_index(module, &function->sig);
177 } 198 }
178 break; 199 break;
179 } 200 }
180 case WasmSection::Code::FunctionBodies: { 201 case WasmSection::Code::FunctionBodies: {
181 // Function bodies should follow signatures.
182 CheckForPreviousSection(sections,
183 WasmSection::Code::FunctionSignatures, true);
184 int length; 202 int length;
185 const byte* pos = pc_; 203 const byte* pos = pc_;
186 uint32_t functions_count = consume_u32v(&length, "functions count"); 204 uint32_t functions_count = consume_u32v(&length, "functions count");
187 if (functions_count != module->functions.size()) { 205 if (functions_count != module->functions.size()) {
188 error(pos, pos, "function body count %u mismatch (%u expected)", 206 error(pos, pos, "function body count %u mismatch (%u expected)",
189 functions_count, 207 functions_count,
190 static_cast<uint32_t>(module->functions.size())); 208 static_cast<uint32_t>(module->functions.size()));
191 break; 209 break;
192 } 210 }
193 for (uint32_t i = 0; i < functions_count; i++) { 211 for (uint32_t i = 0; i < functions_count; i++) {
194 WasmFunction* function = &module->functions[i]; 212 WasmFunction* function = &module->functions[i];
195 int length; 213 int length;
196 uint32_t size = consume_u32v(&length, "body size"); 214 uint32_t size = consume_u32v(&length, "body size");
197 function->code_start_offset = pc_offset(); 215 function->code_start_offset = pc_offset();
198 function->code_end_offset = pc_offset() + size; 216 function->code_end_offset = pc_offset() + size;
199 217
200 TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body", 218 TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body",
201 size); 219 size);
202 pc_ += size; 220 pc_ += size;
203 if (pc_ > limit_) { 221 if (pc_ > limit_) {
204 error(pc_, "function body extends beyond end of file"); 222 error(pc_, "function body extends beyond end of file");
205 } 223 }
206 } 224 }
207 break; 225 break;
208 } 226 }
209 case WasmSection::Code::Functions: { 227 case WasmSection::Code::Functions: {
210 // Functions require a signature table first.
211 CheckForPreviousSection(sections, WasmSection::Code::Signatures,
212 true);
213 int length; 228 int length;
214 uint32_t functions_count = consume_u32v(&length, "functions count"); 229 uint32_t functions_count = consume_u32v(&length, "functions count");
215 module->functions.reserve(SafeReserve(functions_count)); 230 module->functions.reserve(SafeReserve(functions_count));
216 // Set up module environment for verification. 231 // Set up module environment for verification.
217 ModuleEnv menv; 232 ModuleEnv menv;
218 menv.module = module; 233 menv.module = module;
219 menv.instance = nullptr; 234 menv.instance = nullptr;
220 menv.origin = origin_; 235 menv.origin = origin_;
221 // Decode functions. 236 // Decode functions.
222 for (uint32_t i = 0; i < functions_count; i++) { 237 for (uint32_t i = 0; i < functions_count; i++) {
(...skipping 13 matching lines...) Expand all
236 if (!function->external) { 251 if (!function->external) {
237 VerifyFunctionBody(i, &menv, function); 252 VerifyFunctionBody(i, &menv, function);
238 if (result_.failed()) 253 if (result_.failed())
239 error(result_.error_pc, result_.error_msg.get()); 254 error(result_.error_pc, result_.error_msg.get());
240 } 255 }
241 } 256 }
242 } 257 }
243 break; 258 break;
244 } 259 }
245 case WasmSection::Code::Names: { 260 case WasmSection::Code::Names: {
246 // Names correspond to functions.
247 CheckForPreviousSection(sections,
248 WasmSection::Code::FunctionSignatures, true);
249 int length; 261 int length;
250 const byte* pos = pc_; 262 const byte* pos = pc_;
251 uint32_t functions_count = consume_u32v(&length, "functions count"); 263 uint32_t functions_count = consume_u32v(&length, "functions count");
252 if (functions_count != module->functions.size()) { 264 if (functions_count != module->functions.size()) {
253 error(pos, pos, "function name count %u mismatch (%u expected)", 265 error(pos, pos, "function name count %u mismatch (%u expected)",
254 functions_count, 266 functions_count,
255 static_cast<uint32_t>(module->functions.size())); 267 static_cast<uint32_t>(module->functions.size()));
256 break; 268 break;
257 } 269 }
258 270
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 WasmFunction* func; 346 WasmFunction* func;
335 const byte* pos = pc_; 347 const byte* pos = pc_;
336 module->start_function_index = consume_func_index(module, &func); 348 module->start_function_index = consume_func_index(module, &func);
337 if (func && func->sig->parameter_count() > 0) { 349 if (func && func->sig->parameter_count() > 0) {
338 error(pos, "invalid start function: non-zero parameter count"); 350 error(pos, "invalid start function: non-zero parameter count");
339 break; 351 break;
340 } 352 }
341 break; 353 break;
342 } 354 }
343 case WasmSection::Code::ImportTable: { 355 case WasmSection::Code::ImportTable: {
344 // Declares an import table.
345 CheckForPreviousSection(sections, WasmSection::Code::Signatures,
346 true);
347 int length; 356 int length;
348 uint32_t import_table_count = 357 uint32_t import_table_count =
349 consume_u32v(&length, "import table count"); 358 consume_u32v(&length, "import table count");
350 module->import_table.reserve(SafeReserve(import_table_count)); 359 module->import_table.reserve(SafeReserve(import_table_count));
351 // Decode import table. 360 // Decode import table.
352 for (uint32_t i = 0; i < import_table_count; i++) { 361 for (uint32_t i = 0; i < import_table_count; i++) {
353 if (failed()) break; 362 if (failed()) break;
354 TRACE("DecodeImportTable[%d] module+%d\n", i, 363 TRACE("DecodeImportTable[%d] module+%d\n", i,
355 static_cast<int>(pc_ - start_)); 364 static_cast<int>(pc_ - start_));
356 365
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 return count < kMaxReserve ? count : kMaxReserve; 419 return count < kMaxReserve ? count : kMaxReserve;
411 } 420 }
412 421
413 void CheckForFunctions(WasmModule* module, WasmSection::Code section) { 422 void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
414 if (module->functions.size() == 0) { 423 if (module->functions.size() == 0) {
415 error(pc_ - 1, nullptr, "functions must appear before section %s", 424 error(pc_ - 1, nullptr, "functions must appear before section %s",
416 WasmSection::getName(section)); 425 WasmSection::getName(section));
417 } 426 }
418 } 427 }
419 428
420 void CheckForPreviousSection(bool* sections, WasmSection::Code section, 429 int CheckSectionOrder(int current_order, WasmSection::Code section) {
421 bool present) { 430 int next_order = WasmSection::getOrder(section);
422 if (section >= WasmSection::Code::Max) return; 431 if (next_order == 0) return current_order;
423 if (sections[(size_t)section] == present) return; 432 if (next_order == current_order) {
424 if (present) { 433 error(pc_, pc_, "section \"%s\" already defined",
425 error(pc_ - 1, nullptr, "required %s section missing",
426 WasmSection::getName(section));
427 } else {
428 error(pc_ - 1, nullptr, "%s section already present",
429 WasmSection::getName(section)); 434 WasmSection::getName(section));
430 } 435 }
436 if (next_order < current_order) {
437 error(pc_, pc_, "section \"%s\" out of order",
438 WasmSection::getName(section));
439 }
440 return next_order;
431 } 441 }
432 442
433 // Decodes a single anonymous function starting at {start_}. 443 // Decodes a single anonymous function starting at {start_}.
434 FunctionResult DecodeSingleFunction(ModuleEnv* module_env, 444 FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
435 WasmFunction* function) { 445 WasmFunction* function) {
436 pc_ = start_; 446 pc_ = start_;
437 function->sig = consume_sig(); // read signature 447 function->sig = consume_sig(); // read signature
438 function->name_offset = 0; // ---- name 448 function->name_offset = 0; // ---- name
439 function->name_length = 0; // ---- name length 449 function->name_length = 0; // ---- name length
440 function->code_start_offset = off(pc_); // ---- code start 450 function->code_start_offset = off(pc_); // ---- code start
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 if (func_index >= module->functions.size()) { 646 if (func_index >= module->functions.size()) {
637 error(pos, pos, "function index %u out of bounds (%d functions)", 647 error(pos, pos, "function index %u out of bounds (%d functions)",
638 func_index, static_cast<int>(module->functions.size())); 648 func_index, static_cast<int>(module->functions.size()));
639 *func = nullptr; 649 *func = nullptr;
640 return 0; 650 return 0;
641 } 651 }
642 *func = &module->functions[func_index]; 652 *func = &module->functions[func_index];
643 return func_index; 653 return func_index;
644 } 654 }
645 655
646 // Reads a section name.
647 WasmSection::Code consume_section_name(int* string_leb_length,
648 uint32_t* string_length) {
649 *string_length = consume_u32v(string_leb_length, "name length");
650 const byte* start = pc_;
651 consume_bytes(*string_length);
652 if (failed()) {
653 TRACE("Section name of length %u couldn't be read\n", *string_length);
654 return WasmSection::Code::Max;
655 }
656 // TODO(jfb) Linear search, it may be better to do a common-prefix search.
657 for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end();
658 i = WasmSection::next(i)) {
659 if (WasmSection::getNameLength(i) == *string_length &&
660 0 == memcmp(WasmSection::getName(i), start, *string_length)) {
661 return i;
662 }
663 }
664 TRACE("Unknown section: '");
665 for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i));
666 TRACE("'\n");
667 return WasmSection::Code::Max;
668 }
669
670 // Reads a single 8-bit integer, interpreting it as a local type. 656 // Reads a single 8-bit integer, interpreting it as a local type.
671 LocalType consume_local_type() { 657 LocalType consume_local_type() {
672 byte val = consume_u8("local type"); 658 byte val = consume_u8("local type");
673 LocalTypeCode t = static_cast<LocalTypeCode>(val); 659 LocalTypeCode t = static_cast<LocalTypeCode>(val);
674 switch (t) { 660 switch (t) {
675 case kLocalVoid: 661 case kLocalVoid:
676 return kAstStmt; 662 return kAstStmt;
677 case kLocalI32: 663 case kLocalI32:
678 return kAstI32; 664 return kAstI32;
679 case kLocalI64: 665 case kLocalI64:
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 return FunctionError("size > maximum function size"); 790 return FunctionError("size > maximum function size");
805 isolate->counters()->wasm_function_size_bytes()->AddSample( 791 isolate->counters()->wasm_function_size_bytes()->AddSample(
806 static_cast<int>(size)); 792 static_cast<int>(size));
807 WasmFunction* function = new WasmFunction(); 793 WasmFunction* function = new WasmFunction();
808 ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin); 794 ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
809 return decoder.DecodeSingleFunction(module_env, function); 795 return decoder.DecodeSingleFunction(module_env, function);
810 } 796 }
811 } // namespace wasm 797 } // namespace wasm
812 } // namespace internal 798 } // namespace internal
813 } // namespace v8 799 } // namespace v8
OLDNEW
« no previous file with comments | « src/wasm/encoder.cc ('k') | src/wasm/wasm-module.h » ('j') | src/wasm/wasm-module.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698