summaryrefslogtreecommitdiff
path: root/libsanitizer/asan
diff options
context:
space:
mode:
authorkcc <kcc@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-05 09:18:38 +0000
committerkcc <kcc@138bc75d-0d04-0410-961f-82ee72b054a4>2013-12-05 09:18:38 +0000
commit4fc7b5acfc1d42a0701c8fff726a3ebe7f563dd9 (patch)
tree20d85354103063e38b162a6a90b7ae51fb4b6104 /libsanitizer/asan
parent50e6c257ee5ad435e3a736a1375ccc7639fd9244 (diff)
downloadgcc-4fc7b5acfc1d42a0701c8fff726a3ebe7f563dd9.tar.gz
libsanitizer merge from upstream r196090
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205695 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libsanitizer/asan')
-rw-r--r--libsanitizer/asan/asan_allocator.h21
-rw-r--r--libsanitizer/asan/asan_allocator2.cc71
-rw-r--r--libsanitizer/asan/asan_dll_thunk.cc2
-rw-r--r--libsanitizer/asan/asan_fake_stack.cc16
-rw-r--r--libsanitizer/asan/asan_fake_stack.h2
-rw-r--r--libsanitizer/asan/asan_flags.h10
-rw-r--r--libsanitizer/asan/asan_globals.cc6
-rw-r--r--libsanitizer/asan/asan_interceptors.cc48
-rw-r--r--libsanitizer/asan/asan_internal.h2
-rw-r--r--libsanitizer/asan/asan_linux.cc6
-rw-r--r--libsanitizer/asan/asan_mac.cc10
-rw-r--r--libsanitizer/asan/asan_malloc_linux.cc5
-rw-r--r--libsanitizer/asan/asan_malloc_win.cc5
-rw-r--r--libsanitizer/asan/asan_poisoning.cc53
-rw-r--r--libsanitizer/asan/asan_poisoning.h3
-rw-r--r--libsanitizer/asan/asan_posix.cc15
-rw-r--r--libsanitizer/asan/asan_report.cc100
-rw-r--r--libsanitizer/asan/asan_report.h6
-rw-r--r--libsanitizer/asan/asan_rtl.cc61
-rw-r--r--libsanitizer/asan/asan_stack.cc7
-rw-r--r--libsanitizer/asan/asan_stack.h30
-rw-r--r--libsanitizer/asan/asan_stats.h4
-rw-r--r--libsanitizer/asan/asan_thread.cc53
-rw-r--r--libsanitizer/asan/asan_thread.h24
-rw-r--r--libsanitizer/asan/asan_win.cc3
25 files changed, 344 insertions, 219 deletions
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index 1f83dcd6780..763f4a58ef9 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -33,10 +33,11 @@ void InitializeAllocator();
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid() { return chunk_ != 0; }
- uptr Beg(); // first byte of user memory.
- uptr End(); // last byte of user memory.
- uptr UsedSize(); // size requested by the user.
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
void GetAllocStack(StackTrace *stack);
@@ -88,16 +89,12 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
};
struct AsanThreadLocalMallocStorage {
- explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
- { }
- AsanThreadLocalMallocStorage() {
- CHECK(REAL(memset));
- REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
- }
-
uptr quarantine_cache[16];
uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ AsanThreadLocalMallocStorage() {}
};
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
@@ -112,7 +109,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack);
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
void asan_mz_force_lock();
diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc
index 34aad11ed75..b9d66dc7a4a 100644
--- a/libsanitizer/asan/asan_allocator2.cc
+++ b/libsanitizer/asan/asan_allocator2.cc
@@ -92,7 +92,7 @@ AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
static Allocator allocator;
static const uptr kMaxAllowedMallocSize =
- FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
+ FIRST_32_SECOND_64(3UL << 30, 64UL << 30);
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
@@ -184,14 +184,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16);
struct AsanChunk: ChunkBase {
uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
- uptr UsedSize() {
+ uptr UsedSize(bool locked_version = false) {
if (user_requested_size != SizeClassMap::kMaxSize)
return user_requested_size;
- return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg()));
- }
- void *AllocBeg() {
- if (from_memalign)
+ return *reinterpret_cast<uptr *>(
+ allocator.GetMetaData(AllocBeg(locked_version)));
+ }
+ void *AllocBeg(bool locked_version = false) {
+ if (from_memalign) {
+ if (locked_version)
+ return allocator.GetBlockBeginFastLocked(
+ reinterpret_cast<void *>(this));
return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
+ }
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// If we don't use stack depot, we store the alloc/free stack traces
@@ -211,11 +216,14 @@ struct AsanChunk: ChunkBase {
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
return (available - kChunkHeader2Size) / sizeof(u32);
}
- bool AddrIsInside(uptr addr) {
- return (addr >= Beg()) && (addr < Beg() + UsedSize());
+ bool AddrIsInside(uptr addr, bool locked_version = false) {
+ return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
};
+bool AsanChunkView::IsValid() {
+ return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE;
+}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
@@ -226,25 +234,16 @@ static void GetStackTraceFromId(u32 id, StackTrace *stack) {
CHECK(id);
uptr size = 0;
const uptr *trace = StackDepotGet(id, &size);
- CHECK_LT(size, kStackTraceMax);
- internal_memcpy(stack->trace, trace, sizeof(uptr) * size);
- stack->size = size;
+ CHECK(trace);
+ stack->CopyFrom(trace, size);
}
void AsanChunkView::GetAllocStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->alloc_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(),
- chunk_->AllocStackSize());
+ GetStackTraceFromId(chunk_->alloc_context_id, stack);
}
void AsanChunkView::GetFreeStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->free_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(),
- chunk_->FreeStackSize());
+ GetStackTraceFromId(chunk_->free_context_id, stack);
}
struct QuarantineCallback;
@@ -390,12 +389,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
- if (fl.use_stack_depot) {
- m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->alloc_context_id = 0;
- StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize());
- }
+ m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
// Unpoison the bulk of the memory region.
@@ -404,7 +398,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
// Deal with the end of the region if size is not aligned to granularity.
if (size != size_rounded_down_to_granularity && fl.poison_heap) {
u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
- *shadow = size & (SHADOW_GRANULARITY - 1);
+ *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
}
AsanStats &thread_stats = GetCurrentThreadStats();
@@ -463,12 +457,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
- if (flags()->use_stack_depot) {
- m->free_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->free_context_id = 0;
- StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
- }
+ m->free_context_id = StackDepotPut(stack->trace, stack->size);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -673,12 +662,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
- CHECK(stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
if (ptr == 0) return 0;
uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr));
- if (flags()->check_malloc_usable_size && (usable_size == 0))
- ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
+ if (flags()->check_malloc_usable_size && (usable_size == 0)) {
+ GET_STACK_TRACE_FATAL(pc, bp);
+ ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
+ }
return usable_size;
}
@@ -718,7 +708,8 @@ uptr PointsIntoChunk(void* p) {
__asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
if (!m) return 0;
uptr chunk = m->Beg();
- if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
+ m->AddrIsInside(addr, /*locked_version=*/true))
return chunk;
return 0;
}
@@ -751,7 +742,7 @@ void LsanMetadata::set_tag(ChunkTag value) {
uptr LsanMetadata::requested_size() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
- return m->UsedSize();
+ return m->UsedSize(/*locked_version=*/true);
}
u32 LsanMetadata::stack_trace_id() const {
diff --git a/libsanitizer/asan/asan_dll_thunk.cc b/libsanitizer/asan/asan_dll_thunk.cc
index 26e19441523..19c31f0def8 100644
--- a/libsanitizer/asan/asan_dll_thunk.cc
+++ b/libsanitizer/asan/asan_dll_thunk.cc
@@ -130,6 +130,8 @@ extern "C" {
}
}
+WRAP_V_V(__asan_handle_no_return)
+
WRAP_V_W(__asan_report_store1)
WRAP_V_W(__asan_report_store2)
WRAP_V_W(__asan_report_store4)
diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc
index b9cce88f34f..cf4122472ef 100644
--- a/libsanitizer/asan/asan_fake_stack.cc
+++ b/libsanitizer/asan/asan_fake_stack.cc
@@ -43,7 +43,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
FakeStack *res = reinterpret_cast<FakeStack *>(
MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
res->stack_size_log_ = stack_size_log;
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
u8 *p = reinterpret_cast<u8 *>(res);
Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
GetCurrentTidOrInvalid(), p,
@@ -132,6 +132,20 @@ NOINLINE void FakeStack::GC(uptr real_stack) {
needs_gc_ = false;
}
+void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ uptr begin = reinterpret_cast<uptr>(ff);
+ callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
+ }
+ }
+}
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
static THREADLOCAL FakeStack *fake_stack_tls;
diff --git a/libsanitizer/asan/asan_fake_stack.h b/libsanitizer/asan/asan_fake_stack.h
index 4287497fd5d..5196025681c 100644
--- a/libsanitizer/asan/asan_fake_stack.h
+++ b/libsanitizer/asan/asan_fake_stack.h
@@ -146,6 +146,8 @@ class FakeStack {
void HandleNoReturn();
void GC(uptr real_stack);
+ void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
+
private:
FakeStack() { }
static const uptr kFlagsOffset = 4096; // This is were the flags begin.
diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h
index c115997ff29..62b5d3215d3 100644
--- a/libsanitizer/asan/asan_flags.h
+++ b/libsanitizer/asan/asan_flags.h
@@ -30,8 +30,6 @@ struct Flags {
// Lower value may reduce memory usage but increase the chance of
// false negatives.
int quarantine_size;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
- int verbosity;
// Size (in bytes) of redzones around heap objects.
// Requirement: redzone >= 32, is a power of two.
int redzone;
@@ -83,6 +81,9 @@ struct Flags {
bool print_legend;
// If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
+ // If set, coverage information will be dumped at shutdown time if the
+ // appropriate instrumentation was enabled.
+ bool coverage;
// By default, disable core dumper on 64-bit - it makes little sense
// to dump 16T+ core.
bool disable_core;
@@ -96,10 +97,11 @@ struct Flags {
// Poison (or not) the heap memory on [de]allocation. Zero value is useful
// for benchmarking the allocator or instrumentator.
bool poison_heap;
+ // If true, poison partially addressable 8-byte aligned words (default=true).
+ // This flag affects heap and global buffers, but not stack buffers.
+ bool poison_partial;
// Report errors on malloc/delete, new/free, new/delete[], etc.
bool alloc_dealloc_mismatch;
- // Use stack depot instead of storing stacks in the redzones.
- bool use_stack_depot;
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
// comparing p1 and p2.
bool strict_memcmp;
diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc
index 96985af71a9..e97850a854a 100644
--- a/libsanitizer/asan/asan_globals.cc
+++ b/libsanitizer/asan/asan_globals.cc
@@ -92,15 +92,13 @@ static void RegisterGlobal(const Global *g) {
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
if (flags()->poison_heap)
PoisonRedZones(*g);
- ListOfGlobals *l =
- (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
+ ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
l->g = g;
l->next = list_of_all_globals;
list_of_all_globals = l;
if (g->has_dynamic_init) {
if (dynamic_init_globals == 0) {
- void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
- dynamic_init_globals = new(mem)
+ dynamic_init_globals = new(allocator_for_globals)
VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
}
DynInitGlobal dyn_global = { *g, false };
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index 72f7aae814a..decbfea5f75 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -92,6 +92,11 @@ void SetThreadName(const char *name) {
asanThreadRegistry().SetThreadName(t->tid(), name);
}
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
} // namespace __asan
// ---------------------- Wrappers ---------------- {{{1
@@ -100,6 +105,19 @@ using namespace __asan; // NOLINT
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+#if !SANITIZER_MAC
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
+ common_flags()->verbosity > 0) \
+ Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif // SANITIZER_MAC
+
+#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
do { \
} while (false)
@@ -124,16 +142,28 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
do { \
} while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
+// But asan does not remember UserId's for threads (pthread_t);
+// and remembers all ever existed threads, so the linear search by UserId
+// can be slow.
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
do { \
+ (void)(p); \
+ (void)(s); \
} while (false)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
do { \
+ (void)(p); \
+ (void)(s); \
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
@@ -144,8 +174,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
-extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
-
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
EnsureMainThreadIDIsCorrect();
@@ -155,7 +183,7 @@ INTERCEPTOR(int, pthread_create, void *thread,
GET_STACK_TRACE_THREAD;
int detached = 0;
if (attr != 0)
- pthread_attr_getdetachstate(attr, &detached);
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(start_routine, arg);
@@ -256,7 +284,7 @@ static void MlockIsUnsupported() {
static bool printed = false;
if (printed) return;
printed = true;
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Printf("INFO: AddressSanitizer ignores "
"mlock/mlockall/munlock/munlockall\n");
}
@@ -645,16 +673,6 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
-#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name) do { \
- if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
- Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
- } while (0)
-#else
-// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
-#define ASAN_INTERCEPT_FUNC(name)
-#endif // SANITIZER_MAC
-
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
@@ -767,7 +785,7 @@ void InitializeAsanInterceptors() {
InitializeWindowsInterceptors();
#endif
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Report("AddressSanitizer: libc interceptors initialized\n");
}
}
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index b5b48708090..ede273a7170 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -96,6 +96,7 @@ void StopInitOrderChecking();
void AsanTSDInit(void (*destructor)(void *tsd));
void *AsanTSDGet();
void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
@@ -133,6 +134,7 @@ const int kAsanStackPartialRedzoneMagic = 0xf4;
const int kAsanStackAfterReturnMagic = 0xf5;
const int kAsanInitializationOrderMagic = 0xf6;
const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
const int kAsanStackUseAfterScopeMagic = 0xf8;
const int kAsanGlobalRedzoneMagic = 0xf9;
const int kAsanInternalHeapMagic = 0xfe;
diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc
index 10c6175092b..0692eb1f455 100644
--- a/libsanitizer/asan/asan_linux.cc
+++ b/libsanitizer/asan/asan_linux.cc
@@ -56,6 +56,12 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.arm_pc;
*bp = ucontext->uc_mcontext.arm_fp;
*sp = ucontext->uc_mcontext.arm_sp;
+# elif defined(__hppa__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.sc_iaoq[0];
+ /* GCC uses %r3 whenever a frame pointer is needed. */
+ *bp = ucontext->uc_mcontext.sc_gr[3];
+ *sp = ucontext->uc_mcontext.sc_gr[30];
# elif defined(__x86_64__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index 4b28c1422cd..8d01843afaf 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -172,7 +172,7 @@ void MaybeReexec() {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("exec()-ing the program with\n");
Report("%s=%s\n", kDyldInsertLibraries, new_env);
Report("to enable ASan wrappers.\n");
@@ -309,7 +309,7 @@ extern "C"
void asan_dispatch_call_block_and_release(void *block) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *context = (asan_block_context_t*)block;
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("asan_dispatch_call_block_and_release(): "
"context: %p, pthread_self: %p\n",
block, pthread_self());
@@ -344,7 +344,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
dispatch_function_t func) { \
GET_STACK_TRACE_THREAD; \
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
- if (flags()->verbosity >= 2) { \
+ if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
PRINT_CURRENT_STACK(); \
@@ -362,7 +362,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_after_f: %p\n", asan_ctxt);
PRINT_CURRENT_STACK();
}
@@ -375,7 +375,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
asan_ctxt, pthread_self());
PRINT_CURRENT_STACK();
diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc
index 97691fcd361..e3495cb0900 100644
--- a/libsanitizer/asan/asan_malloc_linux.cc
+++ b/libsanitizer/asan/asan_malloc_linux.cc
@@ -103,8 +103,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
ALIAS("memalign");
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
// We avoid including malloc.h for portability reasons.
diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc
index cabf8cd254c..1f2495ffc50 100644
--- a/libsanitizer/asan/asan_malloc_win.cc
+++ b/libsanitizer/asan/asan_malloc_win.cc
@@ -96,8 +96,9 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
SANITIZER_INTERFACE_ATTRIBUTE
size_t _msize(void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
int _CrtDbgReport(int, const char*, int,
diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc
index b967acded63..86d49909b68 100644
--- a/libsanitizer/asan/asan_poisoning.cc
+++ b/libsanitizer/asan/asan_poisoning.cc
@@ -12,6 +12,7 @@
#include "asan_poisoning.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -66,7 +67,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to poison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -108,7 +109,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to unpoison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -242,13 +243,57 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
void __asan_poison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("poisoning: %p %zx\n", (void*)addr, size);
PoisonAlignedStackMemory(addr, size, true);
}
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("unpoisoning: %p %zx\n", (void*)addr, size);
PoisonAlignedStackMemory(addr, size, false);
}
+
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (common_flags()->verbosity >= 2)
+ Printf("contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end= reinterpret_cast<uptr>(end_p);
+ uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
+ uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+ uptr granularity = SHADOW_GRANULARITY;
+ CHECK(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity));
+ CHECK_LE(end - beg,
+ FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
+
+ uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
+ uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ uptr d2 = RoundUpTo(old_mid, granularity);
+ // Currently we should be in this state:
+ // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
+ // Make a quick sanity check that we are indeed in this state.
+ if (d1 != d2)
+ CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
+ if (a + granularity <= d1)
+ CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ if (d2 + granularity <= c && c <= end)
+ CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ kAsanContiguousContainerOOBMagic);
+
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
+ // New state:
+ // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
+ PoisonShadow(a, b1 - a, 0);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+ if (b1 != b2) {
+ CHECK_EQ(b2 - b1, granularity);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+ }
+}
diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h
index 866c0a57c7e..da79a0ff2e4 100644
--- a/libsanitizer/asan/asan_poisoning.h
+++ b/libsanitizer/asan/asan_poisoning.h
@@ -41,6 +41,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
DCHECK(flags()->poison_heap);
+ bool poison_partial = flags()->poison_partial;
u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
if (i + SHADOW_GRANULARITY <= size) {
@@ -49,7 +50,7 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
} else {
// first size-i bytes are addressable
- *shadow = static_cast<u8>(size - i);
+ *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
}
}
}
diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc
index a210a810036..ac4ec9e0191 100644
--- a/libsanitizer/asan/asan_posix.cc
+++ b/libsanitizer/asan/asan_posix.cc
@@ -1,4 +1,4 @@
-//===-- asan_linux.cc -----------------------------------------------------===//
+//===-- asan_posix.cc -----------------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
@@ -42,7 +42,7 @@ static void MaybeInstallSigaction(int signum,
sigact.sa_flags = SA_SIGINFO;
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("Installed the sigaction for signal %d\n", signum);
}
}
@@ -69,7 +69,7 @@ void SetAlternateSignalStack() {
altstack.ss_flags = 0;
altstack.ss_size = kAltStackSize;
CHECK_EQ(0, sigaltstack(&altstack, 0));
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Report("Alternative stack for T%d set: [%p,%p)\n",
GetCurrentTidOrInvalid(),
altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
@@ -114,6 +114,15 @@ void AsanTSDSet(void *tsd) {
pthread_setspecific(tsd_key, tsd);
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ if (context->destructor_iterations > 1) {
+ context->destructor_iterations--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ AsanThread::TSDDtor(tsd);
+}
} // namespace __asan
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index 8f11ff4eac3..70c4b481a2f 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -18,6 +18,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
namespace __asan {
@@ -71,6 +72,7 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
case kAsanInitializationOrderMagic:
return Cyan();
case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
return Blue();
case kAsanStackUseAfterScopeMagic:
return Magenta();
@@ -117,19 +119,21 @@ static void PrintLegend() {
for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
PrintShadowByte("", i, " ");
Printf("\n");
- PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
- PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
- PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
- PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
- PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
- PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
- PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
- PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
- PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
- PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
- PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
- PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
- PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
+ PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
+ PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
+ PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
+ PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(" Contiguous container OOB:",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
}
static void PrintShadowMemoryForAddress(uptr addr) {
@@ -178,8 +182,8 @@ static bool IsASCII(unsigned char c) {
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
- return (name[0] == '_' && name[1] == 'Z' && &getSymbolizer)
- ? getSymbolizer()->Demangle(name)
+ return (name[0] == '_' && name[1] == 'Z')
+ ? Symbolizer::Get()->Demangle(name)
: name;
}
@@ -412,7 +416,11 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
void DescribeHeapAddress(uptr addr, uptr access_size) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
- if (!chunk.IsValid()) return;
+ if (!chunk.IsValid()) {
+ Printf("AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return;
+ }
DescribeAccessToHeapChunk(chunk, addr, access_size);
CHECK(chunk.AllocTid() != kInvalidTid);
asanThreadRegistry().CheckLocked();
@@ -479,7 +487,9 @@ void DescribeThread(AsanThreadContext *context) {
context->parent_tid,
ThreadNameWithParenthesis(context->parent_tid,
tname, sizeof(tname)));
- PrintStack(&context->stack);
+ uptr stack_size;
+ const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
+ PrintStack(stack_trace, stack_size);
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadContext *parent_context =
@@ -540,22 +550,6 @@ class ScopedInErrorReport {
}
};
-static void ReportSummary(const char *error_type, StackTrace *stack) {
- if (!stack->size) return;
- if (&getSymbolizer && getSymbolizer()->IsAvailable()) {
- AddressInfo ai;
- // Currently, we include the first stack frame into the report summary.
- // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
- uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
- getSymbolizer()->SymbolizeCode(pc, &ai, 1);
- ReportErrorSummary(error_type,
- StripPathPrefix(ai.file,
- common_flags()->strip_path_prefix),
- ai.line, ai.function);
- }
- // FIXME: do we need to print anything at all if there is no symbolizer?
-}
-
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
@@ -565,13 +559,13 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- Printf("AddressSanitizer can not provide additional info.\n");
GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
- ReportSummary("SEGV", &stack);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary("SEGV", &stack);
}
-void ReportDoubleFree(uptr addr, StackTrace *stack) {
+void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -581,14 +575,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) {
"thread T%d%s:\n",
addr, curr_tid,
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
-
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("double-free", stack);
+ ReportErrorSummary("double-free", &stack);
}
-void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
+void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -598,12 +593,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
"which was not malloc()-ed: %p in thread T%d%s\n", addr,
curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-free", stack);
+ ReportErrorSummary("bad-free", &stack);
}
-void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
static const char *alloc_names[] =
@@ -617,9 +614,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("alloc-dealloc-mismatch", stack);
+ ReportErrorSummary("alloc-dealloc-mismatch", &stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
@@ -634,7 +633,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-malloc_usable_size", stack);
+ ReportErrorSummary("bad-malloc_usable_size", stack);
}
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -647,7 +646,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-__asan_get_allocated_size", stack);
+ ReportErrorSummary("bad-__asan_get_allocated_size", stack);
}
void ReportStringFunctionMemoryRangesOverlap(
@@ -665,7 +664,7 @@ void ReportStringFunctionMemoryRangesOverlap(
PrintStack(stack);
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
- ReportSummary(bug_type, stack);
+ ReportErrorSummary(bug_type, stack);
}
// ----------------------- Mac-specific reports ----------------- {{{1
@@ -747,6 +746,9 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
case kAsanUserPoisonedMemoryMagic:
bug_descr = "use-after-poison";
break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
case kAsanStackUseAfterScopeMagic:
bug_descr = "stack-use-after-scope";
break;
@@ -775,7 +777,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
PrintStack(&stack);
DescribeAddress(addr, access_size);
- ReportSummary(bug_descr, &stack);
+ ReportErrorSummary(bug_descr, &stack);
PrintShadowMemoryForAddress(addr);
}
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index afe7673304c..e4c756e557f 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -31,9 +31,9 @@ void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
-void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 67327611e84..537d40612aa 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -49,6 +49,8 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
+ if (flags()->coverage)
+ __sanitizer_cov_dump();
if (death_callback)
death_callback();
if (flags()->abort_on_error)
@@ -86,11 +88,11 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
}
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ CHECK((uptr)cf->malloc_context_size <= kStackTraceMax);
ParseFlag(str, &f->quarantine_size, "quarantine_size");
- ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->redzone, "redzone");
CHECK_GE(f->redzone, 16);
CHECK(IsPowerOfTwo(f->redzone));
@@ -119,32 +121,25 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->print_stats, "print_stats");
ParseFlag(str, &f->print_legend, "print_legend");
ParseFlag(str, &f->atexit, "atexit");
+ ParseFlag(str, &f->coverage, "coverage");
ParseFlag(str, &f->disable_core, "disable_core");
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
ParseFlag(str, &f->poison_heap, "poison_heap");
+ ParseFlag(str, &f->poison_partial, "poison_partial");
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
- ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
ParseFlag(str, &f->strict_init_order, "strict_init_order");
}
void InitializeFlags(Flags *f, const char *env) {
CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
- cf->symbolize = true;
cf->malloc_context_size = kDefaultMallocContextSize;
- cf->fast_unwind_on_fatal = false;
- cf->fast_unwind_on_malloc = true;
- cf->strip_path_prefix = "";
- cf->handle_ioctl = false;
- cf->log_path = 0;
- cf->detect_leaks = false;
- cf->leak_check_at_exit = true;
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
- f->verbosity = 0;
f->redzone = 16;
f->debug = false;
f->report_globals = 1;
@@ -168,14 +163,15 @@ void InitializeFlags(Flags *f, const char *env) {
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
+ f->coverage = false;
f->disable_core = (SANITIZER_WORDSIZE == 64);
f->allow_reexec = true;
f->print_full_thread_history = true;
f->poison_heap = true;
+ f->poison_partial = true;
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
// TODO(glider,timurrrr): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
- f->use_stack_depot = true;
f->strict_memcmp = true;
f->strict_init_order = false;
@@ -184,7 +180,7 @@ void InitializeFlags(Flags *f, const char *env) {
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
- if (flags()->verbosity) {
+ if (cf->verbosity) {
Report("Using the defaults from __asan_default_options: %s\n",
MaybeCallAsanDefaultOptions());
}
@@ -200,10 +196,10 @@ void InitializeFlags(Flags *f, const char *env) {
}
#endif
- if (cf->detect_leaks && !f->use_stack_depot) {
- Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
- SanitizerToolName);
- cf->detect_leaks = false;
+ // Make "strict_init_order" imply "check_initialization_order".
+ // TODO(samsonov): Use a single runtime flag for an init-order checker.
+ if (f->strict_init_order) {
+ f->check_initialization_order = true;
}
}
@@ -462,7 +458,7 @@ void __asan_init() {
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
- if (flags()->verbosity && options) {
+ if (common_flags()->verbosity && options) {
Report("Parsed ASAN_OPTIONS: %s\n", options);
}
@@ -472,11 +468,6 @@ void __asan_init() {
// Setup internal allocator callback.
SetLowLevelAllocateCallback(OnLowLevelAllocate);
- if (flags()->atexit) {
- Atexit(asan_atexit);
- }
-
- // interceptors
InitializeAsanInterceptors();
ReplaceSystemMalloc();
@@ -495,7 +486,7 @@ void __asan_init() {
}
#endif
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
PrintAddressSpaceLayout();
if (flags()->disable_core) {
@@ -531,17 +522,18 @@ void __asan_init() {
Die();
}
+ AsanTSDInit(PlatformTSDDtor);
InstallSignalHandlers();
- AsanTSDInit(AsanThread::TSDDtor);
// Allocator should be initialized before starting external symbolizer, as
// fork() on Mac locks the allocator.
InitializeAllocator();
// Start symbolizer process if necessary.
- if (common_flags()->symbolize && &getSymbolizer) {
- getSymbolizer()
- ->InitializeExternal(common_flags()->external_symbolizer_path);
+ if (common_flags()->symbolize) {
+ Symbolizer::Init(common_flags()->external_symbolizer_path);
+ } else {
+ Symbolizer::Disable();
}
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
@@ -549,6 +541,13 @@ void __asan_init() {
asan_inited = 1;
asan_init_is_running = false;
+ if (flags()->atexit)
+ Atexit(asan_atexit);
+
+ if (flags()->coverage)
+ Atexit(__sanitizer_cov_dump);
+
+ // interceptors
InitTlsSize();
// Create main thread.
@@ -568,7 +567,7 @@ void __asan_init() {
}
#endif // CAN_SANITIZE_LEAKS
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
Report("AddressSanitizer Init done\n");
}
}
diff --git a/libsanitizer/asan/asan_stack.cc b/libsanitizer/asan/asan_stack.cc
index 74952518642..93671a03a92 100644
--- a/libsanitizer/asan/asan_stack.cc
+++ b/libsanitizer/asan/asan_stack.cc
@@ -22,9 +22,12 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
: false;
}
+void PrintStack(const uptr *trace, uptr size) {
+ StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
+}
+
void PrintStack(StackTrace *stack) {
- stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
- common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
+ PrintStack(stack->trace, stack->size);
}
} // namespace __asan
diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
index 3c0ac31f6c6..c929c887d06 100644
--- a/libsanitizer/asan/asan_stack.h
+++ b/libsanitizer/asan/asan_stack.h
@@ -20,6 +20,7 @@
namespace __asan {
void PrintStack(StackTrace *stack);
+void PrintStack(const uptr *trace, uptr size);
} // namespace __asan
@@ -29,19 +30,24 @@ void PrintStack(StackTrace *stack);
#if SANITIZER_WINDOWS
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
StackTrace stack; \
- GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
+ stack.Unwind(max_s, pc, bp, 0, 0, fast)
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- { \
- AsanThread *t; \
- stack.size = 0; \
- if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \
- uptr stack_top = t->stack_top(); \
- uptr stack_bottom = t->stack_bottom(); \
- ScopedUnwinding unwind_scope(t); \
- GetStackTrace(&stack, max_s, pc, bp, stack_top, stack_bottom, fast); \
- } \
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
+ StackTrace stack; \
+ { \
+ AsanThread *t; \
+ stack.size = 0; \
+ if (asan_inited) { \
+ if ((t = GetCurrentThread()) && !t->isUnwinding()) { \
+ uptr stack_top = t->stack_top(); \
+ uptr stack_bottom = t->stack_bottom(); \
+ ScopedUnwinding unwind_scope(t); \
+ stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
+ } else if (t == 0 && !fast) { \
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ \
+ stack.Unwind(max_s, pc, bp, 0, 0, false); \
+ } \
+ } \
}
#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/asan/asan_stats.h b/libsanitizer/asan/asan_stats.h
index 2f964f8d052..5b04b1718eb 100644
--- a/libsanitizer/asan/asan_stats.h
+++ b/libsanitizer/asan/asan_stats.h
@@ -45,9 +45,9 @@ struct AsanStats {
uptr malloc_large;
uptr malloc_small_slow;
- // Ctor for global AsanStats (accumulated stats and main thread stats).
+ // Ctor for global AsanStats (accumulated stats for dead threads).
explicit AsanStats(LinkerInitialized) { }
- // Default ctor for thread-local stats.
+ // Creates empty stats.
AsanStats();
void Print(); // Prints formatted stats to stderr.
diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc
index 1da714c6013..5a9c2dddffb 100644
--- a/libsanitizer/asan/asan_thread.cc
+++ b/libsanitizer/asan/asan_thread.cc
@@ -17,6 +17,7 @@
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "lsan/lsan_common.h"
namespace __asan {
@@ -25,9 +26,8 @@ namespace __asan {
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
- if (args->stack) {
- internal_memcpy(&stack, args->stack, sizeof(stack));
- }
+ if (args->stack)
+ stack_id = StackDepotPut(args->stack->trace, args->stack->size);
thread = args->thread;
thread->set_context(this);
}
@@ -41,9 +41,12 @@ void AsanThreadContext::OnFinished() {
static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *asan_thread_registry;
+static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_thread_context;
+
static ThreadContextBase *GetAsanThreadContext(u32 tid) {
- void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
- return new(mem) AsanThreadContext(tid);
+ BlockingMutexLock lock(&mu_for_thread_context);
+ return new(allocator_for_thread_context) AsanThreadContext(tid);
}
ThreadRegistry &asanThreadRegistry() {
@@ -76,24 +79,25 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine,
AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- thread->context_ = 0;
return thread;
}
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
- if (flags()->verbosity >= 1)
+ if (common_flags()->verbosity >= 1)
Report("T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("T%d exited\n", tid());
}
+ malloc_storage().CommitBack();
+ if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
asanThreadRegistry().FinishThread(tid());
FlushToDeadThreadStats(&stats_);
// We also clear the shadow on thread destruction because
@@ -136,7 +140,7 @@ void AsanThread::Init() {
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
ClearShadowForThreadStackAndTLS();
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
int local = 0;
Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
tid(), (void*)stack_bottom_, (void*)stack_top_,
@@ -160,10 +164,14 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) {
}
thread_return_t res = start_routine_(arg_);
- malloc_storage().CommitBack();
- if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
- this->Destroy();
+ // On POSIX systems we defer this to the TSD destructor. LSan will consider
+ // the thread's memory as non-live from the moment we call Destroy(), even
+ // though that memory might contain pointers to heap objects which will be
+ // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+ // the TSD destructors have run might cause false positives in LSan.
+ if (!SANITIZER_POSIX)
+ this->Destroy();
return res;
}
@@ -257,7 +265,7 @@ AsanThread *GetCurrentThread() {
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("SetCurrentThread: %p for thread %p\n",
t->context(), (void*)GetThreadSelf());
}
@@ -286,6 +294,13 @@ void EnsureMainThreadIDIsCorrect() {
if (context && (context->tid == 0))
context->os_id = GetTid();
}
+
+__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+ __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+ __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+ if (!context) return 0;
+ return context->thread;
+}
} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
@@ -293,10 +308,7 @@ namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end) {
- __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
- __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
- if (!context) return false;
- __asan::AsanThread *t = context->thread;
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (!t) return false;
*stack_begin = t->stack_bottom();
*stack_end = t->stack_top();
@@ -308,6 +320,13 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (t && t->has_fake_stack())
+ t->fake_stack()->ForEachFakeFrame(callback, arg);
+}
+
void LockThreadRegistry() {
__asan::asanThreadRegistry().Lock();
}
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index f21971ff430..5a917fa9a3d 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -17,6 +17,7 @@
#include "asan_fake_stack.h"
#include "asan_stack.h"
#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
@@ -34,11 +35,13 @@ class AsanThreadContext : public ThreadContextBase {
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid),
announced(false),
+ destructor_iterations(kPthreadDestructorIterations),
+ stack_id(0),
thread(0) {
- internal_memset(&stack, 0, sizeof(stack));
}
bool announced;
- StackTrace stack;
+ u8 destructor_iterations;
+ u32 stack_id;
AsanThread *thread;
void OnCreated(void *arg);
@@ -46,7 +49,7 @@ class AsanThreadContext : public ThreadContextBase {
};
// AsanThreadContext objects are never freed, so we need many of them.
-COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
@@ -96,14 +99,15 @@ class AsanThread {
// True is this thread is currently unwinding stack (i.e. collecting a stack
// trace). Used to prevent deadlocks on platforms where libc unwinder calls
// malloc internally. See PR17116 for more details.
- bool isUnwinding() const { return unwinding; }
- void setUnwinding(bool b) { unwinding = b; }
+ bool isUnwinding() const { return unwinding_; }
+ void setUnwinding(bool b) { unwinding_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
- AsanThread() : unwinding(false) {}
+ // NOTE: There is no AsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -111,18 +115,18 @@ class AsanThread {
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
- uptr stack_top_;
- uptr stack_bottom_;
+ uptr stack_top_;
+ uptr stack_bottom_;
// stack_size_ == stack_top_ - stack_bottom_;
// It needs to be set in a async-signal-safe manner.
- uptr stack_size_;
+ uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
- bool unwinding;
+ bool unwinding_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc
index ed785b69281..8ffa58faa37 100644
--- a/libsanitizer/asan/asan_win.cc
+++ b/libsanitizer/asan/asan_win.cc
@@ -58,6 +58,9 @@ void AsanTSDSet(void *tsd) {
fake_tsd = tsd;
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThread::TSDDtor(tsd);
+}
// ---------------------- Various stuff ---------------- {{{1
void MaybeReexec() {
// No need to re-exec on Windows.