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

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

Issue 2396433008: [wasm] Add guard regions to end of WebAssembly.Memory buffers (Closed)
Patch Set: Merging with master Created 4 years, 1 month 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
« no previous file with comments | « src/wasm/wasm-module.h ('k') | test/cctest/cctest.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <memory> 5 #include <memory>
6 6
7 #include "src/base/atomic-utils.h" 7 #include "src/base/atomic-utils.h"
8 #include "src/code-stubs.h" 8 #include "src/code-stubs.h"
9 9
10 #include "src/macro-assembler.h" 10 #include "src/macro-assembler.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, 63 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
64 Handle<Object> new_ref) { 64 Handle<Object> new_ref) {
65 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); 65 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
66 it.next()) { 66 it.next()) {
67 if (it.rinfo()->target_object() == *old_ref) { 67 if (it.rinfo()->target_object() == *old_ref) {
68 it.rinfo()->set_target_object(*new_ref); 68 it.rinfo()->set_target_object(*new_ref);
69 } 69 }
70 } 70 }
71 } 71 }
72 72
73 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { 73 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) {
74 if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) { 74 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter());
75 // TODO(titzer): lift restriction on maximum memory allocated here. 75 JSArrayBuffer* buffer = *p;
76 return Handle<JSArrayBuffer>::null();
77 }
78 void* memory = isolate->array_buffer_allocator()->Allocate(size);
79 if (memory == nullptr) {
80 return Handle<JSArrayBuffer>::null();
81 }
82 76
83 #if DEBUG 77 void* memory = buffer->backing_store();
84 // Double check the API allocator actually zero-initialized the memory. 78 base::OS::Free(memory,
85 const byte* bytes = reinterpret_cast<const byte*>(memory); 79 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()));
86 for (size_t i = 0; i < size; ++i) { 80
87 DCHECK_EQ(0, bytes[i]); 81 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
88 } 82 -buffer->byte_length()->Number());
83
84 GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
85 }
86
87 #if V8_TARGET_ARCH_64_BIT
88 const bool kGuardRegionsSupported = true;
89 #else
90 const bool kGuardRegionsSupported = false;
89 #endif 91 #endif
90 92
91 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 93 bool EnableGuardRegions() {
92 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size)); 94 return FLAG_wasm_guard_pages && kGuardRegionsSupported;
93 buffer->set_is_neuterable(false); 95 }
94 return buffer; 96
97 void* TryAllocateBackingStore(Isolate* isolate, size_t size,
98 bool enable_guard_regions, bool& is_external) {
99 is_external = false;
100 // TODO(eholk): Right now enable_guard_regions has no effect on 32-bit
101 // systems. It may be safer to fail instead, given that other code might do
102 // things that would be unsafe if they expected guard pages where there
103 // weren't any.
104 if (enable_guard_regions && kGuardRegionsSupported) {
105 // TODO(eholk): On Windows we want to make sure we don't commit the guard
106 // pages yet.
107
108 // We always allocate the largest possible offset into the heap, so the
109 // addressable memory after the guard page can be made inaccessible.
110 const size_t alloc_size =
111 RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize());
112 DCHECK_EQ(0u, size % base::OS::CommitPageSize());
113
114 // AllocateGuarded makes the whole region inaccessible by default.
115 void* memory = base::OS::AllocateGuarded(alloc_size);
116 if (memory == nullptr) {
117 return nullptr;
118 }
119
120 // Make the part we care about accessible.
121 base::OS::Unprotect(memory, size);
122
123 reinterpret_cast<v8::Isolate*>(isolate)
124 ->AdjustAmountOfExternalAllocatedMemory(size);
125
126 is_external = true;
127 return memory;
128 } else {
129 void* memory = isolate->array_buffer_allocator()->Allocate(size);
130 return memory;
131 }
95 } 132 }
96 133
97 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, 134 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,
98 Address old_start, Address start, 135 Address old_start, Address start,
99 uint32_t prev_size, uint32_t new_size) { 136 uint32_t prev_size, uint32_t new_size) {
100 for (int i = 0; i < code_table->length(); ++i) { 137 for (int i = 0; i < code_table->length(); ++i) {
101 DCHECK(code_table->get(i)->IsCode()); 138 DCHECK(code_table->get(i)->IsCode());
102 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); 139 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
103 AllowDeferredHandleDereference embedding_raw_address; 140 AllowDeferredHandleDereference embedding_raw_address;
104 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | 141 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 Handle<WasmCompiledModule> compiled_module, int func_index) { 638 Handle<WasmCompiledModule> compiled_module, int func_index) {
602 int offset, length; 639 int offset, length;
603 std::tie(offset, length) = 640 std::tie(offset, length) =
604 GetFunctionOffsetAndLength(compiled_module, func_index); 641 GetFunctionOffsetAndLength(compiled_module, func_index);
605 return Vector<const uint8_t>( 642 return Vector<const uint8_t>(
606 compiled_module->module_bytes()->GetChars() + offset, length); 643 compiled_module->module_bytes()->GetChars() + offset, length);
607 } 644 }
608 645
609 } // namespace 646 } // namespace
610 647
648 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
649 bool enable_guard_regions) {
650 if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) {
651 // TODO(titzer): lift restriction on maximum memory allocated here.
652 return Handle<JSArrayBuffer>::null();
653 }
654
655 enable_guard_regions = enable_guard_regions && kGuardRegionsSupported;
656
657 bool is_external; // Set by TryAllocateBackingStore
658 void* memory =
659 TryAllocateBackingStore(isolate, size, enable_guard_regions, is_external);
660
661 if (memory == nullptr) {
662 return Handle<JSArrayBuffer>::null();
663 }
664
665 #if DEBUG
666 // Double check the API allocator actually zero-initialized the memory.
667 const byte* bytes = reinterpret_cast<const byte*>(memory);
668 for (size_t i = 0; i < size; ++i) {
669 DCHECK_EQ(0, bytes[i]);
670 }
671 #endif
672
673 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
674 JSArrayBuffer::Setup(buffer, isolate, is_external, memory,
675 static_cast<int>(size));
676 buffer->set_is_neuterable(false);
677 buffer->set_has_guard_region(enable_guard_regions);
678
679 if (is_external) {
680 // We mark the buffer as external if we allocated it here with guard
681 // pages. That means we need to arrange for it to be freed.
682
683 // TODO(eholk): Finalizers may not run when the main thread is shutting
684 // down, which means we may leak memory here.
685 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
686 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
687 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
688 }
689
690 return buffer;
691 }
692
611 const char* wasm::SectionName(WasmSectionCode code) { 693 const char* wasm::SectionName(WasmSectionCode code) {
612 switch (code) { 694 switch (code) {
613 case kUnknownSectionCode: 695 case kUnknownSectionCode:
614 return "Unknown"; 696 return "Unknown";
615 case kTypeSectionCode: 697 case kTypeSectionCode:
616 return "Type"; 698 return "Type";
617 case kImportSectionCode: 699 case kImportSectionCode:
618 return "Import"; 700 return "Import";
619 case kFunctionSectionCode: 701 case kFunctionSectionCode:
620 return "Function"; 702 return "Function";
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after
1052 //-------------------------------------------------------------------------- 1134 //--------------------------------------------------------------------------
1053 Handle<WasmInstanceObject> instance = 1135 Handle<WasmInstanceObject> instance =
1054 WasmInstanceObject::New(isolate_, compiled_module_); 1136 WasmInstanceObject::New(isolate_, compiled_module_);
1055 1137
1056 //-------------------------------------------------------------------------- 1138 //--------------------------------------------------------------------------
1057 // Set up the globals for the new instance. 1139 // Set up the globals for the new instance.
1058 //-------------------------------------------------------------------------- 1140 //--------------------------------------------------------------------------
1059 MaybeHandle<JSArrayBuffer> old_globals; 1141 MaybeHandle<JSArrayBuffer> old_globals;
1060 uint32_t globals_size = module_->globals_size; 1142 uint32_t globals_size = module_->globals_size;
1061 if (globals_size > 0) { 1143 if (globals_size > 0) {
1144 const bool enable_guard_regions = false;
1062 Handle<JSArrayBuffer> global_buffer = 1145 Handle<JSArrayBuffer> global_buffer =
1063 NewArrayBuffer(isolate_, globals_size); 1146 NewArrayBuffer(isolate_, globals_size, enable_guard_regions);
1064 globals_ = global_buffer; 1147 globals_ = global_buffer;
1065 if (globals_.is_null()) { 1148 if (globals_.is_null()) {
1066 thrower_->RangeError("Out of memory: wasm globals"); 1149 thrower_->RangeError("Out of memory: wasm globals");
1067 return nothing; 1150 return nothing;
1068 } 1151 }
1069 Address old_address = 1152 Address old_address =
1070 owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate( 1153 owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
1071 isolate_->heap()->undefined_value(), 1154 isolate_->heap()->undefined_value(),
1072 *owner.ToHandleChecked()); 1155 *owner.ToHandleChecked());
1073 RelocateGlobals(code_table, old_address, 1156 RelocateGlobals(code_table, old_address,
(...skipping 28 matching lines...) Expand all
1102 // Set up the memory for the new instance. 1185 // Set up the memory for the new instance.
1103 //-------------------------------------------------------------------------- 1186 //--------------------------------------------------------------------------
1104 MaybeHandle<JSArrayBuffer> old_memory; 1187 MaybeHandle<JSArrayBuffer> old_memory;
1105 1188
1106 uint32_t min_mem_pages = module_->min_mem_pages; 1189 uint32_t min_mem_pages = module_->min_mem_pages;
1107 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); 1190 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
1108 1191
1109 if (!memory_.is_null()) { 1192 if (!memory_.is_null()) {
1110 // Set externally passed ArrayBuffer non neuterable. 1193 // Set externally passed ArrayBuffer non neuterable.
1111 memory_->set_is_neuterable(false); 1194 memory_->set_is_neuterable(false);
1195
1196 DCHECK_IMPLIES(EnableGuardRegions(), module_->origin == kAsmJsOrigin ||
1197 memory_->has_guard_region());
1112 } else if (min_mem_pages > 0) { 1198 } else if (min_mem_pages > 0) {
1113 memory_ = AllocateMemory(min_mem_pages); 1199 memory_ = AllocateMemory(min_mem_pages);
1114 if (memory_.is_null()) return nothing; // failed to allocate memory 1200 if (memory_.is_null()) return nothing; // failed to allocate memory
1115 } 1201 }
1116 1202
1117 if (!memory_.is_null()) { 1203 if (!memory_.is_null()) {
1118 instance->set_memory_buffer(*memory_); 1204 instance->set_memory_buffer(*memory_);
1119 Address mem_start = static_cast<Address>(memory_->backing_store()); 1205 Address mem_start = static_cast<Address>(memory_->backing_store());
1120 uint32_t mem_size = 1206 uint32_t mem_size =
1121 static_cast<uint32_t>(memory_->byte_length()->Number()); 1207 static_cast<uint32_t>(memory_->byte_length()->Number());
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after
1574 } 1660 }
1575 } 1661 }
1576 } 1662 }
1577 1663
1578 // Allocate memory for a module instance as a new JSArrayBuffer. 1664 // Allocate memory for a module instance as a new JSArrayBuffer.
1579 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { 1665 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) {
1580 if (min_mem_pages > WasmModule::kV8MaxPages) { 1666 if (min_mem_pages > WasmModule::kV8MaxPages) {
1581 thrower_->RangeError("Out of memory: wasm memory too large"); 1667 thrower_->RangeError("Out of memory: wasm memory too large");
1582 return Handle<JSArrayBuffer>::null(); 1668 return Handle<JSArrayBuffer>::null();
1583 } 1669 }
1584 Handle<JSArrayBuffer> mem_buffer = 1670 const bool enable_guard_regions = EnableGuardRegions();
1585 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize); 1671 Handle<JSArrayBuffer> mem_buffer = NewArrayBuffer(
1672 isolate_, min_mem_pages * WasmModule::kPageSize, enable_guard_regions);
1586 1673
1587 if (mem_buffer.is_null()) { 1674 if (mem_buffer.is_null()) {
1588 thrower_->RangeError("Out of memory: wasm memory"); 1675 thrower_->RangeError("Out of memory: wasm memory");
1589 } 1676 }
1590 return mem_buffer; 1677 return mem_buffer;
1591 } 1678 }
1592 1679
1593 // Process the exports, creating wrappers for functions, tables, memories, 1680 // Process the exports, creating wrappers for functions, tables, memories,
1594 // and globals. 1681 // and globals.
1595 void ProcessExports(Handle<FixedArray> code_table, 1682 void ProcessExports(Handle<FixedArray> code_table,
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after
2090 DCHECK_NOT_NULL(old_mem_start); 2177 DCHECK_NOT_NULL(old_mem_start);
2091 DCHECK(old_size + pages * WasmModule::kPageSize <= 2178 DCHECK(old_size + pages * WasmModule::kPageSize <=
2092 std::numeric_limits<uint32_t>::max()); 2179 std::numeric_limits<uint32_t>::max());
2093 new_size = old_size + pages * WasmModule::kPageSize; 2180 new_size = old_size + pages * WasmModule::kPageSize;
2094 } 2181 }
2095 2182
2096 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size || 2183 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
2097 WasmModule::kV8MaxPages * WasmModule::kPageSize < new_size) { 2184 WasmModule::kV8MaxPages * WasmModule::kPageSize < new_size) {
2098 return -1; 2185 return -1;
2099 } 2186 }
2100 Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size); 2187
2101 if (buffer.is_null()) return -1; 2188 Handle<JSArrayBuffer> buffer;
2102 Address new_mem_start = static_cast<Address>(buffer->backing_store()); 2189
2103 if (old_size != 0) { 2190 if (!old_buffer.is_null() && old_buffer->has_guard_region()) {
2104 memcpy(new_mem_start, old_mem_start, old_size); 2191 // We don't move the backing store, we simply change the protection to make
2192 // more of it accessible.
2193 base::OS::Unprotect(old_buffer->backing_store(), new_size);
2194 reinterpret_cast<v8::Isolate*>(isolate)
2195 ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize);
2196 Handle<Object> new_size_object =
2197 isolate->factory()->NewNumberFromSize(new_size);
2198 old_buffer->set_byte_length(*new_size_object);
2199
2200 SetInstanceMemory(instance, *old_buffer);
2201 Handle<FixedArray> code_table =
2202 instance->get_compiled_module()->code_table();
2203 RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start,
2204 old_size, new_size);
2205 buffer = old_buffer;
2206 } else {
2207 const bool enable_guard_regions = false;
2208 buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions);
2209 if (buffer.is_null()) return -1;
2210 Address new_mem_start = static_cast<Address>(buffer->backing_store());
2211 if (old_size != 0) {
2212 memcpy(new_mem_start, old_mem_start, old_size);
2213 }
2214 SetInstanceMemory(instance, *buffer);
2215 Handle<FixedArray> code_table =
2216 instance->get_compiled_module()->code_table();
2217 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
2218 old_size, new_size);
2105 } 2219 }
2220
2106 SetInstanceMemory(instance, *buffer); 2221 SetInstanceMemory(instance, *buffer);
2107 Handle<FixedArray> code_table = instance->get_compiled_module()->code_table();
2108 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
2109 old_size, new_size);
2110 if (instance->has_memory_object()) { 2222 if (instance->has_memory_object()) {
2111 instance->get_memory_object()->set_buffer(*buffer); 2223 instance->get_memory_object()->set_buffer(*buffer);
2112 } 2224 }
2113 2225
2114 DCHECK(old_size % WasmModule::kPageSize == 0); 2226 DCHECK(old_size % WasmModule::kPageSize == 0);
2115 return (old_size / WasmModule::kPageSize); 2227 return (old_size / WasmModule::kPageSize);
2116 } 2228 }
2117 2229
2118 void testing::ValidateInstancesChain(Isolate* isolate, 2230 void testing::ValidateInstancesChain(Isolate* isolate,
2119 Handle<WasmModuleObject> module_obj, 2231 Handle<WasmModuleObject> module_obj,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
2193 MaybeHandle<String> WasmCompiledModule::GetFunctionName( 2305 MaybeHandle<String> WasmCompiledModule::GetFunctionName(
2194 Handle<WasmCompiledModule> compiled_module, uint32_t func_index) { 2306 Handle<WasmCompiledModule> compiled_module, uint32_t func_index) {
2195 DCHECK_LT(func_index, compiled_module->module()->functions.size()); 2307 DCHECK_LT(func_index, compiled_module->module()->functions.size());
2196 WasmFunction& function = compiled_module->module()->functions[func_index]; 2308 WasmFunction& function = compiled_module->module()->functions[func_index];
2197 Isolate* isolate = compiled_module->GetIsolate(); 2309 Isolate* isolate = compiled_module->GetIsolate();
2198 MaybeHandle<String> string = ExtractStringFromModuleBytes( 2310 MaybeHandle<String> string = ExtractStringFromModuleBytes(
2199 isolate, compiled_module, function.name_offset, function.name_length); 2311 isolate, compiled_module, function.name_offset, function.name_length);
2200 if (!string.is_null()) return string.ToHandleChecked(); 2312 if (!string.is_null()) return string.ToHandleChecked();
2201 return {}; 2313 return {};
2202 } 2314 }
OLDNEW
« no previous file with comments | « src/wasm/wasm-module.h ('k') | test/cctest/cctest.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698