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

Unified Diff: src/wasm/wasm-module.cc

Issue 2396433008: [wasm] Add guard regions to end of WebAssembly.Memory buffers (Closed)
Patch Set: Merge branch 'master' of https://chromium.googlesource.com/v8/v8 into guard-pages 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 side-by-side diff with in-line comments
Download patch
Index: src/wasm/wasm-module.cc
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index 64f5663aeb55c0a1fa74914ab16a65f139943169..127e730eacc3777aa1606b99a70b5b5754b94985 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -114,28 +114,62 @@ void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
}
}
-Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) {
- if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) {
- // TODO(titzer): lift restriction on maximum memory allocated here.
- return Handle<JSArrayBuffer>::null();
- }
- void* memory = isolate->array_buffer_allocator()->Allocate(size);
- if (memory == nullptr) {
- return Handle<JSArrayBuffer>::null();
- }
+#if V8_HOST_ARCH_64_BIT
+static void MemoryFinalizer(const v8::WeakCallbackInfo<void>& data) {
+ JSArrayBuffer** p = reinterpret_cast<JSArrayBuffer**>(data.GetParameter());
+ JSArrayBuffer* buffer = *p;
-#if DEBUG
- // Double check the API allocator actually zero-initialized the memory.
- const byte* bytes = reinterpret_cast<const byte*>(memory);
- for (size_t i = 0; i < size; ++i) {
- DCHECK_EQ(0, bytes[i]);
- }
+ void* memory = buffer->backing_store();
+ base::OS::Free(memory,
+ RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize()));
+
+ data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
+ -buffer->byte_length()->Number());
+
+ GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
+}
#endif
- Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
- JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
- buffer->set_is_neuterable(false);
- return buffer;
+void* TryAllocateBackingStore(Isolate* isolate, size_t size, bool guard) {
+ if (guard) {
titzer 2016/11/07 19:54:53 I think this needs to be TARGET_ARCH. How about g
Eric Holk 2016/11/08 23:58:15 Done. I also updated the help text for --wasm_guar
+#if V8_HOST_ARCH_64_BIT
+ void* memory;
+ // TODO(eholk): On Windows we want to make sure we don't commit the guard
+ // pages yet.
+
+ // We always allocate the largest possible offset into the heap, so the
+ // addressable memory after the guard page can be made inaccessible.
+ const size_t alloc_size =
+ RoundUp(kWasmMaxHeapOffset, base::OS::CommitPageSize());
+ DCHECK_EQ(0, size % base::OS::CommitPageSize());
+
+ size_t allocated_size = 0;
+ const bool is_executable = false;
+ memory = base::OS::Allocate(alloc_size, &allocated_size, is_executable);
+ if (allocated_size < alloc_size) {
+ base::OS::Free(memory, allocated_size);
+ return nullptr;
+ }
+
+ if (memory == nullptr) {
+ return nullptr;
+ }
+
+ byte* bytes = reinterpret_cast<byte*>(memory);
+ base::OS::Guard(bytes + size, alloc_size - size);
+
+ reinterpret_cast<v8::Isolate*>(isolate)
+ ->AdjustAmountOfExternalAllocatedMemory(size);
+
+ return memory;
+#else
+ DCHECK(false && "Guard pages are not supported on 32-bit systems");
+ return nullptr;
+#endif
+ } else {
+ void* memory = isolate->array_buffer_allocator()->Allocate(size);
+ return memory;
+ }
}
void RelocateMemoryReferencesInCode(Handle<FixedArray> code_table,
@@ -631,6 +665,50 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
} // namespace
+Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
+ bool enable_guard_regions) {
titzer 2016/11/07 19:54:52 I like this name better. Can we make the header fi
Eric Holk 2016/11/08 23:58:15 Done.
+ if (size > (WasmModule::kV8MaxPages * WasmModule::kPageSize)) {
+ // TODO(titzer): lift restriction on maximum memory allocated here.
+ return Handle<JSArrayBuffer>::null();
+ }
+
+ void* memory = TryAllocateBackingStore(isolate, size, enable_guard_regions);
+ bool is_external = enable_guard_regions;
titzer 2016/11/07 19:54:52 What about making is_external a return value from
Eric Holk 2016/11/08 23:58:15 Done, although it seems like V8_TARGET_ARCH_64_BIT
+
+ if (memory == nullptr) {
+ return Handle<JSArrayBuffer>::null();
+ }
+
+#if DEBUG
+ // Double check the API allocator actually zero-initialized the memory.
+ const byte* bytes = reinterpret_cast<const byte*>(memory);
+ for (size_t i = 0; i < size; ++i) {
+ DCHECK_EQ(0, bytes[i]);
+ }
+#endif
+
+ Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
+ JSArrayBuffer::Setup(buffer, isolate, is_external, memory,
+ static_cast<int>(size));
+ buffer->set_is_neuterable(false);
+ buffer->set_has_guard_region(enable_guard_regions);
+
+#if V8_HOST_ARCH_64_BIT
+ if (is_external) {
+ // We mark the buffer as external if we allocated it here with guard
+ // pages. That means we need to arrange for it to be freed.
+
+ // TODO(eholk): Finalizers may not run when the main thread is shutting
+ // down, which means we may leak memory here.
+ Handle<Object> global_handle = isolate->global_handles()->Create(*buffer);
+ GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
+ &MemoryFinalizer, v8::WeakCallbackType::kFinalizer);
+ }
+#endif
+
+ return buffer;
+}
+
const char* wasm::SectionName(WasmSectionCode code) {
switch (code) {
case kUnknownSectionCode:
@@ -1076,8 +1154,9 @@ class WasmInstanceBuilder {
MaybeHandle<JSArrayBuffer> old_globals;
uint32_t globals_size = module_->globals_size;
if (globals_size > 0) {
+ const bool enable_guard_regions = false;
Handle<JSArrayBuffer> global_buffer =
- NewArrayBuffer(isolate_, globals_size);
+ NewArrayBuffer(isolate_, globals_size, enable_guard_regions);
globals_ = global_buffer;
if (globals_.is_null()) {
thrower_->RangeError("Out of memory: wasm globals");
@@ -1128,6 +1207,9 @@ class WasmInstanceBuilder {
if (!memory_.is_null()) {
// Set externally passed ArrayBuffer non neuterable.
memory_->set_is_neuterable(false);
+
+ DCHECK_IMPLIES(FLAG_wasm_guard_pages, module_->origin == kAsmJsOrigin ||
+ memory_->has_guard_region());
} else if (min_mem_pages > 0) {
memory_ = AllocateMemory(min_mem_pages);
if (memory_.is_null()) return nothing; // failed to allocate memory
@@ -1579,8 +1661,9 @@ class WasmInstanceBuilder {
thrower_->RangeError("Out of memory: wasm memory too large");
return Handle<JSArrayBuffer>::null();
}
- Handle<JSArrayBuffer> mem_buffer =
- NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize);
+ const bool enable_guard_regions = FLAG_wasm_guard_pages;
+ Handle<JSArrayBuffer> mem_buffer = NewArrayBuffer(
+ isolate_, min_mem_pages * WasmModule::kPageSize, enable_guard_regions);
if (mem_buffer.is_null()) {
thrower_->RangeError("Out of memory: wasm memory");
@@ -2141,16 +2224,36 @@ int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance,
if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) {
return -1;
}
- Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size);
- if (buffer.is_null()) return -1;
- Address new_mem_start = static_cast<Address>(buffer->backing_store());
- if (old_size != 0) {
- memcpy(new_mem_start, old_mem_start, old_size);
+
+ Handle<JSArrayBuffer> buffer;
+
+ if (FLAG_wasm_guard_pages && !old_buffer.is_null()) {
titzer 2016/11/07 19:54:53 How about !old_buffer.is_null() and old_buffer.has
Eric Holk 2016/11/08 23:58:15 Done.
+ base::OS::Unprotect(old_buffer->backing_store(), new_size);
titzer 2016/11/07 19:54:53 Add a comment that we aren't moving the memory her
Eric Holk 2016/11/08 23:58:15 Done.
+ reinterpret_cast<v8::Isolate*>(isolate)
+ ->AdjustAmountOfExternalAllocatedMemory(pages * WasmModule::kPageSize);
+ Handle<Object> new_size_object =
+ isolate->factory()->NewNumberFromSize(new_size);
+ old_buffer->set_byte_length(*new_size_object);
+
+ SetInstanceMemory(instance, *old_buffer);
+ Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
+ RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start,
+ old_size, new_size);
+ buffer = old_buffer;
+ } else {
+ const bool enable_guard_regions = FLAG_wasm_guard_pages;
+ buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions);
+ if (buffer.is_null()) return -1;
+ Address new_mem_start = static_cast<Address>(buffer->backing_store());
+ if (old_size != 0) {
+ memcpy(new_mem_start, old_mem_start, old_size);
+ }
+ SetInstanceMemory(instance, *buffer);
+ Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
+ RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
+ old_size, new_size);
}
- SetInstanceMemory(instance, *buffer);
- Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table();
- RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
- old_size, new_size);
+
Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject),
isolate);
if (!memory_object->IsUndefined(isolate)) {

Powered by Google App Engine
This is Rietveld 408576698