| // Copyright 2020 The Fuchsia 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 <lib/fidl/llcpp/aligned.h> |
| #include <lib/fidl/llcpp/buffer_then_heap_allocator.h> |
| |
| #include <gtest/gtest.h> |
| |
| TEST(UnsafeBufferAllocator, MultipleArgumentMake) { |
| struct A { |
| A(int64_t x, bool y) : x(x), y(y) {} |
| int64_t x; |
| bool y; |
| }; |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| fidl::tracking_ptr<A> ptr = allocator.make<A>(1, true); |
| EXPECT_EQ(ptr->x, 1); |
| EXPECT_EQ(ptr->y, true); |
| } |
| |
| TEST(UnsafeBufferAllocator, AllocationLayout) { |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| fidl::tracking_ptr<uint8_t> ptr1 = allocator.make<uint8_t>(); |
| fidl::tracking_ptr<uint8_t> ptr2 = allocator.make<uint8_t>(); |
| fidl::tracking_ptr<uint64_t[]> ptr3 = allocator.make<uint64_t[]>(2); |
| fidl::tracking_ptr<uint16_t> ptr4 = allocator.make<uint16_t>(); |
| |
| // Alignment. |
| EXPECT_TRUE(reinterpret_cast<uintptr_t>(ptr1.get()) % FIDL_ALIGNMENT == 0); |
| EXPECT_TRUE(reinterpret_cast<uintptr_t>(ptr2.get()) % FIDL_ALIGNMENT == 0); |
| EXPECT_TRUE(reinterpret_cast<uintptr_t>(ptr3.get()) % FIDL_ALIGNMENT == 0); |
| EXPECT_TRUE(reinterpret_cast<uintptr_t>(ptr4.get()) % FIDL_ALIGNMENT == 0); |
| |
| // Ensure objects don't overlap. |
| // The +1 is to get to the end of the object. |
| EXPECT_LE(ptr1.get() + 1, ptr2.get()); |
| EXPECT_LE(ptr2.get() + 1, reinterpret_cast<uint8_t*>(ptr3.get())); |
| EXPECT_LE(ptr3.get() + 1, reinterpret_cast<uint64_t*>(ptr4.get())); |
| } |
| |
| struct DestructCounter { |
| DestructCounter() : count(nullptr) {} |
| DestructCounter(int* count) : count(count) {} |
| ~DestructCounter() { ++*count; } |
| int* count; |
| }; |
| |
| TEST(UnsafeBufferAllocator, SingleItemDestructor) { |
| int destructCountA = 0; |
| int destructCountB = 0; |
| int destructCountC = 0; |
| { |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| { |
| allocator.make<DestructCounter>(&destructCountA); |
| allocator.make<DestructCounter>(&destructCountB); |
| allocator.make<DestructCounter>(&destructCountC); |
| } |
| EXPECT_EQ(destructCountA, 0); |
| EXPECT_EQ(destructCountB, 0); |
| EXPECT_EQ(destructCountC, 0); |
| } |
| EXPECT_EQ(destructCountA, 1); |
| EXPECT_EQ(destructCountB, 1); |
| EXPECT_EQ(destructCountC, 1); |
| } |
| |
| TEST(UnsafeBufferAllocator, ResetDestructor) { |
| int destructCountA = 0; |
| int destructCountB = 0; |
| int destructCountC = 0; |
| |
| { |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| |
| allocator.make<DestructCounter>(&destructCountA); |
| allocator.make<DestructCounter>(&destructCountB); |
| allocator.make<DestructCounter>(&destructCountC); |
| |
| EXPECT_EQ(destructCountA, 0); |
| EXPECT_EQ(destructCountB, 0); |
| EXPECT_EQ(destructCountC, 0); |
| |
| allocator.reset(); |
| |
| EXPECT_EQ(destructCountA, 1); |
| EXPECT_EQ(destructCountB, 1); |
| EXPECT_EQ(destructCountC, 1); |
| |
| allocator.make<DestructCounter>(&destructCountA); |
| allocator.make<DestructCounter>(&destructCountB); |
| allocator.make<DestructCounter>(&destructCountC); |
| |
| EXPECT_EQ(destructCountA, 1); |
| EXPECT_EQ(destructCountB, 1); |
| EXPECT_EQ(destructCountC, 1); |
| } |
| EXPECT_EQ(destructCountA, 2); |
| EXPECT_EQ(destructCountB, 2); |
| EXPECT_EQ(destructCountC, 2); |
| } |
| |
| TEST(UnsafeBufferAllocator, ArrayDestructor) { |
| constexpr int n = 3; |
| int destructCounts[n] = {}; |
| { |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| { |
| fidl::tracking_ptr<DestructCounter[]> ptr = allocator.make<DestructCounter[]>(n); |
| for (int i = 0; i < n; i++) { |
| ptr[i].count = &destructCounts[i]; |
| } |
| } |
| for (int i = 0; i < n; i++) { |
| EXPECT_EQ(destructCounts[i], 0); |
| } |
| } |
| for (int i = 0; i < n; i++) { |
| EXPECT_EQ(destructCounts[i], 1); |
| } |
| } |
| |
| TEST(UnsafeBufferAllocator, PrimitiveEightBytesEach) { |
| // Primitives will each use 8 bytes because allocations maintain FIDL_ALIGNMENT. |
| fidl::UnsafeBufferAllocator<64> allocator; |
| uint8_t* last_ptr = nullptr; |
| for (int i = 0; i < 8; i++) { |
| fidl::tracking_ptr<uint16_t> ptr = allocator.make<uint16_t>(); |
| |
| uint8_t* ptr_as_byte = reinterpret_cast<uint8_t*>(ptr.get()); |
| EXPECT_GE(ptr_as_byte - last_ptr, 8); |
| last_ptr = ptr_as_byte; |
| } |
| } |
| |
| TEST(UnsafeBufferAllocator, PrimitiveArrayFullSpace) { |
| // Primitives using at least 2 byte alignment should be able to allocate the |
| // full space. There should be no metadata. |
| // Currently (in the name of keeping the allocator interface simple), there is |
| // no way to verify the internal allocator state, in that all 32 bytes were |
| // consumed. |
| fidl::UnsafeBufferAllocator<32> allocator; |
| fidl::tracking_ptr<uint16_t[]> ptr = allocator.make<uint16_t[]>(16); |
| for (int i = 0; i < 16; i++) |
| EXPECT_EQ(ptr[i], 0); |
| } |
| |
| TEST(UnsafeBufferAllocator, EmptyAllocator) { |
| // In some implementations, it might be possible for uninitialized fields to trigger bad behavior |
| // for instance, uninitialized destructor metadata could be misinterpreted. |
| fidl::UnsafeBufferAllocator<2048> allocator; |
| } |