[ASan] Fix an error on invalid deallocation in ASan allocator. When ASan checks if memory freed by user was indeed previously allocated, it first does an atomic write to presumed location of chunk header. This is wrong, as if the free is invalid, we may overwrite some valuable data (like other fields of the chunk header). Fix this by using atomic_compare_exchange instead.

llvm-svn: 177710
This commit is contained in:
Alexey Samsonov 2013-03-22 07:40:34 +00:00
parent a7e42b5be5
commit a5eb3cb721
2 changed files with 13 additions and 9 deletions

View File

@ -421,15 +421,17 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
u8 old_chunk_state = CHUNK_ALLOCATED;
// Flip the chunk_state atomically to avoid race on double-free.
u8 old_chunk_state = atomic_exchange((atomic_uint8_t*)m, CHUNK_QUARANTINE,
memory_order_relaxed);
if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
CHUNK_QUARANTINE, memory_order_relaxed)) {
if (old_chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else
ReportFreeNotMalloced((uptr)ptr, stack);
}
CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
if (old_chunk_state == CHUNK_QUARANTINE)
ReportDoubleFree((uptr)ptr, stack);
else if (old_chunk_state != CHUNK_ALLOCATED)
ReportFreeNotMalloced((uptr)ptr, stack);
CHECK(old_chunk_state == CHUNK_ALLOCATED);
if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
ReportAllocTypeMismatch((uptr)ptr, stack,
(AllocType)m->alloc_type, (AllocType)alloc_type);

View File

@ -400,8 +400,10 @@ void WrongFree() {
}
TEST(AddressSanitizer, WrongFreeTest) {
EXPECT_DEATH(WrongFree(),
"ERROR: AddressSanitizer: attempting free.*not malloc");
EXPECT_DEATH(WrongFree(), ASAN_PCRE_DOTALL
"ERROR: AddressSanitizer: attempting free.*not malloc"
".*is located 4 bytes inside of 400-byte region"
".*allocated by thread");
}
void DoubleFree() {