From 3edc5c41bbee7cf608a781e7056599f32ca1949c Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 21 Jan 2016 10:55:40 -0800 Subject: [PATCH] linker: align allocated blocks to 16 bytes C/C++ requires the result of malloc/new to be aligned for any primitive type. Change-Id: I715b7679e738f34b3b409993fb3ef242e1321b7f --- linker/linker_allocator.cpp | 2 ++ linker/linker_allocator.h | 2 +- linker/linker_block_allocator.cpp | 13 +++++++++++-- linker/tests/linker_block_allocator_test.cpp | 12 +++++++++--- linker/tests/linker_memory_allocator_test.cpp | 10 ++++++++++ 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/linker/linker_allocator.cpp b/linker/linker_allocator.cpp index 1b16cf12c..76ec97005 100644 --- a/linker/linker_allocator.cpp +++ b/linker/linker_allocator.cpp @@ -189,6 +189,8 @@ void LinkerSmallObjectAllocator::create_page_record(void* page_addr, size_t free } void LinkerSmallObjectAllocator::alloc_page() { + static_assert(sizeof(page_info) % 16 == 0, + "sizeof(page_info) is not multiple of 16"); void* map_ptr = mmap(nullptr, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); if (map_ptr == MAP_FAILED) { diff --git a/linker/linker_allocator.h b/linker/linker_allocator.h index 2adad56fe..c1edac414 100644 --- a/linker/linker_allocator.h +++ b/linker/linker_allocator.h @@ -45,7 +45,7 @@ struct page_info { // and allocator_addr for small ones. LinkerSmallObjectAllocator* allocator_addr; }; -}; +} __attribute__((aligned(16))); struct small_object_page_record { void* page_addr; diff --git a/linker/linker_block_allocator.cpp b/linker/linker_block_allocator.cpp index fc9a75b15..23298a473 100644 --- a/linker/linker_block_allocator.cpp +++ b/linker/linker_block_allocator.cpp @@ -22,9 +22,14 @@ #include "private/bionic_prctl.h" +// the multiplier should be power of 2 +static constexpr size_t round_up(size_t size, size_t multiplier) { + return (size + (multiplier - 1)) & ~(multiplier-1); +} + struct LinkerBlockAllocatorPage { LinkerBlockAllocatorPage* next; - uint8_t bytes[PAGE_SIZE-sizeof(LinkerBlockAllocatorPage*)]; + uint8_t bytes[PAGE_SIZE - 16] __attribute__((aligned(16))); }; struct FreeBlockInfo { @@ -33,7 +38,8 @@ struct FreeBlockInfo { }; LinkerBlockAllocator::LinkerBlockAllocator(size_t block_size) - : block_size_(block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size), + : block_size_( + round_up(block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size, 16)), page_list_(nullptr), free_block_list_(nullptr) {} @@ -95,6 +101,9 @@ void LinkerBlockAllocator::protect_all(int prot) { } void LinkerBlockAllocator::create_new_page() { + static_assert(sizeof(LinkerBlockAllocatorPage) == PAGE_SIZE, + "Invalid sizeof(LinkerBlockAllocatorPage)"); + LinkerBlockAllocatorPage* page = reinterpret_cast( mmap(nullptr, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)); diff --git a/linker/tests/linker_block_allocator_test.cpp b/linker/tests/linker_block_allocator_test.cpp index 3ef0f36f8..5adc4253e 100644 --- a/linker/tests/linker_block_allocator_test.cpp +++ b/linker/tests/linker_block_allocator_test.cpp @@ -53,10 +53,12 @@ TEST(linker_allocator, test_nominal) { test_struct_nominal* ptr1 = allocator.alloc(); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); test_struct_nominal* ptr2 = allocator.alloc(); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); ASSERT_TRUE(ptr2 != nullptr); // they should be next to each other. - ASSERT_EQ(ptr1+1, ptr2); + ASSERT_EQ(reinterpret_cast(ptr1)+16, reinterpret_cast(ptr2)); ptr1->value = 42; @@ -71,8 +73,10 @@ TEST(linker_allocator, test_small) { char* ptr2 = reinterpret_cast(allocator.alloc()); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); ASSERT_TRUE(ptr2 != nullptr); - ASSERT_EQ(ptr1+2*sizeof(void*), ptr2); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); + ASSERT_EQ(ptr1+16, ptr2); // aligned to 16 } TEST(linker_allocator, test_larger) { @@ -82,9 +86,11 @@ TEST(linker_allocator, test_larger) { test_struct_larger* ptr2 = allocator.alloc(); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); ASSERT_TRUE(ptr2 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); - ASSERT_EQ(ptr1+1, ptr2); + ASSERT_EQ(reinterpret_cast(ptr1) + 1024, reinterpret_cast(ptr2)); // lets allocate until we reach next page. size_t n = kPageSize/sizeof(test_struct_larger) + 1 - 2; diff --git a/linker/tests/linker_memory_allocator_test.cpp b/linker/tests/linker_memory_allocator_test.cpp index defd4f3a8..5b8553675 100644 --- a/linker/tests/linker_memory_allocator_test.cpp +++ b/linker/tests/linker_memory_allocator_test.cpp @@ -96,6 +96,7 @@ TEST(linker_memory, test_realloc) { ASSERT_TRUE(reallocated_ptr != nullptr); ASSERT_TRUE(reallocated_ptr != array); + ASSERT_EQ(0U, reinterpret_cast(reallocated_ptr) % 16); ASSERT_TRUE(memcmp(reallocated_ptr, model, array_size * 2) == 0); @@ -107,6 +108,7 @@ TEST(linker_memory, test_realloc) { ASSERT_TRUE(reallocated_ptr != nullptr); ASSERT_TRUE(reallocated_ptr != array); + ASSERT_EQ(0U, reinterpret_cast(reallocated_ptr) % 16); ASSERT_TRUE(memcmp(reallocated_ptr, model, 4000) == 0); @@ -125,7 +127,10 @@ TEST(linker_memory, test_small_smoke) { reinterpret_cast(allocator.alloc(sizeof(test_struct_small))); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); ASSERT_TRUE(ptr2 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); + ASSERT_EQ(reinterpret_cast(ptr1)+16, reinterpret_cast(ptr2)); ASSERT_TRUE(memcmp(ptr1, zeros, 16) == 0); @@ -143,7 +148,9 @@ TEST(linker_memory, test_huge_smoke) { reinterpret_cast(allocator.alloc(sizeof(test_struct_huge))); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); ASSERT_TRUE(ptr2 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); ASSERT_TRUE( reinterpret_cast(ptr1)/kPageSize != reinterpret_cast(ptr2)/kPageSize); @@ -160,7 +167,9 @@ TEST(linker_memory, test_large) { reinterpret_cast(allocator.alloc(1024)); ASSERT_TRUE(ptr1 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr1) % 16); ASSERT_TRUE(ptr2 != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr2) % 16); ASSERT_EQ(reinterpret_cast(ptr1) + 1024, reinterpret_cast(ptr2)); @@ -179,6 +188,7 @@ TEST(linker_memory, test_large) { reinterpret_cast(allocator.alloc(sizeof(test_struct_large))); ASSERT_TRUE(ptr_to_free != nullptr); + ASSERT_EQ(0U, reinterpret_cast(ptr_to_free) % 16); allocator.free(ptr1); -- 2.11.0