[asan] make __asan::Deallocate immune to racy double-free (issue #57)
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@154097 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index 3797a09..8c3cc00 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -704,18 +704,22 @@
// Printf("Deallocate %p\n", ptr);
AsanChunk *m = PtrToChunk((uintptr_t)ptr);
- if (m->chunk_state == CHUNK_QUARANTINE) {
+
+ // Flip the state atomically to avoid race on double-free.
+ uint16_t old_chunk_state = AtomicExchange(&m->chunk_state, CHUNK_QUARANTINE);
+
+ if (old_chunk_state == CHUNK_QUARANTINE) {
Report("ERROR: AddressSanitizer attempting double-free on %p:\n", ptr);
stack->PrintStack();
Describe((uintptr_t)ptr, 1);
ShowStatsAndAbort();
- } else if (m->chunk_state != CHUNK_ALLOCATED) {
+ } else if (old_chunk_state != CHUNK_ALLOCATED) {
Report("ERROR: AddressSanitizer attempting free on address which was not"
" malloc()-ed: %p\n", ptr);
stack->PrintStack();
ShowStatsAndAbort();
}
- CHECK(m->chunk_state == CHUNK_ALLOCATED);
+ CHECK(old_chunk_state == CHUNK_ALLOCATED);
CHECK(m->free_tid == AsanThread::kInvalidTid);
CHECK(m->alloc_tid >= 0);
AsanThread *t = asanThreadRegistry().GetCurrent();
@@ -731,7 +735,7 @@
thread_stats.freed += m->used_size;
thread_stats.freed_by_size[m->SizeClass()]++;
- m->chunk_state = CHUNK_QUARANTINE;
+ CHECK(m->chunk_state == CHUNK_QUARANTINE);
if (t) {
AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
CHECK(!m->next);
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 39d3adf..3a25cf2 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -187,6 +187,7 @@
int GetPid();
uintptr_t GetThreadSelf();
int AtomicInc(int *a);
+uint16_t AtomicExchange(uint16_t *a, uint16_t new_val);
// Wrapper for TLS/TSD.
void AsanTSDInit(void (*destructor)(void *tsd));
diff --git a/lib/asan/asan_posix.cc b/lib/asan/asan_posix.cc
index 0ab09e6..03bd057 100644
--- a/lib/asan/asan_posix.cc
+++ b/lib/asan/asan_posix.cc
@@ -152,6 +152,10 @@
#endif
}
+uint16_t AtomicExchange(uint16_t *a, uint16_t new_val) {
+ return __sync_lock_test_and_set(a, new_val);
+}
+
void SortArray(uintptr_t *array, size_t size) {
std::sort(array, array + size);
}
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 94f4d04..baa8268 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -234,6 +234,10 @@
return InterlockedExchangeAdd((LONG*)a, 1) + 1;
}
+uint16_t AtomicExchange(uint16_t *a, uint16_t new_val) {
+ return InterlockedExchange16(a, new_val);
+}
+
const char* AsanGetEnv(const char* name) {
static char env_buffer[32767] = {};