| 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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 } | 619 } |
| 617 | 620 |
| 618 // ===== Remaining sections ============================================== | 621 // ===== Remaining sections ============================================== |
| 619 if (section_iter.more() && ok()) { | 622 if (section_iter.more() && ok()) { |
| 620 error(pc(), pc(), "unexpected section: %s", | 623 error(pc(), pc(), "unexpected section: %s", |
| 621 SectionName(section_iter.section_code())); | 624 SectionName(section_iter.section_code())); |
| 622 } | 625 } |
| 623 | 626 |
| 624 if (ok()) { | 627 if (ok()) { |
| 625 CalculateGlobalOffsets(module); | 628 CalculateGlobalOffsets(module); |
| 626 PreinitializeIndirectFunctionTables(module); | |
| 627 } | 629 } |
| 628 const WasmModule* finished_module = module; | 630 const WasmModule* finished_module = module; |
| 629 ModuleResult result = toResult(finished_module); | 631 ModuleResult result = toResult(finished_module); |
| 630 if (FLAG_dump_wasm_module) DumpModule(module, result); | 632 if (FLAG_dump_wasm_module) DumpModule(module, result); |
| 631 return result; | 633 return result; |
| 632 } | 634 } |
| 633 | 635 |
| 634 uint32_t SafeReserve(uint32_t count) { | 636 uint32_t SafeReserve(uint32_t count) { |
| 635 // Avoid OOM by only reserving up to a certain size. | 637 // Avoid OOM by only reserving up to a certain size. |
| 636 const uint32_t kMaxReserve = 20000; | 638 const uint32_t kMaxReserve = 20000; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 for (WasmGlobal& global : module->globals) { | 744 for (WasmGlobal& global : module->globals) { |
| 743 byte size = | 745 byte size = |
| 744 WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type)); | 746 WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(global.type)); |
| 745 offset = (offset + size - 1) & ~(size - 1); // align | 747 offset = (offset + size - 1) & ~(size - 1); // align |
| 746 global.offset = offset; | 748 global.offset = offset; |
| 747 offset += size; | 749 offset += size; |
| 748 } | 750 } |
| 749 module->globals_size = offset; | 751 module->globals_size = offset; |
| 750 } | 752 } |
| 751 | 753 |
| 752 // TODO(titzer): this only works without overlapping initializations from | |
| 753 // global bases for entries | |
| 754 void PreinitializeIndirectFunctionTables(WasmModule* module) { | |
| 755 // Fill all tables with invalid entries first. | |
| 756 for (WasmIndirectFunctionTable& table : module->function_tables) { | |
| 757 table.values.resize(table.size); | |
| 758 for (size_t i = 0; i < table.size; i++) { | |
| 759 table.values[i] = kInvalidFunctionIndex; | |
| 760 } | |
| 761 } | |
| 762 for (WasmTableInit& init : module->table_inits) { | |
| 763 if (init.offset.kind != WasmInitExpr::kI32Const) continue; | |
| 764 if (init.table_index >= module->function_tables.size()) continue; | |
| 765 WasmIndirectFunctionTable& table = | |
| 766 module->function_tables[init.table_index]; | |
| 767 for (size_t i = 0; i < init.entries.size(); i++) { | |
| 768 size_t index = i + init.offset.val.i32_const; | |
| 769 if (index < table.values.size()) { | |
| 770 table.values[index] = init.entries[i]; | |
| 771 } | |
| 772 } | |
| 773 } | |
| 774 } | |
| 775 | |
| 776 // Verifies the body (code) of a given function. | 754 // Verifies the body (code) of a given function. |
| 777 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, | 755 void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv, |
| 778 WasmFunction* function) { | 756 WasmFunction* function) { |
| 779 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { | 757 if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) { |
| 780 OFStream os(stdout); | 758 OFStream os(stdout); |
| 781 os << "Verifying WASM function " << WasmFunctionName(function, menv) | 759 os << "Verifying WASM function " << WasmFunctionName(function, menv) |
| 782 << std::endl; | 760 << std::endl; |
| 783 } | 761 } |
| 784 FunctionBody body = {menv, function->sig, start_, | 762 FunctionBody body = {menv, function->sig, start_, |
| 785 start_ + function->code_start_offset, | 763 start_ + function->code_start_offset, |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 859 static_cast<int>(vector.size())); | 837 static_cast<int>(vector.size())); |
| 860 *ptr = nullptr; | 838 *ptr = nullptr; |
| 861 return 0; | 839 return 0; |
| 862 } | 840 } |
| 863 *ptr = &vector[index]; | 841 *ptr = &vector[index]; |
| 864 return index; | 842 return index; |
| 865 } | 843 } |
| 866 | 844 |
| 867 void consume_resizable_limits(const char* name, const char* units, | 845 void consume_resizable_limits(const char* name, const char* units, |
| 868 uint32_t max_value, uint32_t* initial, | 846 uint32_t max_value, uint32_t* initial, |
| 869 uint32_t* maximum) { | 847 bool* has_max, uint32_t* maximum) { |
| 870 uint32_t flags = consume_u32v("resizable limits flags"); | 848 uint32_t flags = consume_u32v("resizable limits flags"); |
| 871 const byte* pos = pc(); | 849 const byte* pos = pc(); |
| 872 *initial = consume_u32v("initial size"); | 850 *initial = consume_u32v("initial size"); |
| 851 *has_max = false; |
| 873 if (*initial > max_value) { | 852 if (*initial > max_value) { |
| 874 error(pos, pos, | 853 error(pos, pos, |
| 875 "initial %s size (%u %s) is larger than maximum allowable (%u)", | 854 "initial %s size (%u %s) is larger than implementation limit (%u)", |
| 876 name, *initial, units, max_value); | 855 name, *initial, units, max_value); |
| 877 } | 856 } |
| 878 if (flags & 1) { | 857 if (flags & 1) { |
| 858 *has_max = true; |
| 879 pos = pc(); | 859 pos = pc(); |
| 880 *maximum = consume_u32v("maximum size"); | 860 *maximum = consume_u32v("maximum size"); |
| 881 if (*maximum > max_value) { | 861 if (*maximum > max_value) { |
| 882 error(pos, pos, | 862 error( |
| 883 "maximum %s size (%u %s) is larger than maximum allowable (%u)", | 863 pos, pos, |
| 884 name, *maximum, units, max_value); | 864 "maximum %s size (%u %s) is larger than implementation limit (%u)", |
| 865 name, *maximum, units, max_value); |
| 885 } | 866 } |
| 886 if (*maximum < *initial) { | 867 if (*maximum < *initial) { |
| 887 error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)", | 868 error(pos, pos, "maximum %s size (%u %s) is less than initial (%u %s)", |
| 888 name, *maximum, units, *initial, units); | 869 name, *maximum, units, *initial, units); |
| 889 } | 870 } |
| 890 } else { | 871 } else { |
| 891 *maximum = 0; | 872 *has_max = false; |
| 873 *maximum = max_value; |
| 892 } | 874 } |
| 893 } | 875 } |
| 894 | 876 |
| 895 bool expect_u8(const char* name, uint8_t expected) { | 877 bool expect_u8(const char* name, uint8_t expected) { |
| 896 const byte* pos = pc(); | 878 const byte* pos = pc(); |
| 897 uint8_t value = consume_u8(name); | 879 uint8_t value = consume_u8(name); |
| 898 if (value != expected) { | 880 if (value != expected) { |
| 899 error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); | 881 error(pos, pos, "expected %s 0x%02x, got 0x%02x", name, expected, value); |
| 900 return false; | 882 return false; |
| 901 } | 883 } |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1214 table.push_back(std::move(func_asm_offsets)); | 1196 table.push_back(std::move(func_asm_offsets)); |
| 1215 } | 1197 } |
| 1216 if (decoder.more()) decoder.error("unexpected additional bytes"); | 1198 if (decoder.more()) decoder.error("unexpected additional bytes"); |
| 1217 | 1199 |
| 1218 return decoder.toResult(std::move(table)); | 1200 return decoder.toResult(std::move(table)); |
| 1219 } | 1201 } |
| 1220 | 1202 |
| 1221 } // namespace wasm | 1203 } // namespace wasm |
| 1222 } // namespace internal | 1204 } // namespace internal |
| 1223 } // namespace v8 | 1205 } // namespace v8 |
| OLD | NEW |