| OLD | NEW |
| 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/flags.h" | 9 #include "src/flags.h" |
| 10 #include "src/macro-assembler.h" | 10 #include "src/macro-assembler.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 } while (false) | 24 } while (false) |
| 25 #else | 25 #else |
| 26 #define TRACE(...) | 26 #define TRACE(...) |
| 27 #endif | 27 #endif |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 const char* kNameString = "name"; | 31 const char* kNameString = "name"; |
| 32 const size_t kNameStringLength = 4; | 32 const size_t kNameStringLength = 4; |
| 33 | 33 |
| 34 static const uint32_t kMaxTableSize = 1 << 28; | |
| 35 | |
| 36 LocalType TypeOf(const WasmModule* module, const WasmInitExpr& expr) { | 34 LocalType TypeOf(const WasmModule* module, const WasmInitExpr& expr) { |
| 37 switch (expr.kind) { | 35 switch (expr.kind) { |
| 38 case WasmInitExpr::kNone: | 36 case WasmInitExpr::kNone: |
| 39 return kAstStmt; | 37 return kAstStmt; |
| 40 case WasmInitExpr::kGlobalIndex: | 38 case WasmInitExpr::kGlobalIndex: |
| 41 return expr.val.global_index < module->globals.size() | 39 return expr.val.global_index < module->globals.size() |
| 42 ? module->globals[expr.val.global_index].type | 40 ? module->globals[expr.val.global_index].type |
| 43 : kAstStmt; | 41 : kAstStmt; |
| 44 case WasmInitExpr::kI32Const: | 42 case WasmInitExpr::kI32Const: |
| 45 return kAstI32; | 43 return kAstI32; |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 true, // imported | 302 true, // imported |
| 305 false}); // exported | 303 false}); // exported |
| 306 WasmFunction* function = &module->functions.back(); | 304 WasmFunction* function = &module->functions.back(); |
| 307 function->sig_index = consume_sig_index(module, &function->sig); | 305 function->sig_index = consume_sig_index(module, &function->sig); |
| 308 break; | 306 break; |
| 309 } | 307 } |
| 310 case kExternalTable: { | 308 case kExternalTable: { |
| 311 // ===== Imported table ========================================== | 309 // ===== Imported table ========================================== |
| 312 import->index = | 310 import->index = |
| 313 static_cast<uint32_t>(module->function_tables.size()); | 311 static_cast<uint32_t>(module->function_tables.size()); |
| 314 module->function_tables.push_back( | 312 module->function_tables.push_back({0, 0, false, |
| 315 {0, 0, std::vector<int32_t>(), true, false, SignatureMap()}); | 313 std::vector<int32_t>(), true, |
| 314 false, SignatureMap()}); |
| 316 expect_u8("element type", kWasmAnyFunctionTypeForm); | 315 expect_u8("element type", kWasmAnyFunctionTypeForm); |
| 317 WasmIndirectFunctionTable* table = &module->function_tables.back(); | 316 WasmIndirectFunctionTable* table = &module->function_tables.back(); |
| 318 consume_resizable_limits("element count", "elements", kMaxTableSize, | 317 consume_resizable_limits( |
| 319 &table->size, &table->max_size); | 318 "element count", "elements", WasmModule::kV8MaxTableSize, |
| 319 &table->min_size, &table->has_max, &table->max_size); |
| 320 break; | 320 break; |
| 321 } | 321 } |
| 322 case kExternalMemory: { | 322 case kExternalMemory: { |
| 323 // ===== Imported memory ========================================= | 323 // ===== Imported memory ========================================= |
| 324 consume_resizable_limits( | 324 bool has_max = false; |
| 325 "memory", "pages", WasmModule::kMaxLegalPages, | 325 consume_resizable_limits("memory", "pages", WasmModule::kV8MaxPages, |
| 326 &module->min_mem_pages, &module->max_mem_pages); | 326 &module->min_mem_pages, &has_max, |
| 327 &module->max_mem_pages); |
| 327 break; | 328 break; |
| 328 } | 329 } |
| 329 case kExternalGlobal: { | 330 case kExternalGlobal: { |
| 330 // ===== Imported global ========================================= | 331 // ===== Imported global ========================================= |
| 331 import->index = static_cast<uint32_t>(module->globals.size()); | 332 import->index = static_cast<uint32_t>(module->globals.size()); |
| 332 module->globals.push_back( | 333 module->globals.push_back( |
| 333 {kAstStmt, false, WasmInitExpr(), 0, true, false}); | 334 {kAstStmt, false, WasmInitExpr(), 0, true, false}); |
| 334 WasmGlobal* global = &module->globals.back(); | 335 WasmGlobal* global = &module->globals.back(); |
| 335 global->type = consume_value_type(); | 336 global->type = consume_value_type(); |
| 336 global->mutability = consume_u8("mutability") != 0; | 337 global->mutability = consume_u8("mutability") != 0; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 368 | 369 |
| 369 // ===== Table section =================================================== | 370 // ===== Table section =================================================== |
| 370 if (section_iter.section_code() == kTableSectionCode) { | 371 if (section_iter.section_code() == kTableSectionCode) { |
| 371 const byte* pos = pc_; | 372 const byte* pos = pc_; |
| 372 uint32_t table_count = consume_u32v("table count"); | 373 uint32_t table_count = consume_u32v("table count"); |
| 373 // Require at most one table for now. | 374 // Require at most one table for now. |
| 374 if (table_count > 1) { | 375 if (table_count > 1) { |
| 375 error(pos, pos, "invalid table count %d, maximum 1", table_count); | 376 error(pos, pos, "invalid table count %d, maximum 1", table_count); |
| 376 } | 377 } |
| 377 if (module->function_tables.size() < 1) { | 378 if (module->function_tables.size() < 1) { |
| 378 module->function_tables.push_back( | 379 module->function_tables.push_back({0, 0, false, std::vector<int32_t>(), |
| 379 {0, 0, std::vector<int32_t>(), false, false, SignatureMap()}); | 380 false, false, SignatureMap()}); |
| 380 } | 381 } |
| 381 | 382 |
| 382 for (uint32_t i = 0; ok() && i < table_count; i++) { | 383 for (uint32_t i = 0; ok() && i < table_count; i++) { |
| 383 WasmIndirectFunctionTable* table = &module->function_tables.back(); | 384 WasmIndirectFunctionTable* table = &module->function_tables.back(); |
| 384 expect_u8("table type", kWasmAnyFunctionTypeForm); | 385 expect_u8("table type", kWasmAnyFunctionTypeForm); |
| 385 consume_resizable_limits("table elements", "elements", kMaxUInt32, | 386 consume_resizable_limits("table elements", "elements", |
| 386 &table->size, &table->max_size); | 387 WasmModule::kV8MaxTableSize, &table->min_size, |
| 388 &table->has_max, &table->max_size); |
| 387 } | 389 } |
| 388 section_iter.advance(); | 390 section_iter.advance(); |
| 389 } | 391 } |
| 390 | 392 |
| 391 // ===== Memory section ================================================== | 393 // ===== Memory section ================================================== |
| 392 if (section_iter.section_code() == kMemorySectionCode) { | 394 if (section_iter.section_code() == kMemorySectionCode) { |
| 393 const byte* pos = pc_; | 395 const byte* pos = pc_; |
| 394 uint32_t memory_count = consume_u32v("memory count"); | 396 uint32_t memory_count = consume_u32v("memory count"); |
| 395 // Require at most one memory for now. | 397 // Require at most one memory for now. |
| 396 if (memory_count > 1) { | 398 if (memory_count > 1) { |
| 397 error(pos, pos, "invalid memory count %d, maximum 1", memory_count); | 399 error(pos, pos, "invalid memory count %d, maximum 1", memory_count); |
| 398 } | 400 } |
| 399 | 401 |
| 400 for (uint32_t i = 0; ok() && i < memory_count; i++) { | 402 for (uint32_t i = 0; ok() && i < memory_count; i++) { |
| 401 consume_resizable_limits("memory", "pages", WasmModule::kMaxLegalPages, | 403 bool has_max = false; |
| 402 &module->min_mem_pages, | 404 consume_resizable_limits("memory", "pages", WasmModule::kV8MaxPages, |
| 405 &module->min_mem_pages, &has_max, |
| 403 &module->max_mem_pages); | 406 &module->max_mem_pages); |
| 404 } | 407 } |
| 405 section_iter.advance(); | 408 section_iter.advance(); |
| 406 } | 409 } |
| 407 | 410 |
| 408 // ===== Global section ================================================== | 411 // ===== Global section ================================================== |
| 409 if (section_iter.section_code() == kGlobalSectionCode) { | 412 if (section_iter.section_code() == kGlobalSectionCode) { |
| 410 uint32_t globals_count = consume_u32v("globals count"); | 413 uint32_t globals_count = consume_u32v("globals count"); |
| 411 uint32_t imported_globals = static_cast<uint32_t>(module->globals.size()); | 414 uint32_t imported_globals = static_cast<uint32_t>(module->globals.size()); |
| 412 if (!IsWithinLimit(std::numeric_limits<int32_t>::max(), globals_count, | 415 if (!IsWithinLimit(std::numeric_limits<int32_t>::max(), globals_count, |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 } | 617 } |
| 615 | 618 |
| 616 // ===== Remaining sections ============================================== | 619 // ===== Remaining sections ============================================== |
| 617 if (section_iter.more() && ok()) { | 620 if (section_iter.more() && ok()) { |
| 618 error(pc(), pc(), "unexpected section: %s", | 621 error(pc(), pc(), "unexpected section: %s", |
| 619 SectionName(section_iter.section_code())); | 622 SectionName(section_iter.section_code())); |
| 620 } | 623 } |
| 621 | 624 |
| 622 if (ok()) { | 625 if (ok()) { |
| 623 CalculateGlobalOffsets(module); | 626 CalculateGlobalOffsets(module); |
| 624 PreinitializeIndirectFunctionTables(module); | |
| 625 } | 627 } |
| 626 const WasmModule* finished_module = module; | 628 const WasmModule* finished_module = module; |
| 627 ModuleResult result = toResult(finished_module); | 629 ModuleResult result = toResult(finished_module); |
| 628 if (FLAG_dump_wasm_module) DumpModule(module, result); | 630 if (FLAG_dump_wasm_module) DumpModule(module, result); |
| 629 return result; | 631 return result; |
| 630 } | 632 } |
| 631 | 633 |
| 632 uint32_t SafeReserve(uint32_t count) { | 634 uint32_t SafeReserve(uint32_t count) { |
| 633 // Avoid OOM by only reserving up to a certain size. | 635 // Avoid OOM by only reserving up to a certain size. |
| 634 const uint32_t kMaxReserve = 20000; | 636 const uint32_t kMaxReserve = 20000; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 for (WasmGlobal& global : module->globals) { | 742 for (WasmGlobal& global : module->globals) { |
| 741 byte size = | 743 byte size = |
| 742 WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type)); | 744 WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type)); |
| 743 offset = (offset + size - 1) & ~(size - 1); // align | 745 offset = (offset + size - 1) & ~(size - 1); // align |
| 744 global.offset = offset; | 746 global.offset = offset; |
| 745 offset += size; | 747 offset += size; |
| 746 } | 748 } |
| 747 module->globals_size = offset; | 749 module->globals_size = offset; |
| 748 } | 750 } |
| 749 | 751 |
| 750 // TODO(titzer): this only works without overlapping initializations from | |
| 751 // global bases for entries | |
| 752 void PreinitializeIndirectFunctionTables(WasmModule* module) { | |
| 753 // Fill all tables with invalid entries first. | |
| 754 for (WasmIndirectFunctionTable& table : module->function_tables) { | |
| 755 table.values.resize(table.size); | |
| 756 for (size_t i = 0; i < table.size; i++) { | |
| 757 table.values[i] = kInvalidFunctionIndex; | |
| 758 } | |
| 759 } | |
| 760 for (WasmTableInit& init : module->table_inits) { | |
| 761 if (init.offset.kind != WasmInitExpr::kI32Const) continue; | |
| 762 if (init.table_index >= module->function_tables.size()) continue; | |
| 763 WasmIndirectFunctionTable& table = | |
| 764 module->function_tables[init.table_index]; | |
| 765 for (size_t i = 0; i < init.entries.size(); i++) { | |
| 766 size_t index = i + init.offset.val.i32_const; | |
| 767 if (index < table.values.size()) { | |
| 768 table.values[index] = init.entries[i]; | |
| 769 } | |
| 770 } | |
| 771 } | |
| 772 } | |
| 773 | |
| 774 // Verifies the body (code) of a given function. | 752 // Verifies the body (code) of a given function. |
| 775 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, | 753 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, |
| 776 WasmFunction* function) { | 754 WasmFunction* function) { |
| 777 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { | 755 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { |
| 778 OFStream os(stdout); | 756 OFStream os(stdout); |
| 779 os << "Verifying WASM function " << WasmFunctionName(function, menv) | 757 os << "Verifying WASM function " << WasmFunctionName(function, menv) |
| 780 << std::endl; | 758 << std::endl; |
| 781 } | 759 } |
| 782 FunctionBody body = {menv, function->sig, start_, | 760 FunctionBody body = {menv, function->sig, start_, |
| 783 start_ + function->code_start_offset, | 761 start_ + function->code_start_offset, |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 static_cast<int>(vector.size())); | 835 static_cast<int>(vector.size())); |
| 858 *ptr = nullptr; | 836 *ptr = nullptr; |
| 859 return 0; | 837 return 0; |
| 860 } | 838 } |
| 861 *ptr = &vector[index]; | 839 *ptr = &vector[index]; |
| 862 return index; | 840 return index; |
| 863 } | 841 } |
| 864 | 842 |
| 865 void consume_resizable_limits(const char* name, const char* units, | 843 void consume_resizable_limits(const char* name, const char* units, |
| 866 uint32_t max_value, uint32_t* initial, | 844 uint32_t max_value, uint32_t* initial, |
| 867 uint32_t* maximum) { | 845 bool* has_max, uint32_t* maximum) { |
| 868 uint32_t flags = consume_u32v("resizable limits flags"); | 846 uint32_t flags = consume_u32v("resizable limits flags"); |
| 869 const byte* pos = pc(); | 847 const byte* pos = pc(); |
| 870 *initial = consume_u32v("initial size"); | 848 *initial = consume_u32v("initial size"); |
| 849 *has_max = false; |
| 871 if (*initial > max_value) { | 850 if (*initial > max_value) { |
| 872 error(pos, pos, | 851 error(pos, pos, |
| 873 "initial %s size (%u %s) is larger than maximum allowable (%u)", | 852 "initial %s size (%u %s) is larger than implementation limit (%u)", |
| 874 name, *initial, units, max_value); | 853 name, *initial, units, max_value); |
| 875 } | 854 } |
| 876 if (flags & 1) { | 855 if (flags & 1) { |
| 856 *has_max = true; |
| 877 pos = pc(); | 857 pos = pc(); |
| 878 *maximum = consume_u32v("maximum size"); | 858 *maximum = consume_u32v("maximum size"); |
| 879 if (*maximum > max_value) { | 859 if (*maximum > max_value) { |
| 880 error(pos, pos, | 860 error( |
| 881 "maximum %s size (%u %s) is larger than maximum allowable (%u)", | 861 pos, pos, |
| 882 name, *maximum, units, max_value); | 862 "maximum %s size (%u %s) is larger than implementation limit (%u)", |
| 863 name, *maximum, units, max_value); |
| 883 } | 864 } |
| 884 if (*maximum < *initial) { | 865 if (*maximum < *initial) { |
| 885 error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)", | 866 error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)", |
| 886 name, *maximum, units, *initial, units); | 867 name, *maximum, units, *initial, units); |
| 887 } | 868 } |
| 888 } else { | 869 } else { |
| 889 *maximum = 0; | 870 *has_max = false; |
| 871 *maximum = max_value; |
| 890 } | 872 } |
| 891 } | 873 } |
| 892 | 874 |
| 893 bool expect_u8(const char* name, uint8_t expected) { | 875 bool expect_u8(const char* name, uint8_t expected) { |
| 894 const byte* pos = pc(); | 876 const byte* pos = pc(); |
| 895 uint8_t value = consume_u8(name); | 877 uint8_t value = consume_u8(name); |
| 896 if (value != expected) { | 878 if (value != expected) { |
| 897 error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); | 879 error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); |
| 898 return false; | 880 return false; |
| 899 } | 881 } |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1212 table.push_back(std::move(func_asm_offsets)); | 1194 table.push_back(std::move(func_asm_offsets)); |
| 1213 } | 1195 } |
| 1214 if (decoder.more()) decoder.error("unexpected additional bytes"); | 1196 if (decoder.more()) decoder.error("unexpected additional bytes"); |
| 1215 | 1197 |
| 1216 return decoder.toResult(std::move(table)); | 1198 return decoder.toResult(std::move(table)); |
| 1217 } | 1199 } |
| 1218 | 1200 |
| 1219 } // namespace wasm | 1201 } // namespace wasm |
| 1220 } // namespace internal | 1202 } // namespace internal |
| 1221 } // namespace v8 | 1203 } // namespace v8 |
| OLD | NEW |