Skip to content

Commit 278ccda

Browse files
committed
[tsan] add metadata to the new tsan allocator
llvm-svn: 159002
1 parent 052f60d commit 278ccda

File tree

2 files changed

+58
-6
lines changed

2 files changed

+58
-6
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_allocator64.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,12 @@ class SizeClassAllocator64 {
9696
CHECK_EQ(AllocBeg(), reinterpret_cast<uptr>(MmapFixedNoReserve(
9797
AllocBeg(), AllocSize())));
9898
}
99+
NOINLINE
99100
void *Allocate(uptr size) {
100101
CHECK_LE(size, SizeClassMap::kMaxSize);
101102
return AllocateBySizeClass(SizeClassMap::ClassID(size));
102103
}
104+
NOINLINE
103105
void Deallocate(void *p) {
104106
DeallocateBySizeClass(p, GetSizeClass(p));
105107
}
@@ -110,6 +112,13 @@ class SizeClassAllocator64 {
110112
return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
111113
}
112114

115+
uptr GetMetaData(void *p) {
116+
uptr class_id = GetSizeClass(p);
117+
uptr chunk_idx = GetChunkIdx(reinterpret_cast<uptr>(p), class_id);
118+
return kSpaceBeg + (kRegionSize * (class_id + 1)) -
119+
(1 + chunk_idx) * kMetadataSize;
120+
}
121+
113122
uptr TotalMemoryUsedIncludingFreeLists() {
114123
uptr res = 0;
115124
for (uptr i = 0; i < kNumClasses; i++)
@@ -125,6 +134,7 @@ class SizeClassAllocator64 {
125134
static const uptr kNumClasses = 256; // Power of two <= 256
126135
COMPILER_CHECK(kNumClasses <= SizeClassMap::kNumClasses);
127136
static const uptr kRegionSize = kSpaceSize / kNumClasses;
137+
COMPILER_CHECK((kRegionSize >> 32) > 0); // kRegionSize must be >= 2^32.
128138
// Populate the free list with at most this number of bytes at once
129139
// or with one element if its size is greater.
130140
static const uptr kPopulateSize = 1 << 18;
@@ -163,6 +173,14 @@ class SizeClassAllocator64 {
163173
return res;
164174
}
165175

176+
uptr GetChunkIdx(uptr chunk, uptr class_id) {
177+
u32 offset = chunk % kRegionSize;
178+
// Here we divide by a non-constant. This is costly.
179+
// We require that kRegionSize is at least 2^32 so that offset is 32-bit.
180+
// We save 2x by using 32-bit div, but may need to use a 256-way switch.
181+
return offset / (u32)SizeClassMap::Size(class_id);
182+
}
183+
166184
LifoListNode *PopulateFreeList(uptr class_id, RegionInfo *region) {
167185
uptr size = SizeClassMap::Size(class_id);
168186
uptr beg_idx = region->allocated;

compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator64_test.cc

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ TEST(SanitizerCommon, DefaultSizeClassMap) {
4747
}
4848
}
4949

50+
static const uptr kAllocatorSpace = 0x600000000000ULL;
51+
static const uptr kAllocatorSize = 0x10000000000; // 1T.
52+
5053
TEST(SanitizerCommon, SizeClassAllocator64) {
51-
const uptr space_beg = 0x600000000000ULL;
52-
const uptr space_size = 0x10000000000; // 1T
53-
const uptr metadata_size = 16;
5454
typedef DefaultSizeClassMap SCMap;
55-
typedef SizeClassAllocator64<space_beg, space_size,
56-
metadata_size, SCMap> Allocator;
55+
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
56+
16, SCMap> Allocator;
5757

5858
Allocator a;
5959
a.Init();
@@ -76,11 +76,18 @@ TEST(SanitizerCommon, SizeClassAllocator64) {
7676
CHECK(a.PointerIsMine(x));
7777
uptr class_id = a.GetSizeClass(x);
7878
CHECK_EQ(class_id, SCMap::ClassID(size));
79+
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
80+
metadata[0] = reinterpret_cast<uptr>(x) + 1;
81+
metadata[1] = 0xABCD;
7982
}
8083
}
8184
// Deallocate all.
8285
for (uptr i = 0; i < allocated.size(); i++) {
83-
a.Deallocate(allocated[i]);
86+
void *x = allocated[i];
87+
uptr *metadata = reinterpret_cast<uptr*>(a.GetMetaData(x));
88+
CHECK_EQ(metadata[0], reinterpret_cast<uptr>(x) + 1);
89+
CHECK_EQ(metadata[1], 0xABCD);
90+
a.Deallocate(x);
8491
}
8592
allocated.clear();
8693
uptr total_allocated = a.TotalMemoryUsedIncludingFreeLists();
@@ -91,3 +98,30 @@ TEST(SanitizerCommon, SizeClassAllocator64) {
9198

9299
a.TestOnlyUnmap();
93100
}
101+
102+
103+
TEST(SanitizerCommon, SizeClassAllocator64MetadataStress) {
104+
typedef DefaultSizeClassMap SCMap;
105+
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
106+
16, SCMap> Allocator;
107+
Allocator a;
108+
a.Init();
109+
static volatile uptr sink;
110+
111+
const uptr kNumAllocs = 10000;
112+
void *allocated[kNumAllocs];
113+
for (uptr i = 0; i < kNumAllocs; i++) {
114+
uptr size = (i % 4096) + 1;
115+
void *x = a.Allocate(size);
116+
allocated[i] = x;
117+
}
118+
// Get Metadata kNumAllocs^2 times.
119+
for (uptr i = 0; i < kNumAllocs * kNumAllocs; i++) {
120+
sink = a.GetMetaData(allocated[i % kNumAllocs]);
121+
}
122+
for (uptr i = 0; i < kNumAllocs; i++) {
123+
a.Deallocate(allocated[i]);
124+
}
125+
126+
a.TestOnlyUnmap();
127+
}

0 commit comments

Comments
 (0)