Commit 9506dc42 authored by Bartek Nowierski's avatar Bartek Nowierski Committed by Commit Bot

[PartitionAlloc] Finish the PartitionRoot move

Continuation of crrev.com/c/2463047

This requires moving other structures and functions from
partition_alloc.* into their own, new files.

Change-Id: I8ceb9966787ef0b4240790f8a77fa46d35efa455
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2498022
Commit-Queue: Bartek Nowierski <bartekn@chromium.org>
Auto-Submit: Bartek Nowierski <bartekn@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821351}
parent c4914aae
...@@ -1761,6 +1761,7 @@ component("base") { ...@@ -1761,6 +1761,7 @@ component("base") {
"allocator/partition_allocator/page_allocator_internal.h", "allocator/partition_allocator/page_allocator_internal.h",
"allocator/partition_allocator/partition_address_space.cc", "allocator/partition_allocator/partition_address_space.cc",
"allocator/partition_allocator/partition_address_space.h", "allocator/partition_allocator/partition_address_space.h",
"allocator/partition_allocator/partition_alloc-inl.h",
"allocator/partition_allocator/partition_alloc.cc", "allocator/partition_allocator/partition_alloc.cc",
"allocator/partition_allocator/partition_alloc.h", "allocator/partition_allocator/partition_alloc.h",
"allocator/partition_allocator/partition_alloc_check.h", "allocator/partition_allocator/partition_alloc_check.h",
...@@ -1768,6 +1769,8 @@ component("base") { ...@@ -1768,6 +1769,8 @@ component("base") {
"allocator/partition_allocator/partition_alloc_features.cc", "allocator/partition_allocator/partition_alloc_features.cc",
"allocator/partition_allocator/partition_alloc_features.h", "allocator/partition_allocator/partition_alloc_features.h",
"allocator/partition_allocator/partition_alloc_forward.h", "allocator/partition_allocator/partition_alloc_forward.h",
"allocator/partition_allocator/partition_alloc_hooks.cc",
"allocator/partition_allocator/partition_alloc_hooks.h",
"allocator/partition_allocator/partition_bucket.cc", "allocator/partition_allocator/partition_bucket.cc",
"allocator/partition_allocator/partition_bucket.h", "allocator/partition_allocator/partition_bucket.h",
"allocator/partition_allocator/partition_cookie.h", "allocator/partition_allocator/partition_cookie.h",
...@@ -1781,6 +1784,7 @@ component("base") { ...@@ -1781,6 +1784,7 @@ component("base") {
"allocator/partition_allocator/partition_page.h", "allocator/partition_allocator/partition_page.h",
"allocator/partition_allocator/partition_ref_count.cc", "allocator/partition_allocator/partition_ref_count.cc",
"allocator/partition_allocator/partition_ref_count.h", "allocator/partition_allocator/partition_ref_count.h",
"allocator/partition_allocator/partition_root.cc",
"allocator/partition_allocator/partition_root.h", "allocator/partition_allocator/partition_root.h",
"allocator/partition_allocator/partition_stats.cc", "allocator/partition_allocator/partition_stats.cc",
"allocator/partition_allocator/partition_stats.h", "allocator/partition_allocator/partition_stats.h",
......
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_
#include <cstring>
#include "base/allocator/partition_allocator/partition_cookie.h"
#include "base/allocator/partition_allocator/partition_ref_count.h"
#include "base/allocator/partition_allocator/partition_tag.h"
#include "base/allocator/partition_allocator/random.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace base {
namespace internal {
ALWAYS_INLINE void* PartitionPointerAdjustSubtract(bool allow_extras,
void* ptr) {
if (allow_extras) {
ptr = PartitionTagPointerAdjustSubtract(ptr);
ptr = PartitionCookiePointerAdjustSubtract(ptr);
ptr = PartitionRefCountPointerAdjustSubtract(ptr);
}
return ptr;
}
ALWAYS_INLINE void* PartitionPointerAdjustAdd(bool allow_extras, void* ptr) {
if (allow_extras) {
ptr = PartitionTagPointerAdjustAdd(ptr);
ptr = PartitionCookiePointerAdjustAdd(ptr);
ptr = PartitionRefCountPointerAdjustAdd(ptr);
}
return ptr;
}
ALWAYS_INLINE size_t PartitionSizeAdjustAdd(bool allow_extras, size_t size) {
if (allow_extras) {
size = PartitionTagSizeAdjustAdd(size);
size = PartitionCookieSizeAdjustAdd(size);
size = PartitionRefCountSizeAdjustAdd(size);
}
return size;
}
ALWAYS_INLINE size_t PartitionSizeAdjustSubtract(bool allow_extras,
size_t size) {
if (allow_extras) {
size = PartitionTagSizeAdjustSubtract(size);
size = PartitionCookieSizeAdjustSubtract(size);
size = PartitionRefCountSizeAdjustSubtract(size);
}
return size;
}
// This is a `memset` that resists being optimized away. Adapted from
// boringssl/src/crypto/mem.c. (Copying and pasting is bad, but //base can't
// depend on //third_party, and this is small enough.)
ALWAYS_INLINE void SecureZero(void* p, size_t size) {
#if defined(OS_WIN)
SecureZeroMemory(p, size);
#else
memset(p, 0, size);
// As best as we can tell, this is sufficient to break any optimisations that
// might try to eliminate "superfluous" memsets. If there's an easy way to
// detect memset_s, it would be better to use that.
__asm__ __volatile__("" : : "r"(p) : "memory");
#endif
}
// Returns true if we've hit the end of a random-length period. We don't want to
// invoke `RandomValue` too often, because we call this function in a hot spot
// (`Free`), and `RandomValue` incurs the cost of atomics.
#if !DCHECK_IS_ON()
ALWAYS_INLINE bool RandomPeriod() {
static thread_local uint8_t counter = 0;
if (UNLIKELY(counter == 0)) {
// It's OK to truncate this value.
counter = static_cast<uint8_t>(base::RandomValue());
}
// If `counter` is 0, this will wrap. That is intentional and OK.
counter--;
return counter == 0;
}
#endif
} // namespace internal
} // namespace base
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_INL_H_
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/allocator/partition_allocator/partition_alloc_hooks.h"
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
namespace base {
Lock& GetHooksLock() {
static NoDestructor<Lock> lock;
return *lock;
}
std::atomic<bool> PartitionAllocHooks::hooks_enabled_(false);
std::atomic<PartitionAllocHooks::AllocationObserverHook*>
PartitionAllocHooks::allocation_observer_hook_(nullptr);
std::atomic<PartitionAllocHooks::FreeObserverHook*>
PartitionAllocHooks::free_observer_hook_(nullptr);
std::atomic<PartitionAllocHooks::AllocationOverrideHook*>
PartitionAllocHooks::allocation_override_hook_(nullptr);
std::atomic<PartitionAllocHooks::FreeOverrideHook*>
PartitionAllocHooks::free_override_hook_(nullptr);
std::atomic<PartitionAllocHooks::ReallocOverrideHook*>
PartitionAllocHooks::realloc_override_hook_(nullptr);
void PartitionAllocHooks::SetObserverHooks(AllocationObserverHook* alloc_hook,
FreeObserverHook* free_hook) {
AutoLock guard(GetHooksLock());
// Chained hooks are not supported. Registering a non-null hook when a
// non-null hook is already registered indicates somebody is trying to
// overwrite a hook.
PA_CHECK((!allocation_observer_hook_ && !free_observer_hook_) ||
(!alloc_hook && !free_hook))
<< "Overwriting already set observer hooks";
allocation_observer_hook_ = alloc_hook;
free_observer_hook_ = free_hook;
hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
}
void PartitionAllocHooks::SetOverrideHooks(AllocationOverrideHook* alloc_hook,
FreeOverrideHook* free_hook,
ReallocOverrideHook realloc_hook) {
AutoLock guard(GetHooksLock());
PA_CHECK((!allocation_override_hook_ && !free_override_hook_ &&
!realloc_override_hook_) ||
(!alloc_hook && !free_hook && !realloc_hook))
<< "Overwriting already set override hooks";
allocation_override_hook_ = alloc_hook;
free_override_hook_ = free_hook;
realloc_override_hook_ = realloc_hook;
hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
}
void PartitionAllocHooks::AllocationObserverHookIfEnabled(
void* address,
size_t size,
const char* type_name) {
if (auto* hook = allocation_observer_hook_.load(std::memory_order_relaxed))
hook(address, size, type_name);
}
bool PartitionAllocHooks::AllocationOverrideHookIfEnabled(
void** out,
int flags,
size_t size,
const char* type_name) {
if (auto* hook = allocation_override_hook_.load(std::memory_order_relaxed))
return hook(out, flags, size, type_name);
return false;
}
void PartitionAllocHooks::FreeObserverHookIfEnabled(void* address) {
if (auto* hook = free_observer_hook_.load(std::memory_order_relaxed))
hook(address);
}
bool PartitionAllocHooks::FreeOverrideHookIfEnabled(void* address) {
if (auto* hook = free_override_hook_.load(std::memory_order_relaxed))
return hook(address);
return false;
}
void PartitionAllocHooks::ReallocObserverHookIfEnabled(void* old_address,
void* new_address,
size_t size,
const char* type_name) {
// Report a reallocation as a free followed by an allocation.
AllocationObserverHook* allocation_hook =
allocation_observer_hook_.load(std::memory_order_relaxed);
FreeObserverHook* free_hook =
free_observer_hook_.load(std::memory_order_relaxed);
if (allocation_hook && free_hook) {
free_hook(old_address);
allocation_hook(new_address, size, type_name);
}
}
bool PartitionAllocHooks::ReallocOverrideHookIfEnabled(size_t* out,
void* address) {
if (ReallocOverrideHook* hook =
realloc_override_hook_.load(std::memory_order_relaxed)) {
return hook(out, address);
}
return false;
}
} // namespace base
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_HOOKS_H_
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_HOOKS_H_
#include <atomic>
#include <cstddef>
#include "base/allocator/partition_allocator/partition_alloc_check.h"
#include "base/base_export.h"
namespace base {
// PartitionAlloc supports setting hooks to observe allocations/frees as they
// occur as well as 'override' hooks that allow overriding those operations.
class BASE_EXPORT PartitionAllocHooks {
public:
// Log allocation and free events.
typedef void AllocationObserverHook(void* address,
size_t size,
const char* type_name);
typedef void FreeObserverHook(void* address);
// If it returns true, the allocation has been overridden with the pointer in
// *out.
typedef bool AllocationOverrideHook(void** out,
int flags,
size_t size,
const char* type_name);
// If it returns true, then the allocation was overridden and has been freed.
typedef bool FreeOverrideHook(void* address);
// If it returns true, the underlying allocation is overridden and *out holds
// the size of the underlying allocation.
typedef bool ReallocOverrideHook(size_t* out, void* address);
// To unhook, call Set*Hooks with nullptrs.
static void SetObserverHooks(AllocationObserverHook* alloc_hook,
FreeObserverHook* free_hook);
static void SetOverrideHooks(AllocationOverrideHook* alloc_hook,
FreeOverrideHook* free_hook,
ReallocOverrideHook realloc_hook);
// Helper method to check whether hooks are enabled. This is an optimization
// so that if a function needs to call observer and override hooks in two
// different places this value can be cached and only loaded once.
static bool AreHooksEnabled() {
return hooks_enabled_.load(std::memory_order_relaxed);
}
static void AllocationObserverHookIfEnabled(void* address,
size_t size,
const char* type_name);
static bool AllocationOverrideHookIfEnabled(void** out,
int flags,
size_t size,
const char* type_name);
static void FreeObserverHookIfEnabled(void* address);
static bool FreeOverrideHookIfEnabled(void* address);
static void ReallocObserverHookIfEnabled(void* old_address,
void* new_address,
size_t size,
const char* type_name);
static bool ReallocOverrideHookIfEnabled(size_t* out, void* address);
private:
// Single bool that is used to indicate whether observer or allocation hooks
// are set to reduce the numbers of loads required to check whether hooking is
// enabled.
static std::atomic<bool> hooks_enabled_;
// Lock used to synchronize Set*Hooks calls.
static std::atomic<AllocationObserverHook*> allocation_observer_hook_;
static std::atomic<FreeObserverHook*> free_observer_hook_;
static std::atomic<AllocationOverrideHook*> allocation_override_hook_;
static std::atomic<FreeOverrideHook*> free_override_hook_;
static std::atomic<ReallocOverrideHook*> realloc_override_hook_;
};
} // namespace base
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_HOOKS_H_
...@@ -15,8 +15,14 @@ ...@@ -15,8 +15,14 @@
#include "build/build_config.h" #include "build/build_config.h"
namespace base { namespace base {
typedef void (*OomFunction)(size_t);
namespace internal { namespace internal {
// g_oom_handling_function is invoked when PartitionAlloc hits OutOfMemory.
static OomFunction g_oom_handling_function = nullptr;
BASE_EXPORT NOINLINE void PartitionExcessiveAllocationSize(size_t size); BASE_EXPORT NOINLINE void PartitionExcessiveAllocationSize(size_t size);
#if !defined(ARCH_CPU_64_BITS) #if !defined(ARCH_CPU_64_BITS)
...@@ -24,6 +30,7 @@ NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size); ...@@ -24,6 +30,7 @@ NOINLINE void PartitionOutOfMemoryWithLotsOfUncommitedPages(size_t size);
#endif #endif
} // namespace internal } // namespace internal
} // namespace base } // namespace base
#endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_ #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_OOM_H_
This diff is collapsed.
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