Commit 0cae02ef authored by Benoit Lize's avatar Benoit Lize Committed by Commit Bot

[PartitionAlloc] Respect alignment constraints on Windows 64 bits.

On Windows 64 bits, alignof(std::max_align_t) is 8, but we need 16 for
operator new(). This is not the case on Linux for instance, and in
https://chromium-review.googlesource.com/c/chromium/src/+/2219498 we
followed the standard for malloc(), but not for operator new.

Make sure we respect the more stringent of the two criteria.

Bug: 998048
Change-Id: I01f060d710f11adb5fb41dc8d332c1c690c2b508
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404444
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarBartek Nowierski <bartekn@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#806130}
parent 704b0f5e
......@@ -69,11 +69,9 @@ static_assert(kMaxDirectMapped <= (1UL << 31) + kPageAllocationGranularity,
"maximum direct mapped allocation");
// Check that some of our zanier calculations worked out as expected.
#if ENABLE_TAG_FOR_MTE_CHECKED_PTR
static_assert(kSmallestBucket >= alignof(std::max_align_t),
"generic smallest bucket");
static_assert(kSmallestBucket >= kAlignment, "generic smallest bucket");
#else
static_assert(kSmallestBucket == alignof(std::max_align_t),
"generic smallest bucket");
static_assert(kSmallestBucket == kAlignment, "generic smallest bucket");
#endif
static_assert(kMaxBucketed == 983040, "generic max bucketed");
static_assert(kMaxSystemPagesPerSlotSpan < (1 << 8),
......
......@@ -6,6 +6,7 @@
#define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONSTANTS_H_
#include <limits.h>
#include <algorithm>
#include <cstddef>
#include "base/allocator/partition_allocator/checked_ptr_support.h"
......@@ -149,6 +150,27 @@ static const size_t kSuperPageBaseMask = ~kSuperPageOffsetMask;
static const size_t kNumPartitionPagesPerSuperPage =
kSuperPageSize / kPartitionPageSize;
// Alignment has two constraints:
// - Alignment requirement for scalar types: alignof(std::max_align_t)
// - Alignment requirement for operator new().
//
// The two are separate on Windows 64 bits, where the first one is 8 bytes, and
// the second one 16. We could technically return something different for
// malloc() and operator new(), but this would complicate things, and most of
// our allocations are presumaly coming from operator new() anyway.
//
// __STDCPP_DEFAULT_NEW_ALIGNMENT__ is C++17. As such, it is not defined on all
// platforms, as Chrome's requirement is C++14 as of 2020.
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
static constexpr size_t kAlignment =
std::max(alignof(std::max_align_t), __STDCPP_DEFAULT_NEW_ALIGNMENT__);
#else
static constexpr size_t kAlignment = alignof(std::max_align_t);
#endif
static_assert(kAlignment <= 16,
"PartitionAlloc doesn't support a fundamental alignment larger "
"than 16 bytes.");
// The "order" of an allocation is closely related to the power-of-1 size of the
// allocation. More precisely, the order is the bit index of the
// most-significant-bit in the allocation size, where the bit numbers starts at
......@@ -157,9 +179,6 @@ static const size_t kNumPartitionPagesPerSuperPage =
// In terms of allocation sizes, order 0 covers 0, order 1 covers 1, order 2
// covers 2->3, order 3 covers 4->7, order 4 covers 8->15.
static_assert(alignof(std::max_align_t) <= 16,
"PartitionAlloc doesn't support a fundamental alignment larger "
"than 16 bytes.");
// PartitionAlloc should return memory properly aligned for any type, to behave
// properly as a generic allocator. This is not strictly required as long as
// types are explicitly allocated with PartitionAlloc, but is to use it as a
......@@ -172,7 +191,7 @@ static_assert(alignof(std::max_align_t) <= 16,
static const size_t kMinBucketedOrder = 5;
#else
static const size_t kMinBucketedOrder =
alignof(std::max_align_t) == 16 ? 5 : 4; // 2^(order - 1), that is 16 or 8.
kAlignment == 16 ? 5 : 4; // 2^(order - 1), that is 16 or 8.
#endif
// The largest bucketed order is 1 << (20 - 1), storing [512 KiB, 1 MiB):
static const size_t kMaxBucketedOrder = 20;
......
......@@ -2447,7 +2447,7 @@ TEST_F(PartitionAllocTest, FundamentalAlignment) {
// See the test above for details. Essentially, checking the bucket size is
// sufficient to ensure that alignment will always be respected, as long as
// the fundamental alignment is <= 16 bytes.
size_t fundamental_alignment = alignof(std::max_align_t);
size_t fundamental_alignment = base::kAlignment;
for (size_t size = 0; size < base::kSystemPageSize; size++) {
// Allocate several pointers, as the first one in use in a size class will
// be aligned on a page boundary.
......
......@@ -64,7 +64,7 @@ class BASE_EXPORT PartitionRefCount {
// Allocate extra space for the reference count to satisfy the alignment
// requirement.
static constexpr size_t kInSlotRefCountBufferSize = alignof(std::max_align_t);
static constexpr size_t kInSlotRefCountBufferSize = kAlignment;
static_assert(sizeof(PartitionRefCount) <= kInSlotRefCountBufferSize,
"PartitionRefCount should fit into the in-slot buffer.");
......
......@@ -27,7 +27,7 @@ using PartitionTag = uint8_t;
// Allocate extra space for the partition tag to satisfy the alignment
// requirement.
static constexpr size_t kInSlotTagBufferSize = alignof(std::max_align_t);
static constexpr size_t kInSlotTagBufferSize = base::kAlignment;
static_assert(sizeof(PartitionTag) <= kInSlotTagBufferSize,
"PartitionTag should fit into the in-slot buffer.");
......
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