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

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

Issue 2396433008: [wasm] Add guard regions to end of WebAssembly.Memory buffers (Closed)
Patch Set: Cleanup 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
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 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, 79 void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
80 Handle<Object> new_ref) { 80 Handle<Object> new_ref) {
81 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); 81 for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
82 it.next()) { 82 it.next()) {
83 if (it.rinfo()->target_object() == *old_ref) { 83 if (it.rinfo()->target_object() == *old_ref) {
84 it.rinfo()->set_target_object(*new_ref); 84 it.rinfo()->set_target_object(*new_ref);
85 } 85 }
86 } 86 }
87 } 87 }
88 88
89 Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) { 89 #if V8_HOST_ARCH_64_BIT
90 if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) { 90 static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) {
91 // TODO(titzer): lift restriction on maximum memory allocated here. 91 JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter());
92 return Handle<JSArrayBuffer>::null(); 92 JSArrayBuffer* buffer = *p;
93 }
94 void* memory = isolate->array_buffer_allocator()->Allocate(size);
95 if (memory == nullptr) {
96 return Handle<JSArrayBuffer>::null();
97 }
98 93
99 #if DEBUG 94 void* memory = buffer->backing_store();
100 // Double check the API allocator actually zero-initialized the memory. 95 base::OS::Free(memory, kWasmMaxHeapOffset);
101 const byte* bytes = reinterpret_cast<const byte*>(memory); 96
102 for (size_t i = 0; i < size; ++i) { 97 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
103 DCHECK_EQ(0, bytes[i]); 98 -buffer->byte_length()->Number());
104 } 99
100 GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
101 }
105 #endif 102 #endif
106 103
107 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer(); 104 void* AllocateBackingStore(Isolate* isolate, size_t size, bool guard) {
108 JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size)); 105 if (guard) {
109 buffer->set_is_neuterable(false); 106 #if V8_HOST_ARCH_64_BIT
110 return buffer; 107 void* memory;
108 // TODO(eholk): On Windows we want to make sure we don't commit the guard
109 // pages yet.
110
111 // We always allocate the largest possible offset into the heap, so the
112 // addressable memory after the guard page can be make inaccessible.
113 const size_t alloc_size = kWasmMaxHeapOffset;
114 DCHECK(size % base::OS::CommitPageSize() == 0);
115
116 size_t allocated_size = 0;
117 const bool is_executable = false;
118 memory = base::OS::Allocate(alloc_size, &allocated_size, is_executable);
119 if (allocated_size < alloc_size) {
120 base::OS::Free(memory, allocated_size);
121 return nullptr;
122 }
123
124 if (memory == nullptr) {
125 return nullptr;
126 }
127
128 byte* bytes = reinterpret_cast<byte*>(memory);
129 base::OS::Guard(bytes + size, alloc_size - size);
130
131 reinterpret_cast<v8::Isolate*>(isolate)
132 ->AdjustAmountOfExternalAllocatedMemory(size);
133
134 return memory;
135 #else
136 DCHECK(false && "Guard pages are not supported on 32-bit systems");
137 #endif
138 } else {
139 void* memory = isolate->array_buffer_allocator()->Allocate(size);
140 return memory;
141 }
111 } 142 }
112 143
113 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table, 144 void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,
114 Address old_start, Address start, 145 Address old_start, Address start,
115 uint32_t prev_size, uint32_t new_size) { 146 uint32_t prev_size, uint32_t new_size) {
116 for (int i = 0; i < code_table->length(); ++i) { 147 for (int i = 0; i < code_table->length(); ++i) {
117 DCHECK(code_table->get(i)->IsCode()); 148 DCHECK(code_table->get(i)->IsCode());
118 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i))); 149 Handle<Code> code = Handle<Code>(Code::cast(code_table->get(i)));
119 AllowDeferredHandleDereference embedding_raw_address; 150 AllowDeferredHandleDereference embedding_raw_address;
120 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) | 151 int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0))); 626 TRACE_CHAIN(WasmCompiledModule::cast(wasm_module->GetInternalField(0)));
596 TRACE("}\n"); 627 TRACE("}\n");
597 } 628 }
598 compiled_module->reset_weak_owning_instance(); 629 compiled_module->reset_weak_owning_instance();
599 GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); 630 GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
600 TRACE("}\n"); 631 TRACE("}\n");
601 } 632 }
602 633
603 } // namespace 634 } // namespace
604 635
636 Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
637 bool guard) {
638 if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) {
639 // TODO(titzer): lift restriction on maximum memory allocated here.
640 return Handle<JSArrayBuffer>::null();
641 }
642
643 void* memory = AllocateBackingStore(isolate, size, guard);
644 bool is_external = guard;
645
646 if (memory == nullptr) {
647 return Handle<JSArrayBuffer>::null();
648 }
649
650 #if DEBUG
651 // Double check the API allocator actually zero-initialized the memory.
652 const byte* bytes = reinterpret_cast<const byte*>(memory);
653 for (size_t i = 0; i < size; ++i) {
654 DCHECK_EQ(0, bytes[i]);
655 }
656 #endif
657
658 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
659 JSArrayBuffer::Setup(buffer, isolate, is_external, memory,
660 static_cast<int>(size));
661 buffer->set_is_neuterable(false);
662 buffer->set_has_guard_region(guard);
663
664 #if V8_HOST_ARCH_64_BIT
665 if (is_external) {
666 // We mark the buffer as external if we allocated it here with guard
667 // pages. That means we need to arrange for it to be freed.
668
669 // TODO(eholk): Finalizers may not run when the main thread is shutting
670 // down, which means we may leak memory here.
671 Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
672 GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
673 &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
674 }
675 #endif
676
677 return buffer;
678 }
679
605 const char* wasm::SectionName(WasmSectionCode code) { 680 const char* wasm::SectionName(WasmSectionCode code) {
606 switch (code) { 681 switch (code) {
607 case kUnknownSectionCode: 682 case kUnknownSectionCode:
608 return "Unknown"; 683 return "Unknown";
609 case kTypeSectionCode: 684 case kTypeSectionCode:
610 return "Type"; 685 return "Type";
611 case kImportSectionCode: 686 case kImportSectionCode:
612 return "Import"; 687 return "Import";
613 case kFunctionSectionCode: 688 case kFunctionSectionCode:
614 return "Function"; 689 return "Function";
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after
946 instance->SetInternalField(kWasmMemObject, 1021 instance->SetInternalField(kWasmMemObject,
947 isolate_->heap()->undefined_value()); 1022 isolate_->heap()->undefined_value());
948 1023
949 //-------------------------------------------------------------------------- 1024 //--------------------------------------------------------------------------
950 // Set up the globals for the new instance. 1025 // Set up the globals for the new instance.
951 //-------------------------------------------------------------------------- 1026 //--------------------------------------------------------------------------
952 MaybeHandle<JSArrayBuffer> old_globals; 1027 MaybeHandle<JSArrayBuffer> old_globals;
953 MaybeHandle<JSArrayBuffer> globals; 1028 MaybeHandle<JSArrayBuffer> globals;
954 uint32_t globals_size = module_->globals_size; 1029 uint32_t globals_size = module_->globals_size;
955 if (globals_size > 0) { 1030 if (globals_size > 0) {
1031 const bool guard = false;
956 Handle<JSArrayBuffer> global_buffer = 1032 Handle<JSArrayBuffer> global_buffer =
957 NewArrayBuffer(isolate_, globals_size); 1033 NewArrayBuffer(isolate_, globals_size, guard);
958 globals = global_buffer; 1034 globals = global_buffer;
959 if (globals.is_null()) { 1035 if (globals.is_null()) {
960 thrower_->RangeError("Out of memory: wasm globals"); 1036 thrower_->RangeError("Out of memory: wasm globals");
961 return nothing; 1037 return nothing;
962 } 1038 }
963 Address old_address = owner.is_null() 1039 Address old_address = owner.is_null()
964 ? nullptr 1040 ? nullptr
965 : GetGlobalStartAddressFromCodeTemplate( 1041 : GetGlobalStartAddressFromCodeTemplate(
966 isolate_->heap()->undefined_value(), 1042 isolate_->heap()->undefined_value(),
967 JSObject::cast(*owner.ToHandleChecked())); 1043 JSObject::cast(*owner.ToHandleChecked()));
(...skipping 18 matching lines...) Expand all
986 //-------------------------------------------------------------------------- 1062 //--------------------------------------------------------------------------
987 MaybeHandle<JSArrayBuffer> old_memory; 1063 MaybeHandle<JSArrayBuffer> old_memory;
988 1064
989 uint32_t min_mem_pages = module_->min_mem_pages; 1065 uint32_t min_mem_pages = module_->min_mem_pages;
990 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages); 1066 isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
991 // TODO(wasm): re-enable counter for max_mem_pages when we use that field. 1067 // TODO(wasm): re-enable counter for max_mem_pages when we use that field.
992 1068
993 if (!memory_.is_null()) { 1069 if (!memory_.is_null()) {
994 // Set externally passed ArrayBuffer non neuterable. 1070 // Set externally passed ArrayBuffer non neuterable.
995 memory_->set_is_neuterable(false); 1071 memory_->set_is_neuterable(false);
1072
1073 DCHECK_IMPLIES(FLAG_wasm_guard_pages, module_->origin == kAsmJsOrigin ||
1074 memory_->has_guard_region());
996 } else if (min_mem_pages > 0) { 1075 } else if (min_mem_pages > 0) {
997 memory_ = AllocateMemory(min_mem_pages); 1076 memory_ = AllocateMemory(min_mem_pages);
998 if (memory_.is_null()) return nothing; // failed to allocate memory 1077 if (memory_.is_null()) return nothing; // failed to allocate memory
999 } 1078 }
1000 1079
1001 if (!memory_.is_null()) { 1080 if (!memory_.is_null()) {
1002 instance->SetInternalField(kWasmMemArrayBuffer, *memory_); 1081 instance->SetInternalField(kWasmMemArrayBuffer, *memory_);
1003 Address mem_start = static_cast<Address>(memory_->backing_store()); 1082 Address mem_start = static_cast<Address>(memory_->backing_store());
1004 uint32_t mem_size = 1083 uint32_t mem_size =
1005 static_cast<uint32_t>(memory_->byte_length()->Number()); 1084 static_cast<uint32_t>(memory_->byte_length()->Number());
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after
1500 } 1579 }
1501 } 1580 }
1502 } 1581 }
1503 1582
1504 // Allocate memory for a module instance as a new JSArrayBuffer. 1583 // Allocate memory for a module instance as a new JSArrayBuffer.
1505 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) { 1584 Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) {
1506 if (min_mem_pages > WasmModule::kMaxMemPages) { 1585 if (min_mem_pages > WasmModule::kMaxMemPages) {
1507 thrower_->RangeError("Out of memory: wasm memory too large"); 1586 thrower_->RangeError("Out of memory: wasm memory too large");
1508 return Handle<JSArrayBuffer>::null(); 1587 return Handle<JSArrayBuffer>::null();
1509 } 1588 }
1589 const bool guard = FLAG_wasm_guard_pages;
1510 Handle<JSArrayBuffer> mem_buffer = 1590 Handle<JSArrayBuffer> mem_buffer =
1511 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize); 1591 NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize, guard);
1512 1592
1513 if (mem_buffer.is_null()) { 1593 if (mem_buffer.is_null()) {
1514 thrower_->RangeError("Out of memory: wasm memory"); 1594 thrower_->RangeError("Out of memory: wasm memory");
1515 } 1595 }
1516 return mem_buffer; 1596 return mem_buffer;
1517 } 1597 }
1518 1598
1519 // Process the exports, creating wrappers for functions, tables, memories, 1599 // Process the exports, creating wrappers for functions, tables, memories,
1520 // and globals. 1600 // and globals.
1521 void ProcessExports(MaybeHandle<JSArrayBuffer> globals, 1601 void ProcessExports(MaybeHandle<JSArrayBuffer> globals,
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after
1992 // "undefined" case above. 2072 // "undefined" case above.
1993 DCHECK_NOT_NULL(old_mem_start); 2073 DCHECK_NOT_NULL(old_mem_start);
1994 DCHECK(old_size + pages * WasmModule::kPageSize <= 2074 DCHECK(old_size + pages * WasmModule::kPageSize <=
1995 std::numeric_limits<uint32_t>::max()); 2075 std::numeric_limits<uint32_t>::max());
1996 new_size = old_size + pages * WasmModule::kPageSize; 2076 new_size = old_size + pages * WasmModule::kPageSize;
1997 } 2077 }
1998 2078
1999 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { 2079 if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) {
2000 return -1; 2080 return -1;
2001 } 2081 }
2002 Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size); 2082
2003 if (buffer.is_null()) return -1; 2083 Handle<JSArrayBuffer> buffer;
2004 Address new_mem_start = static_cast<Address>(buffer->backing_store()); 2084
2005 if (old_size != 0) { 2085 if (FLAG_wasm_guard_pages && !old_buffer.is_null()) {
2006 memcpy(new_mem_start, old_mem_start, old_size); 2086 base::OS::Unprotect(old_buffer->backing_store(), new_size);
2087 reinterpret_cast<v8::Isolate*>(isolate)
2088 ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize);
2089 Handle<Object> new_size_object =
2090 isolate->factory()->NewNumberFromSize(new_size);
2091 old_buffer->set_byte_length(*new_size_object);
2092
2093 SetInstanceMemory(instance, *old_buffer);
2094 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
2095 RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start,
2096 old_size, new_size);
2097 buffer = old_buffer;
2098 } else {
2099 const bool guard = FLAG_wasm_guard_pages;
2100 buffer = NewArrayBuffer(isolate, new_size, guard);
2101 if (buffer.is_null()) return -1;
2102 Address new_mem_start = static_cast<Address>(buffer->backing_store());
2103 if (old_size != 0) {
2104 memcpy(new_mem_start, old_mem_start, old_size);
2105 }
2106 SetInstanceMemory(instance, *buffer);
2107 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
2108 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
2109 old_size, new_size);
2007 } 2110 }
2008 SetInstanceMemory(instance, *buffer); 2111
2009 Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
2010 RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
2011 old_size, new_size);
2012 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), 2112 Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject),
2013 isolate); 2113 isolate);
2014 if (!memory_object->IsUndefined(isolate)) { 2114 if (!memory_object->IsUndefined(isolate)) {
2015 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); 2115 WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer);
2016 } 2116 }
2017 2117
2018 DCHECK(old_size % WasmModule::kPageSize == 0); 2118 DCHECK(old_size % WasmModule::kPageSize == 0);
2019 return (old_size / WasmModule::kPageSize); 2119 return (old_size / WasmModule::kPageSize);
2020 } 2120 }
2021 2121
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
2090 CHECK_NOT_NULL(result.val); 2190 CHECK_NOT_NULL(result.val);
2091 module = const_cast<WasmModule*>(result.val); 2191 module = const_cast<WasmModule*>(result.val);
2092 } 2192 }
2093 2193
2094 Handle<WasmModuleWrapper> module_wrapper = 2194 Handle<WasmModuleWrapper> module_wrapper =
2095 WasmModuleWrapper::New(isolate, module); 2195 WasmModuleWrapper::New(isolate, module);
2096 2196
2097 compiled_module->set_module_wrapper(module_wrapper); 2197 compiled_module->set_module_wrapper(module_wrapper);
2098 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); 2198 DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
2099 } 2199 }
OLDNEW
« src/objects-inl.h ('K') | « src/wasm/wasm-module.h ('k') | test/intl/intl.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698