Force static flatbuffer memory to be aligned
For buffers which required lots of alignment, we were allocating more
space than needed, and manually aligning inside that space. That
doesn't have a good enough contract to ensure that if the flatbuffer is
loaded back into RAM, it would still be aligned well enough for the
requirements.
Instead, we need to push the alignment requirement out to the allocator,
and then make sure we stay aligned inside the buffer. The std::vector<>
allocator isn't guarenteed to be aligned, so switch everything over to
the AlignedVectorAllocator instead which is aligned.
Change-Id: Ice2aa1316914472f2a3d55f470a4dc957e2caa3c
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/flatbuffers/base_test.cc b/aos/flatbuffers/base_test.cc
index 87d89fa..43c9c5b 100644
--- a/aos/flatbuffers/base_test.cc
+++ b/aos/flatbuffers/base_test.cc
@@ -6,8 +6,6 @@
#include "gtest/gtest.h"
-#include "aos/flatbuffers/aligned_allocator.h"
-
namespace aos::fbs::testing {
// Tests that PaddedSize() behaves as expected.
TEST(BaseTest, PaddedSize) {
@@ -23,19 +21,18 @@
class AllocatorTest : public ::testing::Test {
protected:
AllocatorTest() : allocator_(std::make_unique<T>()) {}
- std::vector<uint8_t> buffer_;
+ alignas(64) std::array<uint8_t, kDefaultSize> buffer_;
// unique_ptr so that we can destroy the allocator at will.
std::unique_ptr<T> allocator_;
};
template <>
AllocatorTest<SpanAllocator>::AllocatorTest()
- : buffer_(kDefaultSize),
- allocator_(std::make_unique<SpanAllocator>(
+ : allocator_(std::make_unique<SpanAllocator>(
std::span<uint8_t>{buffer_.data(), buffer_.size()})) {}
-using AllocatorTypes =
- ::testing::Types<SpanAllocator, VectorAllocator, AlignedVectorAllocator>;
+using AllocatorTypes = ::testing::Types<SpanAllocator, AlignedVectorAllocator,
+ FixedStackAllocator<kDefaultSize>>;
TYPED_TEST_SUITE(AllocatorTest, AllocatorTypes);
// Tests that we can create and not use a VectorAllocator.
@@ -80,6 +77,17 @@
this->allocator_->Deallocate(span);
}
+// Tests that all allocators return data aligned to the requested alignment.
+TYPED_TEST(AllocatorTest, Alignment) {
+ for (size_t alignment : {4, 8, 16, 32, 64}) {
+ std::span<uint8_t> span =
+ this->allocator_->Allocate(kDefaultSize, alignment, SetZero::kYes)
+ .value();
+ EXPECT_EQ(reinterpret_cast<size_t>(span.data()) % alignment, 0);
+ this->allocator_->Deallocate(span);
+ }
+}
+
// Tests that we can remove bytes from an arbitrary spot in the buffer.
TYPED_TEST(AllocatorTest, RemoveBytes) {
// Deletion doesn't require resizing, so we don't need to worry about it being
@@ -142,7 +150,7 @@
std::vector<uint8_t> buffer(kDefaultSize);
SpanAllocator allocator({buffer.data(), buffer.size()});
std::span<uint8_t> span =
- allocator.Allocate(kDefaultSize, 0, SetZero::kYes).value();
+ allocator.Allocate(kDefaultSize, 1, SetZero::kYes).value();
EXPECT_EQ(kDefaultSize, span.size());
EXPECT_FALSE(
allocator.InsertBytes(span.data(), 1u, 0, SetZero::kYes).has_value());
@@ -209,7 +217,7 @@
: object_(allocator_.Allocate(kInitialSize, 4, SetZero::kYes).value(),
&allocator_) {}
~ResizeableObjectTest() { allocator_.Deallocate(object_.buffer()); }
- VectorAllocator allocator_;
+ AlignedVectorAllocator allocator_;
TestResizeableObject object_;
};