Commit e89d0061 authored by Samuel Groß's avatar Samuel Groß Committed by V8 LUCI CQ

[sandbox] Fail with OOM when external pointer table can't be grown

Bug: chromium:1355990
Change-Id: I1a822ce7b476baf5866070b11b65c464800d3b7b
Cq-Include-Trybots: luci.v8.try:v8_linux64_heap_sandbox_dbg_ng,v8_linux_arm64_sim_heap_sandbox_dbg_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3859849
Commit-Queue: Samuel Groß <saelo@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82779}
parent 972b01f9
...@@ -5932,7 +5932,7 @@ ExternalPointerHandle Isolate::GetOrCreateWaiterQueueNodeExternalPointer() { ...@@ -5932,7 +5932,7 @@ ExternalPointerHandle Isolate::GetOrCreateWaiterQueueNodeExternalPointer() {
handle = waiter_queue_node_external_pointer_handle_; handle = waiter_queue_node_external_pointer_handle_;
} else { } else {
handle = shared_external_pointer_table().AllocateAndInitializeEntry( handle = shared_external_pointer_table().AllocateAndInitializeEntry(
kNullAddress, kWaiterQueueNodeTag); this, kNullAddress, kWaiterQueueNodeTag);
waiter_queue_node_external_pointer_handle_ = handle; waiter_queue_node_external_pointer_handle_ = handle;
} }
DCHECK_NE(0, handle); DCHECK_NE(0, handle);
......
...@@ -159,7 +159,8 @@ void ExternalPointerSlot::init(Isolate* isolate, Address value, ...@@ -159,7 +159,8 @@ void ExternalPointerSlot::init(Isolate* isolate, Address value,
#ifdef V8_ENABLE_SANDBOX #ifdef V8_ENABLE_SANDBOX
if (IsSandboxedExternalPointerType(tag)) { if (IsSandboxedExternalPointerType(tag)) {
ExternalPointerTable& table = GetExternalPointerTableForTag(isolate, tag); ExternalPointerTable& table = GetExternalPointerTableForTag(isolate, tag);
ExternalPointerHandle handle = table.AllocateAndInitializeEntry(value, tag); ExternalPointerHandle handle =
table.AllocateAndInitializeEntry(isolate, value, tag);
// Use a Release_Store to ensure that the store of the pointer into the // Use a Release_Store to ensure that the store of the pointer into the
// table is not reordered after the store of the handle. Otherwise, other // table is not reordered after the store of the handle. Otherwise, other
// threads may access an uninitialized table entry and crash. // threads may access an uninitialized table entry and crash.
......
...@@ -36,7 +36,8 @@ V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate, ...@@ -36,7 +36,8 @@ V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate,
#ifdef V8_ENABLE_SANDBOX #ifdef V8_ENABLE_SANDBOX
if (IsSandboxedExternalPointerType(tag)) { if (IsSandboxedExternalPointerType(tag)) {
ExternalPointerTable& table = GetExternalPointerTable<tag>(isolate); ExternalPointerTable& table = GetExternalPointerTable<tag>(isolate);
ExternalPointerHandle handle = table.AllocateAndInitializeEntry(value, tag); ExternalPointerHandle handle =
table.AllocateAndInitializeEntry(isolate, value, tag);
// Use a Release_Store to ensure that the store of the pointer into the // Use a Release_Store to ensure that the store of the pointer into the
// table is not reordered after the store of the handle. Otherwise, other // table is not reordered after the store of the handle. Otherwise, other
// threads may access an uninitialized table entry and crash. // threads may access an uninitialized table entry and crash.
...@@ -93,7 +94,7 @@ V8_INLINE void WriteLazilyInitializedExternalPointerField(Address field_address, ...@@ -93,7 +94,7 @@ V8_INLINE void WriteLazilyInitializedExternalPointerField(Address field_address,
if (handle == kNullExternalPointerHandle) { if (handle == kNullExternalPointerHandle) {
// Field has not been initialized yet. // Field has not been initialized yet.
ExternalPointerHandle handle = ExternalPointerHandle handle =
table.AllocateAndInitializeEntry(value, tag); table.AllocateAndInitializeEntry(isolate, value, tag);
base::AsAtomic32::Release_Store(location, handle); base::AsAtomic32::Release_Store(location, handle);
} else { } else {
table.Set(handle, value, tag); table.Set(handle, value, tag);
......
...@@ -47,7 +47,7 @@ Address ExternalPointerTable::Exchange(ExternalPointerHandle handle, ...@@ -47,7 +47,7 @@ Address ExternalPointerTable::Exchange(ExternalPointerHandle handle,
} }
ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry( ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry(
Address initial_value, ExternalPointerTag tag) { Isolate* isolate, Address initial_value, ExternalPointerTag tag) {
DCHECK(is_initialized()); DCHECK(is_initialized());
uint32_t index; uint32_t index;
...@@ -69,7 +69,7 @@ ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry( ...@@ -69,7 +69,7 @@ ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry(
if (!freelist_head) { if (!freelist_head) {
// Freelist is (still) empty so grow the table. // Freelist is (still) empty so grow the table.
freelist_head = Grow(); freelist_head = Grow(isolate);
} }
} }
......
...@@ -61,7 +61,7 @@ void ExternalPointerTable::Init(Isolate* isolate) { ...@@ -61,7 +61,7 @@ void ExternalPointerTable::Init(Isolate* isolate) {
// Allocate the initial block. Mutex must be held for that. // Allocate the initial block. Mutex must be held for that.
base::MutexGuard guard(mutex_); base::MutexGuard guard(mutex_);
Grow(); Grow(isolate);
// Set up the special null entry. This entry must contain nullptr so that // Set up the special null entry. This entry must contain nullptr so that
// empty EmbedderDataSlots represent nullptr. // empty EmbedderDataSlots represent nullptr.
...@@ -281,23 +281,28 @@ void ExternalPointerTable::StopCompacting() { ...@@ -281,23 +281,28 @@ void ExternalPointerTable::StopCompacting() {
set_start_of_evacuation_area(kNotCompactingMarker); set_start_of_evacuation_area(kNotCompactingMarker);
} }
uint32_t ExternalPointerTable::Grow() { uint32_t ExternalPointerTable::Grow(Isolate* isolate) {
// Freelist should be empty. // Freelist should be empty.
DCHECK_EQ(0, freelist_head_); DCHECK_EQ(0, freelist_head_);
// Mutex must be held when calling this method. // Mutex must be held when calling this method.
mutex_->AssertHeld(); mutex_->AssertHeld();
// Grow the table by one block. // Grow the table by one block.
VirtualAddressSpace* root_space = GetPlatformVirtualAddressSpace();
DCHECK(IsAligned(kBlockSize, root_space->page_size()));
uint32_t old_capacity = capacity(); uint32_t old_capacity = capacity();
uint32_t new_capacity = old_capacity + kEntriesPerBlock; uint32_t new_capacity = old_capacity + kEntriesPerBlock;
CHECK_LE(new_capacity, kMaxExternalPointers); if (new_capacity > kMaxExternalPointers) {
V8::FatalProcessOutOfMemory(
isolate, "Cannot grow ExternalPointerTable past its maximum capacity");
}
if (!root_space->SetPagePermissions(buffer_ + old_capacity * sizeof(Address),
kBlockSize,
PagePermissions::kReadWrite)) {
V8::FatalProcessOutOfMemory(
isolate, "Failed to grow the ExternalPointerTable backing buffer");
}
// Failure likely means OOM. TODO(saelo) handle this.
VirtualAddressSpace* root_space = GetPlatformVirtualAddressSpace();
DCHECK(IsAligned(kBlockSize, root_space->page_size()));
CHECK(root_space->SetPagePermissions(buffer_ + old_capacity * sizeof(Address),
kBlockSize,
PagePermissions::kReadWrite));
set_capacity(new_capacity); set_capacity(new_capacity);
// Build freelist bottom to top, which might be more cache friendly. // Build freelist bottom to top, which might be more cache friendly.
......
...@@ -107,7 +107,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable { ...@@ -107,7 +107,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable {
// //
// This method is atomic and can be called from background threads. // This method is atomic and can be called from background threads.
inline ExternalPointerHandle AllocateAndInitializeEntry( inline ExternalPointerHandle AllocateAndInitializeEntry(
Address initial_value, ExternalPointerTag tag); Isolate* isolate, Address initial_value, ExternalPointerTag tag);
// Determines the number of entries currently on the freelist. // Determines the number of entries currently on the freelist.
// The freelist entries encode the freelist size and the next entry on the // The freelist entries encode the freelist size and the next entry on the
...@@ -287,7 +287,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable { ...@@ -287,7 +287,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable {
// If the table cannot be grown, either because it is already at its maximum // If the table cannot be grown, either because it is already at its maximum
// size or because the memory for it could not be allocated, this method will // size or because the memory for it could not be allocated, this method will
// fail with an OOM crash. // fail with an OOM crash.
uint32_t Grow(); uint32_t Grow(Isolate* isolate);
// Stop compacting at the end of sweeping. // Stop compacting at the end of sweeping.
void StopCompacting(); void StopCompacting();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment