// This method is *not* marked noalias, because
// SpecificBumpPtrAllocator::DestroyAll() loops over all allocations, and
// that loop is not based on the Allocate() return value.
+ //
+ // Allocate(0, N) is valid, it returns a non-null pointer (which should not
+ // be dereferenced).
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, Align Alignment) {
// Keep track of how many bytes we've allocated.
BytesAllocated += Size;
#endif
// Check if we have enough space.
- if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)) {
+ if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)
+ // We can't return nullptr even for a zero-sized allocation!
+ && CurPtr != nullptr) {
char *AlignedPtr = CurPtr + Adjustment;
CurPtr = AlignedPtr + SizeToAllocate;
// Update the allocation point of this memory block in MemorySanitizer.
EXPECT_EQ(0U, a & 127);
}
+// Test zero-sized allocations.
+// In general we don't need to allocate memory for these.
+// However Allocate never returns null, so if the first allocation is zero-sized
+// we end up creating a slab for it.
+TEST(AllocatorTest, TestZero) {
+ BumpPtrAllocator Alloc;
+ EXPECT_EQ(0u, Alloc.GetNumSlabs());
+ EXPECT_EQ(0u, Alloc.getBytesAllocated());
+
+ void *Empty = Alloc.Allocate(0, 1);
+ EXPECT_NE(Empty, nullptr) << "Allocate is __attribute__((returns_nonnull))";
+ EXPECT_EQ(1u, Alloc.GetNumSlabs()) << "Allocated a slab to point to";
+ EXPECT_EQ(0u, Alloc.getBytesAllocated());
+
+ void *Large = Alloc.Allocate(4096, 1);
+ EXPECT_EQ(1u, Alloc.GetNumSlabs());
+ EXPECT_EQ(4096u, Alloc.getBytesAllocated());
+ EXPECT_EQ(Empty, Large);
+
+ void *Empty2 = Alloc.Allocate(0, 1);
+ EXPECT_NE(Empty2, nullptr);
+ EXPECT_EQ(1u, Alloc.GetNumSlabs());
+ EXPECT_EQ(4096u, Alloc.getBytesAllocated());
+}
+
// Test allocating just over the slab size. This tests a bug where before the
// allocator incorrectly calculated the buffer end pointer.
TEST(AllocatorTest, TestOverflow) {