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() {
handle = waiter_queue_node_external_pointer_handle_;
} else {
handle = shared_external_pointer_table().AllocateAndInitializeEntry(
kNullAddress, kWaiterQueueNodeTag);
this, kNullAddress, kWaiterQueueNodeTag);
waiter_queue_node_external_pointer_handle_ = handle;
}
DCHECK_NE(0, handle);
......
......@@ -159,7 +159,8 @@ void ExternalPointerSlot::init(Isolate* isolate, Address value,
#ifdef V8_ENABLE_SANDBOX
if (IsSandboxedExternalPointerType(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
// table is not reordered after the store of the handle. Otherwise, other
// threads may access an uninitialized table entry and crash.
......
......@@ -36,7 +36,8 @@ V8_INLINE void InitExternalPointerField(Address field_address, Isolate* isolate,
#ifdef V8_ENABLE_SANDBOX
if (IsSandboxedExternalPointerType(tag)) {
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
// table is not reordered after the store of the handle. Otherwise, other
// threads may access an uninitialized table entry and crash.
......@@ -93,7 +94,7 @@ V8_INLINE void WriteLazilyInitializedExternalPointerField(Address field_address,
if (handle == kNullExternalPointerHandle) {
// Field has not been initialized yet.
ExternalPointerHandle handle =
table.AllocateAndInitializeEntry(value, tag);
table.AllocateAndInitializeEntry(isolate, value, tag);
base::AsAtomic32::Release_Store(location, handle);
} else {
table.Set(handle, value, tag);
......
......@@ -47,7 +47,7 @@ Address ExternalPointerTable::Exchange(ExternalPointerHandle handle,
}
ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry(
Address initial_value, ExternalPointerTag tag) {
Isolate* isolate, Address initial_value, ExternalPointerTag tag) {
DCHECK(is_initialized());
uint32_t index;
......@@ -69,7 +69,7 @@ ExternalPointerHandle ExternalPointerTable::AllocateAndInitializeEntry(
if (!freelist_head) {
// Freelist is (still) empty so grow the table.
freelist_head = Grow();
freelist_head = Grow(isolate);
}
}
......
......@@ -61,7 +61,7 @@ void ExternalPointerTable::Init(Isolate* isolate) {
// Allocate the initial block. Mutex must be held for that.
base::MutexGuard guard(mutex_);
Grow();
Grow(isolate);
// Set up the special null entry. This entry must contain nullptr so that
// empty EmbedderDataSlots represent nullptr.
......@@ -281,23 +281,28 @@ void ExternalPointerTable::StopCompacting() {
set_start_of_evacuation_area(kNotCompactingMarker);
}
uint32_t ExternalPointerTable::Grow() {
uint32_t ExternalPointerTable::Grow(Isolate* isolate) {
// Freelist should be empty.
DCHECK_EQ(0, freelist_head_);
// Mutex must be held when calling this method.
mutex_->AssertHeld();
// Grow the table by one block.
VirtualAddressSpace* root_space = GetPlatformVirtualAddressSpace();
DCHECK(IsAligned(kBlockSize, root_space->page_size()));
uint32_t old_capacity = capacity();
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);
// Build freelist bottom to top, which might be more cache friendly.
......
......@@ -107,7 +107,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable {
//
// This method is atomic and can be called from background threads.
inline ExternalPointerHandle AllocateAndInitializeEntry(
Address initial_value, ExternalPointerTag tag);
Isolate* isolate, Address initial_value, ExternalPointerTag tag);
// Determines the number of entries currently on the freelist.
// The freelist entries encode the freelist size and the next entry on the
......@@ -287,7 +287,7 @@ class V8_EXPORT_PRIVATE ExternalPointerTable {
// 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
// fail with an OOM crash.
uint32_t Grow();
uint32_t Grow(Isolate* isolate);
// Stop compacting at the end of sweeping.
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