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:
1 parent
9a772b2261
commit
fbacbd84e2
6 files changed
+139
-24
No files matched your search
@@ -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") {
|
||||
|
||||
@@ -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
@@ -330,7 +330,7 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
|
||||
|
||||
private:
|
||||
i::Sandbox* sandbox_ = nullptr;
|
||||
i::SandboxedArrayBufferAllocator* allocator_ = nullptr;
|
||||
i::SandboxedArrayBufferAllocatorBase* allocator_ = nullptr;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user