d8: Use PA for ArrayBufferAllocator when malloc is PA

Use PA's configurable pool for the ArrayBufferAllocator when PA is
enabled.

Bug: 392817524

Change-Id: Ie8eb64d978c825ad958ffb29fd9f4ab0f2d962be
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6651069
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Cr-Commit-Position: refs/heads/main@{#100972}
This commit is contained in:
Anton Bikineev authored and V8 LUCI CQ committed 2025-06-23 09:50:31 -07:00
1 parent 9a772b2261
commit fbacbd84e2
6 files changed
+139 -24

No files matched your search

+7 -5
View File
@@ -1472,6 +1472,9 @@ config("features") {
if (v8_enable_leaptiering) {
defines += [ "V8_ENABLE_LEAPTIERING" ]
}
if (v8_enable_partition_alloc) {
defines += [ "V8_ENABLE_PARTITION_ALLOC" ]
}
if (v8_wasm_random_fuzzers) {
defines += [ "V8_WASM_RANDOM_FUZZERS" ]
}
@@ -5034,6 +5037,10 @@ v8_header_set("v8_internal_headers") {
"//third_party/fp16",
]
if (v8_enable_partition_alloc) {
public_deps += [ "//third_party/partition_alloc" ]
}
deps = [
":cppgc_headers",
":generate_bytecode_builtins_list",
@@ -7903,11 +7910,6 @@ v8_executable("d8") {
if (current_os == "zos" && is_component_build) {
deps += [ ":zoslib" ]
}
if (v8_enable_partition_alloc) {
defines += [ "V8_ENABLE_PARTITION_ALLOC" ]
deps += [ "//third_party/partition_alloc" ]
}
}
v8_executable("v8_hello_world") {
+1
View File
@@ -34,6 +34,7 @@ _supported = _supported_compiler && _supported_build_type &&
use_partition_alloc_as_malloc_default = _supported
use_allocator_shim_default = _supported
shim_supports_sized_dealloc_default = false
enable_backup_ref_ptr_support_default = _supported
put_ref_count_in_previous_slot_default = true
enable_backup_ref_ptr_slow_checks_default = false
+1 -1
View File
@@ -330,7 +330,7 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
private:
i::Sandbox* sandbox_ = nullptr;
i::SandboxedArrayBufferAllocator* allocator_ = nullptr;
i::SandboxedArrayBufferAllocatorBase* allocator_ = nullptr;
};
#else
+70 -3
View File
@@ -7,6 +7,7 @@
#include <memory>
#include "src/base/bounded-page-allocator.h"
#include "src/base/once.h"
#include "src/base/platform/memory.h"
#include "src/base/platform/mutex.h"
#include "src/common/ptr-compr-inl.h"
@@ -476,19 +477,85 @@ void* SandboxedArrayBufferAllocator::Allocate(size_t length) {
return mem;
}
void* SandboxedArrayBufferAllocator::AllocateUninitialized(size_t length) {
return Allocate(length);
}
void SandboxedArrayBufferAllocator::Free(void* data) {
base::MutexGuard guard(&mutex_);
region_alloc_->FreeRegion(reinterpret_cast<Address>(data));
}
PageAllocator* SandboxedArrayBufferAllocator::page_allocator() {
return sandbox_->page_allocator();
#if defined(V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR)
void PABackedSandboxedArrayBufferAllocator::LazyInitialize(Sandbox* sandbox) {
base::CallOnce(&partition_init_, [sandbox] {
const size_t max_pool_size = partition_alloc::internal::
PartitionAddressSpace::ConfigurablePoolMaxSize();
const size_t min_pool_size = partition_alloc::internal::
PartitionAddressSpace::ConfigurablePoolMinSize();
size_t pool_size = max_pool_size;
// Try to reserve the maximum size of the pool at first, then keep halving
// the size on failure until it succeeds.
uintptr_t pool_base = 0;
while (!pool_base && pool_size >= min_pool_size) {
pool_base = sandbox->address_space()->AllocatePages(
VirtualAddressSpace::kNoHint, pool_size, pool_size,
v8::PagePermissions::kNoAccess);
if (!pool_base) {
pool_size /= 2;
}
}
// The V8 sandbox is guaranteed to be large enough to host the pool.
CHECK(pool_base);
partition_alloc::internal::PartitionAddressSpace::InitConfigurablePool(
pool_base, pool_size);
});
partition_alloc::PartitionOptions opts;
opts.backup_ref_ptr = partition_alloc::PartitionOptions::kDisabled;
opts.use_configurable_pool = partition_alloc::PartitionOptions::kAllowed;
partition_.emplace(std::move(opts));
}
SandboxedArrayBufferAllocator*
void* PABackedSandboxedArrayBufferAllocator::Allocate(size_t length) {
constexpr partition_alloc::AllocFlags flags =
partition_alloc::AllocFlags::kZeroFill |
partition_alloc::AllocFlags::kReturnNull;
return AllocateInternal<flags>(length);
}
void* PABackedSandboxedArrayBufferAllocator::AllocateUninitialized(
size_t length) {
constexpr partition_alloc::AllocFlags flags =
partition_alloc::AllocFlags::kReturnNull;
return AllocateInternal<flags>(length);
}
template <partition_alloc::AllocFlags flags>
void* PABackedSandboxedArrayBufferAllocator::AllocateInternal(size_t length) {
// The V8 sandbox requires all ArrayBuffer backing stores to be allocated
// inside the sandbox address space. This isn't guaranteed if allocation
// override hooks (which are e.g. used by GWP-ASan) are enabled or if a
// memory tool (e.g. ASan) overrides malloc, so disable both.
constexpr auto new_flags = flags |
partition_alloc::AllocFlags::kNoOverrideHooks |
partition_alloc::AllocFlags::kNoMemoryToolOverride;
return partition_->root()->AllocInline<new_flags>(
length, "PABackedSandboxedArrayBufferAllocator");
}
void PABackedSandboxedArrayBufferAllocator::Free(void* data) {
partition_->root()->Free<partition_alloc::FreeFlags::kNoMemoryToolOverride>(
data);
}
#endif // defined(V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR)
SandboxedArrayBufferAllocatorBase*
IsolateGroup::GetSandboxedArrayBufferAllocator() {
// TODO(342905186): Consider initializing it during IsolateGroup
// initialization instead of doing it lazily.
//
backend_allocator_.LazyInitialize(sandbox());
return &backend_allocator_;
}
+58 -15
View File
@@ -26,7 +26,16 @@
#ifdef V8_ENABLE_SANDBOX
#include "src/base/region-allocator.h"
#endif
#ifdef V8_ENABLE_PARTITION_ALLOC
#include <partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h>
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
#define V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR 1
#endif // PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
#endif // V8_ENABLE_PARTITION_ALLOC
#endif // V8_ENABLE_SANDBOX
namespace v8 {
@@ -43,33 +52,35 @@ class PagePool;
class MemoryChunkMetadata;
class Sandbox;
class SandboxedArrayBufferAllocatorBase {
public:
virtual void* Allocate(size_t length) = 0;
virtual void* AllocateUninitialized(size_t length) = 0;
virtual void Free(void* ptr) = 0;
};
// Backend allocator shared by all ArrayBufferAllocator instances inside one
// sandbox. This way, there is a single region of virtual address space
// reserved inside a sandbox from which all ArrayBufferAllocators allocate
// their memory, instead of each allocator creating their own region, which
// may cause address space exhaustion inside the sandbox.
// TODO(chromium:1340224): replace this with a more efficient allocator.
class SandboxedArrayBufferAllocator {
class SandboxedArrayBufferAllocator final
: public SandboxedArrayBufferAllocatorBase {
public:
SandboxedArrayBufferAllocator() = default;
SandboxedArrayBufferAllocator(const SandboxedArrayBufferAllocator&) = delete;
SandboxedArrayBufferAllocator& operator=(
const SandboxedArrayBufferAllocator&) = delete;
void LazyInitialize(Sandbox* sandbox);
bool is_initialized() const { return !!sandbox_; }
// Returns page allocator that's supposed to be used for allocating pages
// for V8 heap. In case pointer compression is enabled it allocates pages
// within the pointer compression cage.
v8::PageAllocator* page_allocator();
~SandboxedArrayBufferAllocator();
void* Allocate(size_t length);
void LazyInitialize(Sandbox* sandbox);
void Free(void* data);
void* Allocate(size_t length) override;
void* AllocateUninitialized(size_t length) override;
void Free(void* data) override;
private:
// Use a region allocator with a "page size" of 128 bytes as a reasonable
@@ -79,12 +90,40 @@ class SandboxedArrayBufferAllocator {
// The backing memory's accessible region is grown in chunks of this size.
static constexpr size_t kChunkSize = 1 * MB;
bool is_initialized() const { return !!sandbox_; }
std::unique_ptr<base::RegionAllocator> region_alloc_;
size_t end_of_accessible_region_ = 0;
Sandbox* sandbox_ = nullptr;
base::Mutex mutex_;
};
#endif
#if defined(V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR)
class PABackedSandboxedArrayBufferAllocator
: public SandboxedArrayBufferAllocatorBase {
public:
PABackedSandboxedArrayBufferAllocator() = default;
PABackedSandboxedArrayBufferAllocator(
const PABackedSandboxedArrayBufferAllocator&) = delete;
PABackedSandboxedArrayBufferAllocator& operator=(
const PABackedSandboxedArrayBufferAllocator&) = delete;
void LazyInitialize(Sandbox* sandbox);
void* Allocate(size_t length) override;
void* AllocateUninitialized(size_t length) override;
void Free(void* data) override;
private:
template <partition_alloc::AllocFlags flags>
void* AllocateInternal(size_t length);
std::optional<partition_alloc::PartitionAllocator> partition_;
base::OnceType partition_init_ = V8_ONCE_INIT;
};
#endif // !defined(V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR)
#endif // V8_ENABLE_SANDBOX
class CodeRange;
class Isolate;
@@ -226,7 +265,7 @@ class V8_EXPORT_PRIVATE IsolateGroup final {
return metadata_pointer_table_;
}
SandboxedArrayBufferAllocator* GetSandboxedArrayBufferAllocator();
SandboxedArrayBufferAllocatorBase* GetSandboxedArrayBufferAllocator();
#endif // V8_ENABLE_SANDBOX
#ifdef V8_ENABLE_LEAPTIERING
@@ -347,7 +386,11 @@ class V8_EXPORT_PRIVATE IsolateGroup final {
MemoryChunkMetadata*
metadata_pointer_table_[MemoryChunkConstants::kMetadataPointerTableSize] =
{nullptr};
#if defined(V8_USE_PA_BACKED_SANDBOX_FOR_ARRAY_BUFFER_ALLOCATOR)
PABackedSandboxedArrayBufferAllocator backend_allocator_;
#else
SandboxedArrayBufferAllocator backend_allocator_;
#endif
#endif // V8_ENABLE_SANDBOX
#ifdef V8_ENABLE_LEAPTIERING
+2
View File
@@ -26,6 +26,8 @@ const int kSubjectStringLength = arraysize(kOneByteSubjectString) - 1;
static_assert(arraysize(kOneByteSubjectString) ==
arraysize(kTwoByteSubjectString));
namespace base = v8::base;
class OneByteVectorResource : public String::ExternalOneByteStringResource {
public:
explicit OneByteVectorResource(base::Vector<const char> vector)