Commit 75c9f17b authored by Benoit Lize's avatar Benoit Lize Committed by Commit Bot

base/allocator: Document PartitionAlloc's alignment guarantees.

PartitionAlloc's alignement guarantees are not explicit anywhere, which
is problematic to support aligned allocations properly. This in turn is
required to broaden its use across the codebase.

This CL doesn't change the behavior, but documents the existing one.

Bug: 787153
Change-Id: Id3502081c5bf92f9f820ef1e992e56e1add92374
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2210422
Commit-Queue: Benoit L <lizeb@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#771723}
parent dea1552f
......@@ -100,3 +100,20 @@ hence at different addresses. One page can contain only similar-sized objects.
* Partial pointer overwrite of freelist pointer should fault.
* Large allocations have guard pages at the beginning and end.
## Alignment
PartitionAlloc doesn't have explicit support for a `posix_memalign()` type call,
however it provides some guarantees on the alignment of returned pointers.
All pointers are aligned on the smallest allocation granularity, namely
`sizeof(void*)`. Additionally, for power-of-two sized allocations, the behavior
depends on the compilation flags:
* With `DCHECK_IS_ON()`, returned pointers are never guaranteed to be aligned on
more than 16 bytes.
* Otherwise, the returned pointer is guaranteed to be aligned on
`min(allocation_size, system page size)`.
See the tests in `partition_alloc_unittest.cc` for more details.
......@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
......@@ -2305,6 +2306,40 @@ TEST_F(PartitionAllocTest, OverrideHooks) {
free(overridden_allocation);
}
TEST_F(PartitionAllocTest, Alignment) {
std::vector<void*> allocated_ptrs;
for (size_t size = 1; size <= base::kSystemPageSize; size <<= 1) {
// All allocations which are not direct-mapped occupy contiguous slots of a
// span, starting on a page boundary. This means that allocations are first
// rounded up to the nearest bucket size, then have an address of the form:
//
// (page-aligned address) + i * bucket_size.
#if DCHECK_IS_ON()
// When DCHECK_IS_ON(), a kCookieSize (16) cookie is added on both sides
// before rounding up the allocation size. The returned pointer points after
// the cookie.
//
// All in all, a power-of-two allocation is aligned on
// min(16, requested_size).
size_t expected_alignment = std::min(size, static_cast<size_t>(16));
#else
// All powers of two are bucket sizes, meaning that all power of two
// allocations smaller than a page will be aligned on the allocation size.
size_t expected_alignment = size;
#endif
for (int index = 0; index < 3; index++) {
void* ptr = generic_allocator.root()->Alloc(size, "");
allocated_ptrs.push_back(ptr);
EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) % expected_alignment)
<< index << "-th allocation of size = " << size;
}
}
for (void* ptr : allocated_ptrs)
generic_allocator.root()->Free(ptr);
}
} // namespace internal
} // namespace base
......
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