Commit 04c06683 authored by Benoit Lize's avatar Benoit Lize Committed by Commit Bot

[PartitionAlloc] Add tests to PartitionAlloc's allocator shim.

Bug: 998048, 1141752
Change-Id: I3b351981e4b51740a51b9756f214bb0f02eb6ce4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2505830Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Commit-Queue: Benoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824042}
parent 58c40a11
......@@ -1295,6 +1295,8 @@ component("base") {
sources += [
"allocator/allocator_shim.cc",
"allocator/allocator_shim.h",
"allocator/allocator_shim_default_dispatch_to_partition_alloc.cc",
"allocator/allocator_shim_default_dispatch_to_partition_alloc.h",
"allocator/allocator_shim_internals.h",
]
if (is_android) {
......@@ -1322,12 +1324,7 @@ component("base") {
]
}
if (use_allocator == "partition") {
sources += [
"allocator/allocator_shim_default_dispatch_to_partition_alloc.cc",
"allocator/allocator_shim_default_dispatch_to_partition_alloc.h",
]
} else if (use_allocator == "tcmalloc") {
if (use_allocator == "tcmalloc") {
sources += [ "allocator/allocator_shim_default_dispatch_to_tcmalloc.cc" ]
deps += [ "//base/allocator:tcmalloc" ]
} else if (use_allocator == "none") {
......@@ -3411,9 +3408,7 @@ test("base_unittests") {
sources += [ "allocator/winheap_stubs_win_unittest.cc" ]
}
if (use_allocator == "partition") {
sources += [ "allocator/allocator_shim_default_dispatch_to_partition_alloc_unittest.cc" ]
}
sources += [ "allocator/allocator_shim_default_dispatch_to_partition_alloc_unittest.cc" ]
}
if (enable_base_tracing) {
......
......@@ -4,7 +4,6 @@
#include "base/allocator/allocator_shim_default_dispatch_to_partition_alloc.h"
#include "base/allocator/allocator_shim.h"
#include "base/allocator/allocator_shim_internals.h"
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/allocator/partition_allocator/partition_alloc_constants.h"
......@@ -14,10 +13,12 @@
#include "base/no_destructor.h"
#include "build/build_config.h"
#if defined(OS_POSIX) && !defined(OS_APPLE)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include <malloc.h>
#endif
using base::allocator::AllocatorDispatch;
namespace {
// We would usually make g_root a static local variable, as these are guaranteed
......@@ -85,10 +86,17 @@ base::ThreadSafePartitionRoot* Allocator() {
return root;
}
auto* new_root = new (g_allocator_buffer) base::ThreadSafePartitionRoot(
{base::PartitionOptions::Alignment::kRegular,
base::PartitionOptions::ThreadCache::kEnabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
auto* new_root = new (g_allocator_buffer) base::ThreadSafePartitionRoot({
base::PartitionOptions::Alignment::kRegular,
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
base::PartitionOptions::ThreadCache::kEnabled,
#else
// Other tests, such as the ThreadCache tests create a thread cache, and
// only one is supported at a time.
base::PartitionOptions::ThreadCache::kDisabled,
#endif
base::PartitionOptions::PCScan::kDisabledByDefault
});
g_root_.store(new_root, std::memory_order_release);
// Semantically equivalent to base::Lock::Release().
......@@ -96,7 +104,20 @@ base::ThreadSafePartitionRoot* Allocator() {
return new_root;
}
using base::allocator::AllocatorDispatch;
base::ThreadSafePartitionRoot* AlignedAllocator() {
// Since the general-purpose allocator uses the thread cache, this one cannot.
static base::NoDestructor<base::ThreadSafePartitionRoot> aligned_allocator(
base::PartitionOptions{
base::PartitionOptions::Alignment::kAlignedAlloc,
base::PartitionOptions::ThreadCache::kDisabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
return aligned_allocator.get();
}
} // namespace
namespace base {
namespace internal {
void* PartitionMalloc(const AllocatorDispatch*, size_t size, void* context) {
return Allocator()->AllocFlagsNoHooks(0, size);
......@@ -115,16 +136,6 @@ void* PartitionCalloc(const AllocatorDispatch*,
return Allocator()->AllocFlagsNoHooks(base::PartitionAllocZeroFill, n * size);
}
base::ThreadSafePartitionRoot* AlignedAllocator() {
// Since the general-purpose allocator uses the thread cache, this one cannot.
static base::NoDestructor<base::ThreadSafePartitionRoot> aligned_allocator(
base::PartitionOptions{
base::PartitionOptions::Alignment::kAlignedAlloc,
base::PartitionOptions::ThreadCache::kDisabled,
base::PartitionOptions::PCScan::kDisabledByDefault});
return aligned_allocator.get();
}
void* PartitionMemalign(const AllocatorDispatch*,
size_t alignment,
size_t size,
......@@ -196,11 +207,6 @@ size_t PartitionGetSizeEstimate(const AllocatorDispatch*,
return base::ThreadSafePartitionRoot::GetUsableSize(address);
}
} // namespace
namespace base {
namespace internal {
// static
ThreadSafePartitionRoot* PartitionAllocMalloc::Allocator() {
return ::Allocator();
......@@ -214,36 +220,36 @@ ThreadSafePartitionRoot* PartitionAllocMalloc::AlignedAllocator() {
} // namespace internal
} // namespace base
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
namespace base {
namespace allocator {
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
void EnablePCScanIfNeeded() {
if (!features::IsPartitionAllocPCScanEnabled())
return;
Allocator()->EnablePCScan();
AlignedAllocator()->EnablePCScan();
}
#endif
} // namespace allocator
} // namespace base
constexpr AllocatorDispatch AllocatorDispatch::default_dispatch = {
&PartitionMalloc, /* alloc_function */
&PartitionMallocUnchecked, /* alloc_unchecked_function */
&PartitionCalloc, /* alloc_zero_initialized_function */
&PartitionMemalign, /* alloc_aligned_function */
&PartitionRealloc, /* realloc_function */
&PartitionFree, /* free_function */
&PartitionGetSizeEstimate, /* get_size_estimate_function */
nullptr, /* batch_malloc_function */
nullptr, /* batch_free_function */
nullptr, /* free_definite_size_function */
&PartitionAlignedAlloc, /* aligned_malloc_function */
&PartitionAlignedRealloc, /* aligned_realloc_function */
&PartitionFree, /* aligned_free_function */
nullptr, /* next */
&base::internal::PartitionMalloc, // alloc_function
&base::internal::PartitionMallocUnchecked, // alloc_unchecked_function
&base::internal::PartitionCalloc, // alloc_zero_initialized_function
&base::internal::PartitionMemalign, // alloc_aligned_function
&base::internal::PartitionRealloc, // realloc_function
&base::internal::PartitionFree, // free_function
&base::internal::PartitionGetSizeEstimate, // get_size_estimate_function
nullptr, // batch_malloc_function
nullptr, // batch_free_function
nullptr, // free_definite_size_function
&base::internal::PartitionAlignedAlloc, // aligned_malloc_function
&base::internal::PartitionAlignedRealloc, // aligned_realloc_function
&base::internal::PartitionFree, // aligned_free_function
nullptr, // next
};
// Intercept diagnostics symbols as well, even though they are not part of the
......@@ -263,8 +269,7 @@ SHIM_ALWAYS_EXPORT int mallopt(int cmd, int value) __THROW {
#endif // !defined(OS_APPLE)
// mallinfo is not a POSIX API and OS_APPLE doesn't support it.
#if defined(OS_POSIX) && !defined(OS_APPLE)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
SHIM_ALWAYS_EXPORT struct mallinfo mallinfo(void) __THROW {
base::SimplePartitionStatsDumper allocator_dumper;
Allocator()->DumpStats("malloc", true, &allocator_dumper);
......@@ -288,6 +293,8 @@ SHIM_ALWAYS_EXPORT struct mallinfo mallinfo(void) __THROW {
return info;
}
#endif // defined(OS_POSIX) && !defined(OS_APPLE)
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
} // extern "C"
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
......@@ -5,17 +5,65 @@
#ifndef BASE_ALLOCATOR_ALLOCATOR_SHIM_DEFAULT_DISPATCH_TO_PARTITION_ALLOC_H_
#define BASE_ALLOCATOR_ALLOCATOR_SHIM_DEFAULT_DISPATCH_TO_PARTITION_ALLOC_H_
#include "base/allocator/allocator_shim.h"
#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/base_export.h"
namespace base {
namespace internal {
class PartitionAllocMalloc {
class BASE_EXPORT PartitionAllocMalloc {
public:
static ThreadSafePartitionRoot* Allocator();
static ThreadSafePartitionRoot* AlignedAllocator();
};
BASE_EXPORT void* PartitionMalloc(const base::allocator::AllocatorDispatch*,
size_t size,
void* context);
BASE_EXPORT void* PartitionMallocUnchecked(
const base::allocator::AllocatorDispatch*,
size_t size,
void* context);
BASE_EXPORT void* PartitionCalloc(const base::allocator::AllocatorDispatch*,
size_t n,
size_t size,
void* context);
BASE_EXPORT void* PartitionMemalign(const base::allocator::AllocatorDispatch*,
size_t alignment,
size_t size,
void* context);
BASE_EXPORT void* PartitionAlignedAlloc(
const base::allocator::AllocatorDispatch* dispatch,
size_t size,
size_t alignment,
void* context);
BASE_EXPORT void* PartitionAlignedRealloc(
const base::allocator::AllocatorDispatch* dispatch,
void* address,
size_t size,
size_t alignment,
void* context);
BASE_EXPORT void* PartitionRealloc(const base::allocator::AllocatorDispatch*,
void* address,
size_t size,
void* context);
BASE_EXPORT void PartitionFree(const base::allocator::AllocatorDispatch*,
void* address,
void* context);
BASE_EXPORT size_t
PartitionGetSizeEstimate(const base::allocator::AllocatorDispatch*,
void* address,
void* context);
} // namespace internal
} // namespace base
......
......@@ -2,18 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/allocator/allocator_shim_default_dispatch_to_partition_alloc.h"
#include <cstdlib>
#include <cstring>
#include "base/allocator/buildflags.h"
#include "base/compiler_specific.h"
#include "base/partition_alloc_buildflags.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_POSIX) && !defined(OS_APPLE)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include <malloc.h>
#include <stdlib.h>
#endif
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
!defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) && BUILDFLAG(USE_PARTITION_ALLOC)
namespace base {
namespace internal {
#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// Platforms on which we override weak libc symbols.
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
......@@ -64,5 +72,91 @@ TEST(PartitionAllocAsMalloc, Mallinfo) {
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
// !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
// Note: the tests below are quite simple, they are used as simple smoke tests
// for PartitionAlloc-Everywhere. Most of these directly dispatch to
// PartitionAlloc, which has much more extensive tests.
TEST(PartitionAllocAsMalloc, Simple) {
void* data = PartitionMalloc(nullptr, 10, nullptr);
EXPECT_TRUE(data);
PartitionFree(nullptr, data, nullptr);
}
TEST(PartitionAllocAsMalloc, MallocUnchecked) {
void* data = PartitionMallocUnchecked(nullptr, 10, nullptr);
EXPECT_TRUE(data);
PartitionFree(nullptr, data, nullptr);
void* too_large = PartitionMallocUnchecked(nullptr, 4e9, nullptr);
EXPECT_FALSE(too_large); // No crash.
}
TEST(PartitionAllocAsMalloc, Calloc) {
constexpr size_t alloc_size = 100;
void* data = PartitionCalloc(nullptr, 1, alloc_size, nullptr);
EXPECT_TRUE(data);
char* zeroes[alloc_size];
memset(zeroes, 0, alloc_size);
EXPECT_EQ(0, memcmp(zeroes, data, alloc_size));
PartitionFree(nullptr, data, nullptr);
}
TEST(PartitionAllocAsMalloc, Memalign) {
constexpr size_t alloc_size = 100;
constexpr size_t alignment = 1024;
void* data = PartitionMemalign(nullptr, alignment, alloc_size, nullptr);
EXPECT_TRUE(data);
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(data) % alignment);
PartitionFree(nullptr, data, nullptr);
}
TEST(PartitionAllocAsMalloc, AlignedAlloc) {
constexpr size_t alloc_size = 100;
constexpr size_t alignment = 1024;
void* data = PartitionAlignedAlloc(nullptr, alloc_size, alignment, nullptr);
EXPECT_TRUE(data);
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(data) % alignment);
PartitionFree(nullptr, data, nullptr);
}
TEST(PartitionAllocAsMalloc, AlignedRealloc) {
constexpr size_t alloc_size = 100;
constexpr size_t alignment = 1024;
void* data = PartitionAlignedAlloc(nullptr, alloc_size, alignment, nullptr);
EXPECT_TRUE(data);
void* data2 = PartitionAlignedRealloc(nullptr, data, alloc_size + 1,
alignment, nullptr);
EXPECT_TRUE(data2);
EXPECT_NE(reinterpret_cast<uintptr_t>(data),
reinterpret_cast<uintptr_t>(data2));
PartitionFree(nullptr, data2, nullptr);
}
TEST(PartitionAllocAsMalloc, Realloc) {
constexpr size_t alloc_size = 100;
void* data = PartitionMalloc(nullptr, alloc_size, nullptr);
EXPECT_TRUE(data);
void* data2 = PartitionMalloc(nullptr, 2 * alloc_size, nullptr);
EXPECT_TRUE(data2);
EXPECT_NE(data2, data);
PartitionFree(nullptr, data2, nullptr);
}
// crbug.com/1141752
TEST(PartitionAllocAsMalloc, Alignment) {
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(PartitionAllocMalloc::Allocator()) %
alignof(ThreadSafePartitionRoot));
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(
PartitionAllocMalloc::AlignedAllocator()) %
alignof(ThreadSafePartitionRoot));
}
} // namespace internal
} // namespace base
#endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) &&
// BUILDFLAG(USE_PARTITION_ALLOC)
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