[llvm-commits] [compiler-rt] r171107 - in /compiler-rt/trunk/lib/asan: asan_allocator2.cc asan_rtl.cc tests/asan_test.cc
Kostya Serebryany
kcc at google.com
Wed Dec 26 02:41:25 PST 2012
Author: kcc
Date: Wed Dec 26 04:41:24 2012
New Revision: 171107
URL: http://llvm.org/viewvc/llvm-project?rev=171107&view=rev
Log:
[asan] asan_allocator2: implement adaptive redzones. Now with asan_allocator2 allocations <= 48 bytes have 16 byte redzone, allocations of 48-96 bytes -- have 32 bytes redzone, etc (max redzone is 2048). If ASAN_OPTIONS=redzone=n is set, it changes the minimal redzone size
Modified:
compiler-rt/trunk/lib/asan/asan_allocator2.cc
compiler-rt/trunk/lib/asan/asan_rtl.cc
compiler-rt/trunk/lib/asan/tests/asan_test.cc
Modified: compiler-rt/trunk/lib/asan/asan_allocator2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator2.cc?rev=171107&r1=171106&r2=171107&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator2.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator2.cc Wed Dec 26 04:41:24 2012
@@ -99,11 +99,39 @@
// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
enum {
- CHUNK_AVAILABLE = 1,
+ CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it.
CHUNK_ALLOCATED = 2,
CHUNK_QUARANTINE = 3
};
+// Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits.
+// We use adaptive redzones: for larger allocation larger redzones are used.
+static u32 RZLog2Size(u32 rz_log) {
+ CHECK_LT(rz_log, 8);
+ return 16 << rz_log;
+}
+
+static u32 RZSize2Log(u32 rz_size) {
+ CHECK_GE(rz_size, 16);
+ CHECK_LE(rz_size, 2048);
+ CHECK(IsPowerOfTwo(rz_size));
+ u32 res = __builtin_ctz(rz_size) - 4;
+ CHECK_EQ(rz_size, RZLog2Size(res));
+ return res;
+}
+
+static uptr ComputeRZLog(uptr user_requested_size) {
+ u32 rz_log =
+ user_requested_size <= 64 - 16 ? 0 :
+ user_requested_size <= 128 - 32 ? 1 :
+ user_requested_size <= 512 - 64 ? 2 :
+ user_requested_size <= 4096 - 128 ? 3 :
+ user_requested_size <= (1 << 14) - 256 ? 4 :
+ user_requested_size <= (1 << 15) - 512 ? 5 :
+ user_requested_size <= (1 << 16) - 1024 ? 6 : 7;
+ return Max(rz_log, RZSize2Log(flags()->redzone));
+}
+
// The memory chunk allocated from the underlying allocator looks like this:
// L L L L L L H H U U U U U U R R
// L -- left redzone words (0 or more bytes)
@@ -130,6 +158,7 @@
u32 free_tid : 24;
u32 from_memalign : 1;
u32 alloc_type : 2;
+ u32 rz_log : 3;
// 2-nd 8 bytes
// This field is used for small sizes. For large sizes it is equal to
// SizeClassMap::kMaxSize and the actual size is stored in the
@@ -149,11 +178,6 @@
COMPILER_CHECK(kChunkHeaderSize == 16);
COMPILER_CHECK(kChunkHeader2Size <= 16);
-static uptr ComputeRZSize(uptr user_requested_size) {
- // FIXME: implement adaptive redzones.
- return flags()->redzone;
-}
-
struct AsanChunk: ChunkBase {
uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
uptr UsedSize() {
@@ -164,21 +188,22 @@
void *AllocBeg() {
if (from_memalign)
return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
- return reinterpret_cast<void*>(Beg() - ComputeRZSize(0));
+ return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// We store the alloc/free stack traces in the chunk itself.
u32 *AllocStackBeg() {
- return (u32*)(Beg() - ComputeRZSize(UsedSize()));
+ return (u32*)(Beg() - RZLog2Size(rz_log));
}
uptr AllocStackSize() {
- return (ComputeRZSize(UsedSize()) - kChunkHeaderSize) / sizeof(u32);
+ CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize);
+ return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32);
}
u32 *FreeStackBeg() {
return (u32*)(Beg() + kChunkHeader2Size);
}
uptr FreeStackSize() {
uptr available = Max(RoundUpTo(UsedSize(), SHADOW_GRANULARITY),
- ComputeRZSize(UsedSize()));
+ (uptr)RZLog2Size(rz_log));
return (available - kChunkHeader2Size) / sizeof(u32);
}
};
@@ -246,10 +271,8 @@
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
kAsanHeapLeftRedzoneMagic);
- uptr alloc_beg = m->Beg() - ComputeRZSize(m->UsedSize());
- void *p = reinterpret_cast<void *>(alloc_beg);
+ void *p = reinterpret_cast<void *>(m->AllocBeg());
if (m->from_memalign) {
- p = allocator.GetBlockBegin(p);
uptr *memalign_magic = reinterpret_cast<uptr *>(p);
CHECK_EQ(memalign_magic[0], kMemalignMagic);
CHECK_EQ(memalign_magic[1], reinterpret_cast<uptr>(m));
@@ -302,7 +325,8 @@
return 0; // 0 bytes with large alignment requested. Just return 0.
}
CHECK(IsPowerOfTwo(alignment));
- uptr rz_size = ComputeRZSize(size);
+ uptr rz_log = ComputeRZLog(size);
+ uptr rz_size = RZLog2Size(rz_log);
uptr rounded_size = RoundUpTo(size, rz_size);
uptr needed_size = rounded_size + rz_size;
if (alignment > rz_size)
@@ -336,6 +360,7 @@
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
m->chunk_state = CHUNK_ALLOCATED;
m->alloc_type = alloc_type;
+ m->rz_log = rz_log;
u32 alloc_tid = t ? t->tid() : 0;
m->alloc_tid = alloc_tid;
CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield?
@@ -354,7 +379,9 @@
} else {
CHECK(!allocator.FromPrimary(allocated));
m->user_requested_size = SizeClassMap::kMaxSize;
- *reinterpret_cast<uptr *>(allocator.GetMetaData(allocated)) = size;
+ uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated));
+ meta[0] = size;
+ meta[1] = chunk_beg;
}
if (flags()->use_stack_depot) {
@@ -465,17 +492,34 @@
}
static AsanChunk *GetAsanChunkByAddr(uptr p) {
- uptr alloc_beg = reinterpret_cast<uptr>(
- allocator.GetBlockBegin(reinterpret_cast<void *>(p)));
+ void *ptr = reinterpret_cast<void *>(p);
+ uptr alloc_beg = reinterpret_cast<uptr>(allocator.GetBlockBegin(ptr));
if (!alloc_beg) return 0;
uptr *memalign_magic = reinterpret_cast<uptr *>(alloc_beg);
if (memalign_magic[0] == kMemalignMagic) {
- AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
- CHECK(m->from_memalign);
- return m;
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(memalign_magic[1]);
+ CHECK(m->from_memalign);
+ return m;
+ }
+ if (!allocator.FromPrimary(ptr)) {
+ uptr *meta = reinterpret_cast<uptr *>(
+ allocator.GetMetaData(reinterpret_cast<void *>(alloc_beg)));
+ AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]);
+ return m;
+ }
+ uptr actual_size = allocator.GetActuallyAllocatedSize(ptr);
+ CHECK_LE(actual_size, SizeClassMap::kMaxSize);
+ // We know the actually allocted size, but we don't know the redzone size.
+ // Just try all possible redzone sizes.
+ for (u32 rz_log = 0; rz_log < 8; rz_log++) {
+ u32 rz_size = RZLog2Size(rz_log);
+ uptr max_possible_size = actual_size - rz_size;
+ if (ComputeRZLog(max_possible_size) != rz_log)
+ continue;
+ return reinterpret_cast<AsanChunk *>(
+ alloc_beg + rz_size - kChunkHeaderSize);
}
- uptr chunk_beg = alloc_beg + ComputeRZSize(0) - kChunkHeaderSize;
- return reinterpret_cast<AsanChunk *>(chunk_beg);
+ return 0;
}
static uptr AllocationSize(uptr p) {
@@ -489,14 +533,19 @@
// We have an address between two chunks, and we want to report just one.
AsanChunk *ChooseChunk(uptr addr,
AsanChunk *left_chunk, AsanChunk *right_chunk) {
- // Prefer an allocated chunk or a chunk from quarantine.
- if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
- right_chunk->chunk_state != CHUNK_AVAILABLE)
- return right_chunk;
- if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
- left_chunk->chunk_state != CHUNK_AVAILABLE)
- return left_chunk;
- // Choose based on offset.
+ // Prefer an allocated chunk over freed chunk and freed chunk
+ // over available chunk.
+ if (left_chunk->chunk_state != right_chunk->chunk_state) {
+ if (left_chunk->chunk_state == CHUNK_ALLOCATED)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_ALLOCATED)
+ return right_chunk;
+ if (left_chunk->chunk_state == CHUNK_QUARANTINE)
+ return left_chunk;
+ if (right_chunk->chunk_state == CHUNK_QUARANTINE)
+ return right_chunk;
+ }
+ // Same chunk_state: choose based on offset.
uptr l_offset = 0, r_offset = 0;
CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=171107&r1=171106&r2=171107&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Wed Dec 26 04:41:24 2012
@@ -117,7 +117,7 @@
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
f->symbolize = false;
f->verbosity = 0;
- f->redzone = (ASAN_LOW_MEMORY) ? 64 : 128;
+ f->redzone = ASAN_ALLOCATOR_VERSION == 2 ? 16 : (ASAN_LOW_MEMORY) ? 64 : 128;
f->debug = false;
f->report_globals = 1;
f->check_initialization_order = true;
Modified: compiler-rt/trunk/lib/asan/tests/asan_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test.cc?rev=171107&r1=171106&r2=171107&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test.cc (original)
+++ compiler-rt/trunk/lib/asan/tests/asan_test.cc Wed Dec 26 04:41:24 2012
@@ -479,7 +479,6 @@
#ifndef __APPLE__
void MemalignRun(size_t align, size_t size, int idx) {
- fprintf(stderr, "align %ld\n", align);
char *p = (char *)memalign(align, size);
Ident(p)[idx] = 0;
free(p);
@@ -899,8 +898,11 @@
LeftOOBWriteMessage(1));
EXPECT_DEATH(memset((char*)array - 5, 0, 6),
LeftOOBWriteMessage(5));
- EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
- LeftOOBWriteMessage(5 * sizeof(T)));
+ if (length >= 100) {
+ // Large OOB, we find it only if the redzone is large enough.
+ EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+ LeftOOBWriteMessage(5 * sizeof(T)));
+ }
// whole interval is to the left
EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
LeftOOBWriteMessage(2 * sizeof(T)));
More information about the llvm-commits
mailing list