static SizeSpecificPartitionAllocator<kTestMaxAllocation> allocator;
static PartitionAllocatorGeneric genericAllocator;
-static const size_t kTestAllocSize = sizeof(void*);
+static const size_t kTestAllocSize = 16;
#ifdef NDEBUG
static const size_t kPointerOffset = 0;
static const size_t kExtraAllocSize = 0;
#else
-static const size_t kPointerOffset = sizeof(uintptr_t);
-static const size_t kExtraAllocSize = sizeof(uintptr_t) * 2;
+static const size_t kPointerOffset = WTF::kCookieSize;
+static const size_t kExtraAllocSize = WTF::kCookieSize * 2;
#endif
static const size_t kRealAllocSize = kTestAllocSize + kExtraAllocSize;
static const size_t kTestBucketIndex = kRealAllocSize >> WTF::kBucketShift;
}
}
+static void CycleGenericFreeCache(size_t size)
+{
+ for (size_t i = 0; i < WTF::kMaxFreeableSpans; ++i) {
+ void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
+ WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
+ WTF::PartitionBucket* bucket = page->bucket;
+ EXPECT_EQ(1, bucket->activePagesHead->numAllocatedSlots);
+ partitionFreeGeneric(genericAllocator.root(), ptr);
+ EXPECT_EQ(0, bucket->activePagesHead->numAllocatedSlots);
+ EXPECT_NE(-1, bucket->activePagesHead->freeCacheIndex);
+ }
+}
+
// Check that the most basic of allocate / free pairs work.
TEST(WTF_PartitionAlloc, Basic)
{
EXPECT_TRUE(page->freelistHead);
EXPECT_EQ(0, page->numAllocatedSlots);
- size_t verySmallSize = (WTF::kAllocationGranularity * 2) - kExtraAllocSize;
+ size_t verySmallSize = 32 - kExtraAllocSize;
bucketIdx = (verySmallSize + kExtraAllocSize) >> WTF::kBucketShift;
bucket = &allocator.root()->buckets()[bucketIdx];
EXPECT_EQ(0, bucket->freePagesHead);
TestShutdown();
}
+// Tests for a bug we had with losing references to free pages.
+TEST(WTF_PartitionAlloc, LostFreePagesBug)
+{
+ TestSetup();
+
+ size_t size = WTF::kPartitionPageSize - kExtraAllocSize;
+
+ void* ptr = partitionAllocGeneric(genericAllocator.root(), size);
+ EXPECT_TRUE(ptr);
+ void* ptr2 = partitionAllocGeneric(genericAllocator.root(), size);
+ EXPECT_TRUE(ptr2);
+
+ WTF::PartitionPage* page = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr));
+ WTF::PartitionPage* page2 = WTF::partitionPointerToPage(WTF::partitionCookieFreePointerAdjust(ptr2));
+ WTF::PartitionBucket* bucket = page->bucket;
+
+ EXPECT_EQ(0, bucket->freePagesHead);
+ EXPECT_EQ(-1, page->numAllocatedSlots);
+ EXPECT_EQ(1, page2->numAllocatedSlots);
+
+ partitionFreeGeneric(genericAllocator.root(), ptr);
+ partitionFreeGeneric(genericAllocator.root(), ptr2);
+
+ EXPECT_EQ(0, bucket->freePagesHead);
+ EXPECT_EQ(0, page->numAllocatedSlots);
+ EXPECT_EQ(0, page2->numAllocatedSlots);
+ EXPECT_TRUE(page->freelistHead);
+ EXPECT_TRUE(page2->freelistHead);
+
+ CycleGenericFreeCache(kTestAllocSize);
+
+ EXPECT_FALSE(page->freelistHead);
+ EXPECT_FALSE(page2->freelistHead);
+
+ EXPECT_FALSE(bucket->freePagesHead);
+ EXPECT_TRUE(bucket->activePagesHead);
+ EXPECT_TRUE(bucket->activePagesHead->nextPage);
+
+ // At this moment, we have two freed pages, on the freelist.
+
+ ptr = partitionAllocGeneric(genericAllocator.root(), size);
+ EXPECT_TRUE(ptr);
+ partitionFreeGeneric(genericAllocator.root(), ptr);
+
+ EXPECT_TRUE(bucket->activePagesHead);
+ EXPECT_TRUE(bucket->freePagesHead);
+
+ CycleGenericFreeCache(kTestAllocSize);
+
+ // We're now set up to trigger the bug by scanning over the active pages
+ // list, where the current active page is freed, and there exists at least
+ // one freed page in the free pages list.
+ ptr = partitionAllocGeneric(genericAllocator.root(), size);
+ EXPECT_TRUE(ptr);
+ partitionFreeGeneric(genericAllocator.root(), ptr);
+
+ EXPECT_TRUE(bucket->activePagesHead);
+ EXPECT_TRUE(bucket->freePagesHead);
+
+ TestShutdown();
+}
+
// Make sure that malloc(-1) dies.
// In the past, we had an integer overflow that would alias malloc(-1) to
// malloc(0), which is not good.