libsanitizer merge from upstream r221802
authorKostya Serebryany <kcc@google.com>
Thu, 13 Nov 2014 20:41:38 +0000 (20:41 +0000)
committerKostya Serebryany <kcc@gcc.gnu.org>
Thu, 13 Nov 2014 20:41:38 +0000 (20:41 +0000)
From-SVN: r217518

98 files changed:
libsanitizer/ChangeLog
libsanitizer/MERGE
libsanitizer/asan/Makefile.am
libsanitizer/asan/Makefile.in
libsanitizer/asan/asan_allocator.h
libsanitizer/asan/asan_allocator2.cc
libsanitizer/asan/asan_debugging.cc
libsanitizer/asan/asan_flags.h
libsanitizer/asan/asan_globals.cc
libsanitizer/asan/asan_interface_internal.h
libsanitizer/asan/asan_internal.h
libsanitizer/asan/asan_mac.cc
libsanitizer/asan/asan_mapping.h
libsanitizer/asan/asan_poisoning.cc
libsanitizer/asan/asan_posix.cc
libsanitizer/asan/asan_report.cc
libsanitizer/asan/asan_report.h
libsanitizer/asan/asan_rtl.cc
libsanitizer/asan/asan_stack.h
libsanitizer/asan/asan_thread.cc
libsanitizer/asan/asan_thread.h
libsanitizer/include/sanitizer/asan_interface.h
libsanitizer/include/sanitizer/common_interface_defs.h
libsanitizer/interception/Makefile.am
libsanitizer/interception/Makefile.in
libsanitizer/interception/interception_win.cc
libsanitizer/libbacktrace/Makefile.am
libsanitizer/libbacktrace/Makefile.in
libsanitizer/lsan/Makefile.am
libsanitizer/lsan/Makefile.in
libsanitizer/lsan/lsan.h
libsanitizer/lsan/lsan_allocator.cc
libsanitizer/lsan/lsan_common.cc
libsanitizer/lsan/lsan_common_linux.cc
libsanitizer/sanitizer_common/Makefile.am
libsanitizer/sanitizer_common/Makefile.in
libsanitizer/sanitizer_common/sanitizer_allocator.h
libsanitizer/sanitizer_common/sanitizer_common.cc
libsanitizer/sanitizer_common/sanitizer_common.h
libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
libsanitizer/sanitizer_common/sanitizer_flags.cc
libsanitizer/sanitizer_common/sanitizer_flags.h
libsanitizer/sanitizer_common/sanitizer_mac.cc
libsanitizer/sanitizer_common/sanitizer_mac.h
libsanitizer/sanitizer_common/sanitizer_platform.h
libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
libsanitizer/sanitizer_common/sanitizer_posix.cc
libsanitizer/sanitizer_common/sanitizer_printf.cc
libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
libsanitizer/sanitizer_common/sanitizer_stackdepot.h
libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h
libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
libsanitizer/sanitizer_common/sanitizer_stacktrace.h
libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_symbolizer.h
libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc
libsanitizer/sanitizer_common/sanitizer_win.cc
libsanitizer/tsan/Makefile.am
libsanitizer/tsan/Makefile.in
libsanitizer/tsan/tsan_defs.h
libsanitizer/tsan/tsan_fd.cc
libsanitizer/tsan/tsan_flags.cc
libsanitizer/tsan/tsan_interceptors.cc
libsanitizer/tsan/tsan_interface_ann.cc
libsanitizer/tsan/tsan_interface_atomic.cc
libsanitizer/tsan/tsan_interface_java.cc
libsanitizer/tsan/tsan_mman.cc
libsanitizer/tsan/tsan_mman.h
libsanitizer/tsan/tsan_platform.h
libsanitizer/tsan/tsan_platform_linux.cc
libsanitizer/tsan/tsan_platform_mac.cc
libsanitizer/tsan/tsan_platform_windows.cc
libsanitizer/tsan/tsan_report.cc
libsanitizer/tsan/tsan_report.h
libsanitizer/tsan/tsan_rtl.cc
libsanitizer/tsan/tsan_rtl.h
libsanitizer/tsan/tsan_rtl_amd64.S
libsanitizer/tsan/tsan_rtl_mutex.cc
libsanitizer/tsan/tsan_rtl_report.cc
libsanitizer/tsan/tsan_stack_trace.cc
libsanitizer/tsan/tsan_stack_trace.h
libsanitizer/tsan/tsan_suppressions.cc
libsanitizer/tsan/tsan_symbolize.cc
libsanitizer/tsan/tsan_trace.h
libsanitizer/ubsan/Makefile.am
libsanitizer/ubsan/Makefile.in
libsanitizer/ubsan/ubsan_diag.cc
libsanitizer/ubsan/ubsan_handlers.cc
libsanitizer/ubsan/ubsan_type_hash.cc

index 0df34af..52d969d 100644 (file)
@@ -1,3 +1,26 @@
+2014-11-13  Kostya Serebryany  <kcc@google.com>
+
+       * All source files: Merge from upstream r221802.
+       * sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
+       (LibbacktraceSymbolizer::SymbolizeData): Replace 'address'
+       with 'start' to follow the new interface.
+       * asan/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * interception/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * libbacktrace/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * lsan/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * sanitizer_common/Makefile.am (sanitizer_common_files): Added new
+       files.
+       (AM_CXXFLAGS): Added -std=c++11.
+       * tsan/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * ubsan/Makefile.am (AM_CXXFLAGS): Added -std=c++11.
+       * asan/Makefile.in: Regenerate.
+       * interception/Makefile.in: Regenerate.
+       * libbacktrace/Makefile.in: Regenerate.
+       * lsan/Makefile.in: Regenerate.
+       * sanitizer_common/Makefile.in: Regenerate.
+       * tsan/Makefile.in: Regenerate.
+       * ubsan/Makefile.in: Regenerate.
+
 2014-11-11  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR target/63610
index 48a7f26..ef893cb 100644 (file)
@@ -1,4 +1,4 @@
-218156
+221802
 
 The first line of this file holds the svn revision number of the
 last merge done from the master library sources.
index d499c72..b421776 100644 (file)
@@ -9,6 +9,7 @@ DEFS += -DMAC_INTERPOSE_FUNCTIONS -DMISSING_BLOCKS_SUPPORT
 endif
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -fno-ipa-icf
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 
 toolexeclib_LTLIBRARIES = libasan.la
index 00a614b..54ae86a 100644 (file)
@@ -270,7 +270,7 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
        -Wno-variadic-macros -fno-ipa-icf \
-       $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+       $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11
 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libasan.la
 nodist_toolexeclib_HEADERS = libasan_preinit.o
index 567b368..d2f30af 100644 (file)
@@ -43,8 +43,8 @@ class AsanChunkView {
   uptr AllocTid();
   uptr FreeTid();
   bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
-  void GetAllocStack(StackTrace *stack);
-  void GetFreeStack(StackTrace *stack);
+  StackTrace GetAllocStack();
+  StackTrace GetFreeStack();
   bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
     if (addr >= Beg() && (addr + access_size) <= End()) {
       *offset = addr - Beg();
@@ -137,20 +137,20 @@ struct AsanThreadLocalMallocStorage {
   AsanThreadLocalMallocStorage() {}
 };
 
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
                     AllocType alloc_type);
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type);
-void asan_sized_free(void *ptr, uptr size, StackTrace *stack,
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
                      AllocType alloc_type);
 
-void *asan_malloc(uptr size, StackTrace *stack);
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack);
-void *asan_realloc(void *p, uptr size, StackTrace *stack);
-void *asan_valloc(uptr size, StackTrace *stack);
-void *asan_pvalloc(uptr size, StackTrace *stack);
+void *asan_malloc(uptr size, BufferedStackTrace *stack);
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
+void *asan_valloc(uptr size, BufferedStackTrace *stack);
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                          StackTrace *stack);
+                        BufferedStackTrace *stack);
 uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
 
 uptr asan_mz_size(const void *ptr);
index 78c1ec1..33d9fea 100644 (file)
@@ -180,20 +180,19 @@ uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
 uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
 uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
 
-static void GetStackTraceFromId(u32 id, StackTrace *stack) {
+static StackTrace GetStackTraceFromId(u32 id) {
   CHECK(id);
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(id, &size);
-  CHECK(trace);
-  stack->CopyFrom(trace, size);
+  StackTrace res = StackDepotGet(id);
+  CHECK(res.trace);
+  return res;
 }
 
-void AsanChunkView::GetAllocStack(StackTrace *stack) {
-  GetStackTraceFromId(chunk_->alloc_context_id, stack);
+StackTrace AsanChunkView::GetAllocStack() {
+  return GetStackTraceFromId(chunk_->alloc_context_id);
 }
 
-void AsanChunkView::GetFreeStack(StackTrace *stack) {
-  GetStackTraceFromId(chunk_->free_context_id, stack);
+StackTrace AsanChunkView::GetFreeStack() {
+  return GetStackTraceFromId(chunk_->free_context_id);
 }
 
 struct QuarantineCallback;
@@ -261,7 +260,7 @@ void ReInitializeAllocator() {
   quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
 }
 
-static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
+static void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
                       AllocType alloc_type, bool can_fill) {
   if (UNLIKELY(!asan_inited))
     AsanInitFromRtl();
@@ -353,7 +352,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
     meta[1] = chunk_beg;
   }
 
-  m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
+  m->alloc_context_id = StackDepotPut(*stack);
 
   uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
   // Unpoison the bulk of the memory region.
@@ -389,15 +388,16 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
   return res;
 }
 
-static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) {
+static void ReportInvalidFree(void *ptr, u8 chunk_state,
+                              BufferedStackTrace *stack) {
   if (chunk_state == CHUNK_QUARANTINE)
     ReportDoubleFree((uptr)ptr, stack);
   else
     ReportFreeNotMalloced((uptr)ptr, stack);
 }
 
-static void AtomicallySetQuarantineFlag(AsanChunk *m,
-                                        void *ptr, StackTrace *stack) {
+static void AtomicallySetQuarantineFlag(AsanChunk *m, void *ptr,
+                                        BufferedStackTrace *stack) {
   u8 old_chunk_state = CHUNK_ALLOCATED;
   // Flip the chunk_state atomically to avoid race on double-free.
   if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state,
@@ -408,8 +408,8 @@ static void AtomicallySetQuarantineFlag(AsanChunk *m,
 
 // Expects the chunk to already be marked as quarantined by using
 // AtomicallySetQuarantineFlag.
-static void QuarantineChunk(AsanChunk *m, void *ptr,
-                            StackTrace *stack, AllocType alloc_type) {
+static void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
+                            AllocType alloc_type) {
   CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
 
   if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch)
@@ -421,7 +421,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
     CHECK_EQ(m->free_tid, kInvalidTid);
   AsanThread *t = GetCurrentThread();
   m->free_tid = t ? t->tid() : 0;
-  m->free_context_id = StackDepotPut(stack->trace, stack->size);
+  m->free_context_id = StackDepotPut(*stack);
   // Poison the region.
   PoisonShadow(m->Beg(),
                RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -445,7 +445,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
   }
 }
 
-static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack,
+static void Deallocate(void *ptr, uptr delete_size, BufferedStackTrace *stack,
                        AllocType alloc_type) {
   uptr p = reinterpret_cast<uptr>(ptr);
   if (p == 0) return;
@@ -462,7 +462,8 @@ static void Deallocate(void *ptr, uptr delete_size, StackTrace *stack,
   QuarantineChunk(m, ptr, stack, alloc_type);
 }
 
-static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
+static void *Reallocate(void *old_ptr, uptr new_size,
+                        BufferedStackTrace *stack) {
   CHECK(old_ptr && new_size);
   uptr p = reinterpret_cast<uptr>(old_ptr);
   uptr chunk_beg = p - kChunkHeaderSize;
@@ -575,25 +576,25 @@ void PrintInternalAllocatorStats() {
   allocator.PrintStats();
 }
 
-void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
                     AllocType alloc_type) {
   return Allocate(size, alignment, stack, alloc_type, true);
 }
 
-void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) {
+void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
   Deallocate(ptr, 0, stack, alloc_type);
 }
 
-void asan_sized_free(void *ptr, uptr size, StackTrace *stack,
+void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
                      AllocType alloc_type) {
   Deallocate(ptr, size, stack, alloc_type);
 }
 
-void *asan_malloc(uptr size, StackTrace *stack) {
+void *asan_malloc(uptr size, BufferedStackTrace *stack) {
   return Allocate(size, 8, stack, FROM_MALLOC, true);
 }
 
-void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
   if (CallocShouldReturnNullDueToOverflow(size, nmemb))
     return AllocatorReturnNull();
   void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
@@ -604,7 +605,7 @@ void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
   return ptr;
 }
 
-void *asan_realloc(void *p, uptr size, StackTrace *stack) {
+void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
   if (p == 0)
     return Allocate(size, 8, stack, FROM_MALLOC, true);
   if (size == 0) {
@@ -614,11 +615,11 @@ void *asan_realloc(void *p, uptr size, StackTrace *stack) {
   return Reallocate(p, size, stack);
 }
 
-void *asan_valloc(uptr size, StackTrace *stack) {
+void *asan_valloc(uptr size, BufferedStackTrace *stack) {
   return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
 }
 
-void *asan_pvalloc(uptr size, StackTrace *stack) {
+void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
   uptr PageSize = GetPageSizeCached();
   size = RoundUpTo(size, PageSize);
   if (size == 0) {
@@ -629,7 +630,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack) {
 }
 
 int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
-                        StackTrace *stack) {
+                        BufferedStackTrace *stack) {
   void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true);
   CHECK(IsAligned((uptr)ptr, alignment));
   *memptr = ptr;
index 302574d..3efad65 100644 (file)
 #include "asan_flags.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "asan_report.h"
 #include "asan_thread.h"
 
 namespace __asan {
 
+void GetInfoForStackVar(uptr addr, AddressDescription *descr, AsanThread *t) {
+  descr->name[0] = 0;
+  descr->region_address = 0;
+  descr->region_size = 0;
+  descr->region_kind = "stack";
+
+  AsanThread::StackFrameAccess access;
+  if (!t->GetStackFrameAccessByAddr(addr, &access))
+    return;
+  InternalMmapVector<StackVarDescr> vars(16);
+  if (!ParseFrameDescription(access.frame_descr, &vars)) {
+    return;
+  }
+
+  for (uptr i = 0; i < vars.size(); i++) {
+    if (access.offset <= vars[i].beg + vars[i].size) {
+      internal_strncat(descr->name, vars[i].name_pos,
+                       Min(descr->name_size, vars[i].name_len));
+      descr->region_address = addr - (access.offset - vars[i].beg);
+      descr->region_size = vars[i].size;
+      return;
+    }
+  }
+}
+
+void GetInfoForHeapAddress(uptr addr, AddressDescription *descr) {
+  AsanChunkView chunk = FindHeapChunkByAddress(addr);
+
+  descr->name[0] = 0;
+  descr->region_address = 0;
+  descr->region_size = 0;
+
+  if (!chunk.IsValid()) {
+    descr->region_kind = "heap-invalid";
+    return;
+  }
+
+  descr->region_address = chunk.Beg();
+  descr->region_size = chunk.UsedSize();
+  descr->region_kind = "heap";
+}
+
+void AsanLocateAddress(uptr addr, AddressDescription *descr) {
+  if (DescribeAddressIfShadow(addr, descr, /* print */ false)) {
+    return;
+  }
+  if (GetInfoForAddressIfGlobal(addr, descr)) {
+    return;
+  }
+  asanThreadRegistry().Lock();
+  AsanThread *thread = FindThreadByStackAddress(addr);
+  asanThreadRegistry().Unlock();
+  if (thread) {
+    GetInfoForStackVar(addr, descr, thread);
+    return;
+  }
+  GetInfoForHeapAddress(addr, descr);
+}
+
 uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
                   bool alloc_stack) {
   AsanChunkView chunk = FindHeapChunkByAddress(addr);
   if (!chunk.IsValid()) return 0;
 
-  StackTrace stack;
+  StackTrace stack(nullptr, 0);
   if (alloc_stack) {
     if (chunk.AllocTid() == kInvalidTid) return 0;
-    chunk.GetAllocStack(&stack);
+    stack = chunk.GetAllocStack();
     if (thread_id) *thread_id = chunk.AllocTid();
   } else {
     if (chunk.FreeTid() == kInvalidTid) return 0;
-    chunk.GetFreeStack(&stack);
+    stack = chunk.GetFreeStack();
     if (thread_id) *thread_id = chunk.FreeTid();
   }
 
   if (trace && size) {
-    if (size > kStackTraceMax)
-      size = kStackTraceMax;
-    if (size > stack.size)
-      size = stack.size;
+    size = Min(size, Min(stack.size, kStackTraceMax));
     for (uptr i = 0; i < size; i++)
       trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
 
@@ -54,6 +111,16 @@ uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
 using namespace __asan;
 
 SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+                                  uptr *region_address, uptr *region_size) {
+  AddressDescription descr = { name, name_size, 0, 0, 0 };
+  AsanLocateAddress(addr, &descr);
+  if (region_address) *region_address = descr.region_address;
+  if (region_size) *region_size = descr.region_size;
+  return descr.region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
 uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
   return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
 }
index 2f155eb..0b6a985 100644 (file)
@@ -63,6 +63,7 @@ struct Flags {
   int detect_invalid_pointer_pairs;
   bool detect_container_overflow;
   int detect_odr_violation;
+  bool dump_instruction_bytes;
 };
 
 extern Flags asan_flags_dont_use_directly;
index 15c1886..ee2ecdc 100644 (file)
@@ -69,6 +69,14 @@ ALWAYS_INLINE void PoisonRedZones(const Global &g) {
   }
 }
 
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
+  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
+  if (addr >= g.beg + g.size_with_redzone) return false;
+  return true;
+}
+
 static void ReportGlobal(const Global &g, const char *prefix) {
   Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
          prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
@@ -80,19 +88,45 @@ static void ReportGlobal(const Global &g, const char *prefix) {
   }
 }
 
-bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+static bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool print,
+                                      Global *output_global) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
   bool res = false;
   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
-    if (flags()->report_globals >= 2)
-      ReportGlobal(g, "Search");
-    res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    if (print) {
+      if (flags()->report_globals >= 2)
+        ReportGlobal(g, "Search");
+      res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    } else {
+      if (IsAddressNearGlobal(addr, g)) {
+        CHECK(output_global);
+        *output_global = g;
+        return true;
+      }
+    }
   }
   return res;
 }
 
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+  return DescribeOrGetInfoIfGlobal(addr, size, /* print */ true,
+                                   /* output_global */ nullptr);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr) {
+  Global g = {};
+  if (DescribeOrGetInfoIfGlobal(addr, /* size */ 1, /* print */ false, &g)) {
+    internal_strncpy(descr->name, g.name, descr->name_size);
+    descr->region_address = g.beg;
+    descr->region_size = g.size;
+    descr->region_kind = "global";
+    return true;
+  }
+  return false;
+}
+
 u32 FindRegistrationSite(const Global *g) {
   CHECK(global_registration_site_vector);
   for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
@@ -181,7 +215,7 @@ using namespace __asan;  // NOLINT
 void __asan_register_globals(__asan_global *globals, uptr n) {
   if (!flags()->report_globals) return;
   GET_STACK_TRACE_FATAL_HERE;
-  u32 stack_id = StackDepotPut(stack.trace, stack.size);
+  u32 stack_id = StackDepotPut(stack);
   BlockingMutexLock lock(&mu_for_globals);
   if (!global_registration_site_vector)
     global_registration_site_vector =
index 1a3b33f..939327e 100644 (file)
@@ -89,6 +89,28 @@ extern "C" {
   void __asan_describe_address(uptr addr);
 
   SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_report_present();
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_pc();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_bp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_sp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_address();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_get_report_access_type();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_access_size();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_get_report_description();
+
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+                                     uptr *region_address, uptr *region_size);
+
+  SANITIZER_INTERFACE_ATTRIBUTE
   uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
                               u32 *thread_id);
 
@@ -149,6 +171,10 @@ extern "C" {
   void __asan_poison_cxx_array_cookie(uptr p);
   SANITIZER_INTERFACE_ATTRIBUTE
   uptr __asan_load_cxx_array_cookie(uptr *p);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_poison_intra_object_redzone(uptr p, uptr size);
+  SANITIZER_INTERFACE_ATTRIBUTE
+  void __asan_unpoison_intra_object_redzone(uptr p, uptr size);
 }  // extern "C"
 
 #endif  // ASAN_INTERFACE_INTERNAL_H
index 9473bf6..8911575 100644 (file)
@@ -133,6 +133,7 @@ const int kAsanStackUseAfterScopeMagic = 0xf8;
 const int kAsanGlobalRedzoneMagic = 0xf9;
 const int kAsanInternalHeapMagic = 0xfe;
 const int kAsanArrayCookieMagic = 0xac;
+const int kAsanIntraObjectRedzone = 0xbb;
 
 static const uptr kCurrentStackFrameMagic = 0x41B58AB3;
 static const uptr kRetiredStackFrameMagic = 0x45E0360E;
index e4c71ce..70823bd 100644 (file)
@@ -295,7 +295,7 @@ using namespace __asan;  // NOLINT
 // The caller retains control of the allocated context.
 extern "C"
 asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
-                                         StackTrace *stack) {
+                                         BufferedStackTrace *stack) {
   asan_block_context_t *asan_ctxt =
       (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
   asan_ctxt->block = ctxt;
index a1f84e2..907704d 100644 (file)
 // || `[0x00000000, 0x1fffffff]` || LowMem     ||
 //
 // Default Linux/MIPS mapping:
-// || `[0x2aaa8000, 0xffffffff]` || HighMem    ||
-// || `[0x0fffd000, 0x2aaa7fff]` || HighShadow ||
-// || `[0x0bffd000, 0x0fffcfff]` || ShadowGap  ||
-// || `[0x0aaa8000, 0x0bffcfff]` || LowShadow  ||
-// || `[0x00000000, 0x0aaa7fff]` || LowMem     ||
+// || `[0x2aaa0000, 0xffffffff]` || HighMem    ||
+// || `[0x0fff4000, 0x2aa9ffff]` || HighShadow ||
+// || `[0x0bff4000, 0x0fff3fff]` || ShadowGap  ||
+// || `[0x0aaa0000, 0x0bff3fff]` || LowShadow  ||
+// || `[0x00000000, 0x0aa9ffff]` || LowMem     ||
 //
 // Shadow mapping on FreeBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
 // || `[0x500000000000, 0x7fffffffffff]` || HighMem    ||
@@ -84,7 +84,8 @@ static const u64 kIosShadowOffset32 = 1ULL << 30;  // 0x40000000
 static const u64 kDefaultShadowOffset64 = 1ULL << 44;
 static const u64 kDefaultShort64bitShadowOffset = 0x7FFF8000;  // < 2G.
 static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
-static const u64 kMIPS32_ShadowOffset32 = 0x0aaa8000;
+static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000;
+static const u64 kMIPS64_ShadowOffset64 = 1ULL << 36;
 static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
 static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30;  // 0x40000000
 static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46;  // 0x400000000000
@@ -114,6 +115,8 @@ static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46;  // 0x400000000000
 #    define SHADOW_OFFSET kFreeBSD_ShadowOffset64
 #  elif SANITIZER_MAC
 #   define SHADOW_OFFSET kDefaultShadowOffset64
+#  elif defined(__mips64)
+#   define SHADOW_OFFSET kMIPS64_ShadowOffset64
 #  else
 #   define SHADOW_OFFSET kDefaultShort64bitShadowOffset
 #  endif
index 65f6cf0..c0f3991 100644 (file)
@@ -59,6 +59,27 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
     FlushUnneededShadowMemory(shadow_beg, shadow_end - shadow_beg);
 }
 
+void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
+  uptr end = ptr + size;
+  if (common_flags()->verbosity) {
+    Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n",
+           poison ? "" : "un", ptr, end, size);
+    if (common_flags()->verbosity >= 2)
+      PRINT_CURRENT_STACK();
+  }
+  CHECK(size);
+  CHECK_LE(size, 4096);
+  CHECK(IsAligned(end, SHADOW_GRANULARITY));
+  if (!IsAligned(ptr, SHADOW_GRANULARITY)) {
+    *(u8 *)MemToShadow(ptr) =
+        poison ? static_cast<u8>(ptr % SHADOW_GRANULARITY) : 0;
+    ptr |= SHADOW_GRANULARITY - 1;
+    ptr++;
+  }
+  for (; ptr < end; ptr += SHADOW_GRANULARITY)
+    *(u8*)MemToShadow(ptr) = poison ? kAsanIntraObjectRedzone : 0;
+}
+
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1
@@ -250,7 +271,8 @@ uptr __asan_load_cxx_array_cookie(uptr *p) {
            "expect a double-free report\n");
     return 0;
   }
-  // FIXME: apparently it can be something else; need to find a reproducer.
+  // The cookie may remain unpoisoned if e.g. it comes from a custom
+  // operator new defined inside a class.
   return *p;
 }
 
@@ -372,6 +394,17 @@ int __sanitizer_verify_contiguous_container(const void *beg_p,
       return 0;
   return 1;
 }
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
+  AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
+}
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+void __asan_unpoison_intra_object_redzone(uptr ptr, uptr size) {
+  AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, false);
+}
+
 // --- Implementation of LSan-specific functions --- {{{1
 namespace __lsan {
 bool WordIsPoisoned(uptr addr) {
index 4eabb74..06d24d4 100644 (file)
@@ -31,6 +31,7 @@
 namespace __asan {
 
 void AsanOnSIGSEGV(int, void *siginfo, void *context) {
+  ScopedDeadlySignal signal_scope(GetCurrentThread());
   uptr addr = (uptr)((siginfo_t*)siginfo)->si_addr;
   int code = (int)((siginfo_t*)siginfo)->si_code;
   // Write the first message using the bullet-proof write.
@@ -39,12 +40,12 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
   GetPcSpBp(context, &pc, &sp, &bp);
 
   // Access at a reasonable offset above SP, or slightly below it (to account
-  // for x86_64 redzone, ARM push of multiple registers, etc) is probably a
-  // stack overflow.
+  // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+  // probably a stack overflow.
   // We also check si_code to filter out SEGV caused by something else other
   // then hitting the guard page or unmapped memory, like, for example,
   // unaligned memory access.
-  if (addr + 128 > sp && addr < sp + 0xFFFF &&
+  if (addr + 512 > sp && addr < sp + 0xFFFF &&
       (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
     ReportStackOverflow(pc, sp, bp, context, addr);
   else
index 05622a1..fcccb70 100644 (file)
@@ -29,6 +29,19 @@ static char *error_message_buffer = 0;
 static uptr error_message_buffer_pos = 0;
 static uptr error_message_buffer_size = 0;
 
+struct ReportData {
+  uptr pc;
+  uptr sp;
+  uptr bp;
+  uptr addr;
+  bool is_write;
+  uptr access_size;
+  const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
 void AppendToErrorMessageBuffer(const char *buffer) {
   if (error_message_buffer) {
     uptr length = internal_strlen(buffer);
@@ -79,20 +92,31 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
         return Red();
       case kAsanInternalHeapMagic:
         return Yellow();
+      case kAsanIntraObjectRedzone:
+        return Yellow();
       default:
         return Default();
     }
   }
   const char *EndShadowByte() { return Default(); }
+  const char *MemoryByte() { return Magenta(); }
+  const char *EndMemoryByte() { return Default(); }
 };
 
 // ---------------------- Helper functions ----------------------- {{{1
 
-static void PrintShadowByte(InternalScopedString *str, const char *before,
-                            u8 byte, const char *after = "\n") {
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+    u8 byte, bool in_shadow, const char *after = "\n") {
   Decorator d;
-  str->append("%s%s%x%x%s%s", before, d.ShadowByte(byte), byte >> 4, byte & 15,
-              d.EndShadowByte(), after);
+  str->append("%s%s%x%x%s%s", before,
+              in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
+              byte >> 4, byte & 15,
+              in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+}
+
+static void PrintShadowByte(InternalScopedString *str, const char *before,
+    u8 byte, const char *after = "\n") {
+  PrintMemoryByte(str, before, byte, /*in_shadow*/true, after);
 }
 
 static void PrintShadowBytes(InternalScopedString *str, const char *before,
@@ -144,9 +168,27 @@ static void PrintLegend(InternalScopedString *str) {
                   kAsanContiguousContainerOOBMagic);
   PrintShadowByte(str, "  Array cookie:            ",
                   kAsanArrayCookieMagic);
+  PrintShadowByte(str, "  Intra object redzone:    ",
+                  kAsanIntraObjectRedzone);
   PrintShadowByte(str, "  ASan internal:           ", kAsanInternalHeapMagic);
 }
 
+void MaybeDumpInstructionBytes(uptr pc) {
+  if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
+    return;
+  InternalScopedString str(1024);
+  str.append("First 16 instruction bytes at pc: ");
+  if (IsAccessibleMemoryRange(pc, 16)) {
+    for (int i = 0; i < 16; ++i) {
+      PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/false, " ");
+    }
+    str.append("\n");
+  } else {
+    str.append("unaccessible\n");
+  }
+  Report("%s", str.data());
+}
+
 static void PrintShadowMemoryForAddress(uptr addr) {
   if (!AddrIsInMem(addr)) return;
   uptr shadow_addr = MemToShadow(addr);
@@ -235,9 +277,7 @@ static void PrintGlobalLocation(InternalScopedString *str,
 
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
                                      const __asan_global &g) {
-  static const uptr kMinimalDistanceFromAnotherGlobal = 64;
-  if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
-  if (addr >= g.beg + g.size_with_redzone) return false;
+  if (!IsAddressNearGlobal(addr, g)) return false;
   InternalScopedString str(4096);
   Decorator d;
   str.append("%s", d.Location());
@@ -263,21 +303,20 @@ bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
   return true;
 }
 
-bool DescribeAddressIfShadow(uptr addr) {
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr, bool print) {
   if (AddrIsInMem(addr))
     return false;
-  static const char kAddrInShadowReport[] =
-      "Address %p is located in the %s.\n";
-  if (AddrIsInShadowGap(addr)) {
-    Printf(kAddrInShadowReport, addr, "shadow gap area");
-    return true;
-  }
-  if (AddrIsInHighShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "high shadow area");
-    return true;
-  }
-  if (AddrIsInLowShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "low shadow area");
+  const char *area_type = nullptr;
+  if (AddrIsInShadowGap(addr)) area_type = "shadow gap";
+  else if (AddrIsInHighShadow(addr)) area_type = "high shadow";
+  else if (AddrIsInLowShadow(addr)) area_type = "low shadow";
+  if (area_type != nullptr) {
+    if (print) {
+      Printf("Address %p is located in the %s area.\n", addr, area_type);
+    } else {
+      CHECK(descr);
+      descr->region_kind = area_type;
+    }
     return true;
   }
   CHECK(0 && "Address is not in memory and not in shadow?");
@@ -304,16 +343,15 @@ const char *ThreadNameWithParenthesis(u32 tid, char buff[],
   return ThreadNameWithParenthesis(t, buff, buff_len);
 }
 
-void PrintAccessAndVarIntersection(const char *var_name,
-                                   uptr var_beg, uptr var_size,
-                                   uptr addr, uptr access_size,
-                                   uptr prev_var_end, uptr next_var_beg) {
-  uptr var_end = var_beg + var_size;
+static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
+                                          uptr access_size, uptr prev_var_end,
+                                          uptr next_var_beg) {
+  uptr var_end = var.beg + var.size;
   uptr addr_end = addr + access_size;
   const char *pos_descr = 0;
-  // If the variable [var_beg, var_end) is the nearest variable to the
+  // If the variable [var.beg, var_end) is the nearest variable to the
   // current memory access, indicate it in the log.
-  if (addr >= var_beg) {
+  if (addr >= var.beg) {
     if (addr_end <= var_end)
       pos_descr = "is inside";  // May happen if this is a use-after-return.
     else if (addr < var_end)
@@ -322,14 +360,20 @@ void PrintAccessAndVarIntersection(const char *var_name,
              next_var_beg - addr_end >= addr - var_end)
       pos_descr = "overflows";
   } else {
-    if (addr_end > var_beg)
+    if (addr_end > var.beg)
       pos_descr = "partially underflows";
     else if (addr >= prev_var_end &&
-             addr - prev_var_end >= var_beg - addr_end)
+             addr - prev_var_end >= var.beg - addr_end)
       pos_descr = "underflows";
   }
   InternalScopedString str(1024);
-  str.append("    [%zd, %zd) '%s'", var_beg, var_beg + var_size, var_name);
+  str.append("    [%zd, %zd)", var.beg, var_end);
+  // Render variable name.
+  str.append(" '");
+  for (uptr i = 0; i < var.name_len; ++i) {
+    str.append("%c", var.name_pos[i]);
+  }
+  str.append("'");
   if (pos_descr) {
     Decorator d;
     // FIXME: we may want to also print the size of the access here,
@@ -344,9 +388,14 @@ void PrintAccessAndVarIntersection(const char *var_name,
 
 bool ParseFrameDescription(const char *frame_descr,
                            InternalMmapVector<StackVarDescr> *vars) {
+  CHECK(frame_descr);
   char *p;
+  // This string is created by the compiler and has the following form:
+  // "n alloc_1 alloc_2 ... alloc_n"
+  // where alloc_i looks like "offset size len ObjectName".
   uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
-  CHECK_GT(n_objects, 0);
+  if (n_objects == 0)
+    return false;
 
   for (uptr i = 0; i < n_objects; i++) {
     uptr beg  = (uptr)internal_simple_strtoll(p, &p, 10);
@@ -367,31 +416,21 @@ bool ParseFrameDescription(const char *frame_descr,
 bool DescribeAddressIfStack(uptr addr, uptr access_size) {
   AsanThread *t = FindThreadByStackAddress(addr);
   if (!t) return false;
-  const uptr kBufSize = 4095;
-  char buf[kBufSize];
-  uptr offset = 0;
-  uptr frame_pc = 0;
-  char tname[128];
-  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
-
-#ifdef __powerpc64__
-  // On PowerPC64, the address of a function actually points to a
-  // three-doubleword data structure with the first field containing
-  // the address of the function's code.
-  frame_pc = *reinterpret_cast<uptr *>(frame_pc);
-#endif
 
-  // This string is created by the compiler and has the following form:
-  // "n alloc_1 alloc_2 ... alloc_n"
-  // where alloc_i looks like "offset size len ObjectName ".
-  CHECK(frame_descr);
   Decorator d;
+  char tname[128];
   Printf("%s", d.Location());
-  Printf("Address %p is located in stack of thread T%d%s "
-         "at offset %zu in frame\n",
-         addr, t->tid(),
-         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)),
-         offset);
+  Printf("Address %p is located in stack of thread T%d%s", addr, t->tid(),
+         ThreadNameWithParenthesis(t->tid(), tname, sizeof(tname)));
+
+  // Try to fetch precise stack frame for this access.
+  AsanThread::StackFrameAccess access;
+  if (!t->GetStackFrameAccessByAddr(addr, &access)) {
+    Printf("%s\n", d.EndLocation());
+    return true;
+  }
+  Printf(" at offset %zu in frame%s\n", access.offset, d.EndLocation());
+
   // Now we print the frame where the alloca has happened.
   // We print this frame as a stack trace with one element.
   // The symbolizer may print more than one frame if inlining was involved.
@@ -399,16 +438,21 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
   // previously. That's unfortunate, but I have no better solution,
   // especially given that the alloca may be from entirely different place
   // (e.g. use-after-scope, or different thread's stack).
-  StackTrace alloca_stack;
-  alloca_stack.trace[0] = frame_pc + 16;
-  alloca_stack.size = 1;
+#if defined(__powerpc64__) && defined(__BIG_ENDIAN__)
+  // On PowerPC64 ELFv1, the address of a function actually points to a
+  // three-doubleword data structure with the first field containing
+  // the address of the function's code.
+  access.frame_pc = *reinterpret_cast<uptr *>(access.frame_pc);
+#endif
+  access.frame_pc += 16;
   Printf("%s", d.EndLocation());
+  StackTrace alloca_stack(&access.frame_pc, 1);
   alloca_stack.Print();
 
   InternalMmapVector<StackVarDescr> vars(16);
-  if (!ParseFrameDescription(frame_descr, &vars)) {
+  if (!ParseFrameDescription(access.frame_descr, &vars)) {
     Printf("AddressSanitizer can't parse the stack frame "
-           "descriptor: |%s|\n", frame_descr);
+           "descriptor: |%s|\n", access.frame_descr);
     // 'addr' is a stack address, so return true even if we can't parse frame
     return true;
   }
@@ -418,13 +462,9 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
 
   // Report all objects in this frame.
   for (uptr i = 0; i < n_objects; i++) {
-    buf[0] = 0;
-    internal_strncat(buf, vars[i].name_pos,
-                     static_cast<uptr>(Min(kBufSize, vars[i].name_len)));
     uptr prev_var_end = i ? vars[i - 1].beg + vars[i - 1].size : 0;
     uptr next_var_beg = i + 1 < n_objects ? vars[i + 1].beg : ~(0UL);
-    PrintAccessAndVarIntersection(buf, vars[i].beg, vars[i].size,
-                                  offset, access_size,
+    PrintAccessAndVarIntersection(vars[i], access.offset, access_size,
                                   prev_var_end, next_var_beg);
   }
   Printf("HINT: this may be a false positive if your program uses "
@@ -476,8 +516,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
   asanThreadRegistry().CheckLocked();
   AsanThreadContext *alloc_thread =
       GetThreadContextByTidLocked(chunk.AllocTid());
-  StackTrace alloc_stack;
-  chunk.GetAllocStack(&alloc_stack);
+  StackTrace alloc_stack = chunk.GetAllocStack();
   char tname[128];
   Decorator d;
   AsanThreadContext *free_thread = 0;
@@ -487,8 +526,7 @@ void DescribeHeapAddress(uptr addr, uptr access_size) {
            free_thread->tid,
            ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
            d.EndAllocation());
-    StackTrace free_stack;
-    chunk.GetFreeStack(&free_stack);
+    StackTrace free_stack = chunk.GetFreeStack();
     free_stack.Print();
     Printf("%spreviously allocated by thread T%d%s here:%s\n",
            d.Allocation(), alloc_thread->tid,
@@ -538,9 +576,7 @@ void DescribeThread(AsanThreadContext *context) {
       " created by T%d%s here:\n", context->parent_tid,
       ThreadNameWithParenthesis(context->parent_tid, tname, sizeof(tname)));
   Printf("%s", str.data());
-  uptr stack_size;
-  const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
-  StackTrace::PrintStack(stack_trace, stack_size);
+  StackDepotGet(context->stack_id).Print();
   // Recursively described parent thread if needed.
   if (flags()->print_full_thread_history) {
     AsanThreadContext *parent_context =
@@ -555,7 +591,7 @@ void DescribeThread(AsanThreadContext *context) {
 // immediately after printing error report.
 class ScopedInErrorReport {
  public:
-  ScopedInErrorReport() {
+  explicit ScopedInErrorReport(ReportData *report = nullptr) {
     static atomic_uint32_t num_calls;
     static u32 reporting_thread_tid;
     if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) != 0) {
@@ -575,6 +611,8 @@ class ScopedInErrorReport {
       // Die() to bypass any additional checks.
       internal__exit(flags()->exitcode);
     }
+    if (report) report_data = *report;
+    report_happened = true;
     ASAN_ON_ERROR();
     // Make sure the registry and sanitizer report mutexes are locked while
     // we're printing an error report.
@@ -634,11 +672,12 @@ void ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
   Printf("%s", d.EndWarning());
   GET_STACK_TRACE_SIGNAL(pc, bp, context);
   stack.Print();
+  MaybeDumpInstructionBytes(pc);
   Printf("AddressSanitizer can not provide additional info.\n");
   ReportErrorSummary("SEGV", &stack);
 }
 
-void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
+void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -657,7 +696,7 @@ void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
 }
 
 void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
-                                 StackTrace *free_stack) {
+                                 BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -680,7 +719,7 @@ void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
          "ASAN_OPTIONS=new_delete_type_mismatch=0\n");
 }
 
-void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
+void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -697,7 +736,7 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
   ReportErrorSummary("bad-free", &stack);
 }
 
-void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
+void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
                              AllocType alloc_type,
                              AllocType dealloc_type) {
   static const char *alloc_names[] =
@@ -720,7 +759,7 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
          "ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
 }
 
-void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -733,7 +772,8 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
   ReportErrorSummary("bad-malloc_usable_size", stack);
 }
 
-void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
+void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+                                             BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   Printf("%s", d.Warning());
@@ -746,9 +786,10 @@ void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
   ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
 }
 
-void ReportStringFunctionMemoryRangesOverlap(
-    const char *function, const char *offset1, uptr length1,
-    const char *offset2, uptr length2, StackTrace *stack) {
+void ReportStringFunctionMemoryRangesOverlap(const char *function,
+                                             const char *offset1, uptr length1,
+                                             const char *offset2, uptr length2,
+                                             BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   char bug_type[100];
@@ -765,7 +806,7 @@ void ReportStringFunctionMemoryRangesOverlap(
 }
 
 void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
-                                      StackTrace *stack) {
+                                      BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Decorator d;
   const char *bug_type = "negative-size-param";
@@ -779,7 +820,7 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
 
 void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
                                                   uptr old_mid, uptr new_mid,
-                                                  StackTrace *stack) {
+                                                  BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Report("ERROR: AddressSanitizer: bad parameters to "
          "__sanitizer_annotate_contiguous_container:\n"
@@ -809,12 +850,9 @@ void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
   if (stack_id1 && stack_id2) {
     Printf("These globals were registered at these points:\n");
     Printf("  [1]:\n");
-    uptr stack_size;
-    const uptr *stack_trace = StackDepotGet(stack_id1, &stack_size);
-    StackTrace::PrintStack(stack_trace, stack_size);
+    StackDepotGet(stack_id1).Print();
     Printf("  [2]:\n");
-    stack_trace = StackDepotGet(stack_id2, &stack_size);
-    StackTrace::PrintStack(stack_trace, stack_size);
+    StackDepotGet(stack_id2).Print();
   }
   Report("HINT: if you don't care about these warnings you may set "
          "ASAN_OPTIONS=detect_odr_violation=0\n");
@@ -854,8 +892,8 @@ static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
 }
 // ----------------------- Mac-specific reports ----------------- {{{1
 
-void WarnMacFreeUnallocated(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+                            BufferedStackTrace *stack) {
   // Just print a warning here.
   Printf("free_common(%p) -- attempting to free unallocated memory.\n"
              "AddressSanitizer is ignoring this error on Mac OS now.\n",
@@ -865,8 +903,8 @@ void WarnMacFreeUnallocated(
   DescribeHeapAddress(addr, 1);
 }
 
-void ReportMacMzReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+                               BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
              "This is an unrecoverable problem, exiting now.\n",
@@ -876,8 +914,8 @@ void ReportMacMzReallocUnknown(
   DescribeHeapAddress(addr, 1);
 }
 
-void ReportMacCfReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack) {
+void ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
+                               BufferedStackTrace *stack) {
   ScopedInErrorReport in_report;
   Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
              "This is an unrecoverable problem, exiting now.\n",
@@ -894,8 +932,6 @@ using namespace __asan;  // NOLINT
 
 void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
                          uptr access_size) {
-  ScopedInErrorReport in_report;
-
   // Determine the error type.
   const char *bug_descr = "unknown-crash";
   if (AddrIsInMem(addr)) {
@@ -941,8 +977,16 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
       case kAsanGlobalRedzoneMagic:
         bug_descr = "global-buffer-overflow";
         break;
+      case kAsanIntraObjectRedzone:
+        bug_descr = "intra-object-overflow";
+        break;
     }
   }
+
+  ReportData report = { pc, sp, bp, addr, (bool)is_write, access_size,
+                        bug_descr };
+  ScopedInErrorReport in_report(&report);
+
   Decorator d;
   Printf("%s", d.Warning());
   Report("ERROR: AddressSanitizer: %s on address "
@@ -984,6 +1028,38 @@ void __asan_describe_address(uptr addr) {
   asanThreadRegistry().Unlock();
 }
 
+int __asan_report_present() {
+  return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+  return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+  return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+  return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+  return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+  return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+  return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+  return report_data.description;
+}
+
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_ptr_sub(void *a, void *b) {
index 4e81b9c..b31b86d 100644 (file)
@@ -23,13 +23,24 @@ struct StackVarDescr {
   uptr name_len;
 };
 
+struct AddressDescription {
+  char *name;
+  uptr name_size;
+  uptr region_address;
+  uptr region_size;
+  const char *region_kind;
+};
+
 // The following functions prints address description depending
 // on the memory type (shadow/heap/stack/global).
 void DescribeHeapAddress(uptr addr, uptr access_size);
 bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
                                      const __asan_global &g);
-bool DescribeAddressIfShadow(uptr addr);
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g);
+bool GetInfoForAddressIfGlobal(uptr addr, AddressDescription *descr);
+bool DescribeAddressIfShadow(uptr addr, AddressDescription *descr = nullptr,
+                             bool print = true);
 bool ParseFrameDescription(const char *frame_descr,
                            InternalMmapVector<StackVarDescr> *vars);
 bool DescribeAddressIfStack(uptr addr, uptr access_size);
@@ -44,35 +55,41 @@ void NORETURN
 void NORETURN ReportSIGSEGV(const char *description, uptr pc, uptr sp, uptr bp,
                             void *context, uptr addr);
 void NORETURN ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
-                                          StackTrace *free_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,
+                                          BufferedStackTrace *free_stack);
+void NORETURN ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
                                       AllocType alloc_type,
                                       AllocType dealloc_type);
-void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
-                                             StackTrace *stack);
 void NORETURN
-ReportSanitizerGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack);
-void NORETURN ReportStringFunctionMemoryRangesOverlap(
-    const char *function, const char *offset1, uptr length1,
-    const char *offset2, uptr length2, StackTrace *stack);
+    ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack);
+void NORETURN
+    ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
+                                            BufferedStackTrace *stack);
 void NORETURN
-ReportStringFunctionSizeOverflow(uptr offset, uptr size, StackTrace *stack);
+    ReportStringFunctionMemoryRangesOverlap(const char *function,
+                                            const char *offset1, uptr length1,
+                                            const char *offset2, uptr length2,
+                                            BufferedStackTrace *stack);
+void NORETURN ReportStringFunctionSizeOverflow(uptr offset, uptr size,
+                                               BufferedStackTrace *stack);
 void NORETURN
-ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end, uptr old_mid,
-                                             uptr new_mid, StackTrace *stack);
+    ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
+                                                 uptr old_mid, uptr new_mid,
+                                                 BufferedStackTrace *stack);
 
 void NORETURN
 ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                    const __asan_global *g2, u32 stack_id2);
 
 // Mac-specific errors and warnings.
-void WarnMacFreeUnallocated(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacMzReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
-void NORETURN ReportMacCfReallocUnknown(
-    uptr addr, uptr zone_ptr, const char *zone_name, StackTrace *stack);
+void WarnMacFreeUnallocated(uptr addr, uptr zone_ptr, const char *zone_name,
+                            BufferedStackTrace *stack);
+void NORETURN ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr,
+                                        const char *zone_name,
+                                        BufferedStackTrace *stack);
+void NORETURN ReportMacCfReallocUnknown(uptr addr, uptr zone_ptr,
+                                        const char *zone_name,
+                                        BufferedStackTrace *stack);
 
 }  // namespace __asan
index 8fccc8d..2c59904 100644 (file)
@@ -65,7 +65,7 @@ static void AsanCheckFailed(const char *file, int line, const char *cond,
   Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
          line, cond, (uptr)v1, (uptr)v2);
   // FIXME: check for infinite recursion without a thread-local counter here.
-  PRINT_CURRENT_STACK();
+  PRINT_CURRENT_STACK_CHECK();
   Die();
 }
 
@@ -228,6 +228,9 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
             "If >=2, detect violation of One-Definition-Rule (ODR); "
             "If ==1, detect ODR-violation only if the two variables "
             "have different sizes");
+
+  ParseFlag(str, &f->dump_instruction_bytes, "dump_instruction_bytes",
+      "If true, dump 16 bytes starting at the instruction that caused SEGV");
 }
 
 void InitializeFlags(Flags *f, const char *env) {
@@ -281,6 +284,7 @@ void InitializeFlags(Flags *f, const char *env) {
   f->detect_invalid_pointer_pairs = 0;
   f->detect_container_overflow = true;
   f->detect_odr_violation = 2;
+  f->dump_instruction_bytes = false;
 
   // Override from compile definition.
   ParseFlagsFromString(f, MaybeUseAsanDefaultOptionsCompileDefinition());
index d31c0af..640c4cf 100644 (file)
@@ -23,8 +23,9 @@ namespace __asan {
 // The pc will be in the position 0 of the resulting stack trace.
 // The bp may refer to the current frame or to the caller's frame.
 ALWAYS_INLINE
-void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
-                                     uptr bp, void *context, bool fast) {
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+                                     uptr pc, uptr bp, void *context,
+                                     bool fast) {
 #if SANITIZER_WINDOWS
   stack->Unwind(max_depth, pc, bp, context, 0, 0, fast);
 #else
@@ -32,6 +33,10 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
   stack->size = 0;
   if (LIKELY(asan_inited)) {
     if ((t = GetCurrentThread()) && !t->isUnwinding()) {
+      // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+      // yields the call stack of the signal's handler and not of the code
+      // that raised the signal (as it does on Linux).
+      if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
       uptr stack_top = t->stack_top();
       uptr stack_bottom = t->stack_bottom();
       ScopedUnwinding unwind_scope(t);
@@ -51,14 +56,14 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
 // don't want stack trace to contain functions from ASan internals.
 
 #define GET_STACK_TRACE(max_size, fast)                                        \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   if (max_size <= 2) {                                                         \
     stack.size = max_size;                                                     \
     if (max_size > 0) {                                                        \
       stack.top_frame_bp = GET_CURRENT_FRAME();                                \
-      stack.trace[0] = StackTrace::GetCurrentPc();                             \
+      stack.trace_buffer[0] = StackTrace::GetCurrentPc();                      \
       if (max_size > 1)                                                        \
-        stack.trace[1] = GET_CALLER_PC();                                      \
+        stack.trace_buffer[1] = GET_CALLER_PC();                               \
     }                                                                          \
   } else {                                                                     \
     GetStackTraceWithPcBpAndContext(&stack, max_size,                          \
@@ -67,18 +72,21 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
   }
 
 #define GET_STACK_TRACE_FATAL(pc, bp)                                          \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, 0,           \
                                   common_flags()->fast_unwind_on_fatal)
 
 #define GET_STACK_TRACE_SIGNAL(pc, bp, context)                                \
-  StackTrace stack;                                                            \
+  BufferedStackTrace stack;                                                    \
   GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,     \
                                   common_flags()->fast_unwind_on_fatal)
 
 #define GET_STACK_TRACE_FATAL_HERE                                \
   GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
 
+#define GET_STACK_TRACE_CHECK_HERE                                \
+  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
+
 #define GET_STACK_TRACE_THREAD                                    \
   GET_STACK_TRACE(kStackTraceMax, true)
 
@@ -94,4 +102,10 @@ void GetStackTraceWithPcBpAndContext(StackTrace *stack, uptr max_depth, uptr pc,
     stack.Print();              \
   }
 
+#define PRINT_CURRENT_STACK_CHECK() \
+  {                                 \
+    GET_STACK_TRACE_CHECK_HERE;     \
+    stack.Print();                  \
+  }
+
 #endif  // ASAN_STACK_H
index 8707406..95ca672 100644 (file)
@@ -28,7 +28,7 @@ namespace __asan {
 void AsanThreadContext::OnCreated(void *arg) {
   CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
   if (args->stack)
-    stack_id = StackDepotPut(args->stack->trace, args->stack->size);
+    stack_id = StackDepotPut(*args->stack);
   thread = args->thread;
   thread->set_context(this);
 }
@@ -196,17 +196,18 @@ void AsanThread::ClearShadowForThreadStackAndTLS() {
     PoisonShadow(tls_begin_, tls_end_ - tls_begin_, 0);
 }
 
-const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
-                                           uptr *frame_pc) {
+bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
+                                           StackFrameAccess *access) {
   uptr bottom = 0;
   if (AddrIsInStack(addr)) {
     bottom = stack_bottom();
   } else if (has_fake_stack()) {
     bottom = fake_stack()->AddrIsInFakeStack(addr);
     CHECK(bottom);
-    *offset = addr - bottom;
-    *frame_pc = ((uptr*)bottom)[2];
-    return  (const char *)((uptr*)bottom)[1];
+    access->offset = addr - bottom;
+    access->frame_pc = ((uptr*)bottom)[2];
+    access->frame_descr = (const char *)((uptr*)bottom)[1];
+    return true;
   }
   uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1);  // align addr.
   u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
@@ -223,15 +224,15 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset,
   }
 
   if (shadow_ptr < shadow_bottom) {
-    *offset = 0;
-    return "UNKNOWN";
+    return false;
   }
 
   uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
   CHECK(ptr[0] == kCurrentStackFrameMagic);
-  *offset = addr - (uptr)ptr;
-  *frame_pc = ptr[2];
-  return (const char*)ptr[1];
+  access->offset = addr - (uptr)ptr;
+  access->frame_pc = ptr[2];
+  access->frame_descr = (const char*)ptr[1];
+  return true;
 }
 
 static bool ThreadStackContainsAddress(ThreadContextBase *tctx_base,
index 33242ef..f5ea53d 100644 (file)
@@ -69,7 +69,12 @@ class AsanThread {
   AsanThreadContext *context() { return context_; }
   void set_context(AsanThreadContext *context) { context_ = context; }
 
-  const char *GetFrameNameByAddr(uptr addr, uptr *offset, uptr *frame_pc);
+  struct StackFrameAccess {
+    uptr offset;
+    uptr frame_pc;
+    const char *frame_descr;
+  };
+  bool GetStackFrameAccessByAddr(uptr addr, StackFrameAccess *access);
 
   bool AddrIsInStack(uptr addr) {
     return addr >= stack_bottom_ && addr < stack_top_;
@@ -101,6 +106,10 @@ class AsanThread {
   bool isUnwinding() const { return unwinding_; }
   void setUnwinding(bool b) { unwinding_ = b; }
 
+  // True if we are in a deadly signal handler.
+  bool isInDeadlySignal() const { return in_deadly_signal_; }
+  void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
+
   AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
   AsanStats &stats() { return stats_; }
 
@@ -126,6 +135,7 @@ class AsanThread {
   AsanThreadLocalMallocStorage malloc_storage_;
   AsanStats stats_;
   bool unwinding_;
+  bool in_deadly_signal_;
 };
 
 // ScopedUnwinding is a scope for stacktracing member of a context
@@ -140,6 +150,20 @@ class ScopedUnwinding {
   AsanThread *thread;
 };
 
+// ScopedDeadlySignal is a scope for handling deadly signals.
+class ScopedDeadlySignal {
+ public:
+  explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
+    if (thread) thread->setInDeadlySignal(true);
+  }
+  ~ScopedDeadlySignal() {
+    if (thread) thread->setInDeadlySignal(false);
+  }
+
+ private:
+  AsanThread *thread;
+};
+
 struct CreateThreadContextArgs {
   AsanThread *thread;
   StackTrace *stack;
index d1d4529..023fa29 100644 (file)
@@ -53,13 +53,39 @@ extern "C" {
   // Otherwise returns 0.
   int __asan_address_is_poisoned(void const volatile *addr);
 
-  // If at least on byte in [beg, beg+size) is poisoned, return the address
+  // If at least one byte in [beg, beg+size) is poisoned, return the address
   // of the first such byte. Otherwise return 0.
   void *__asan_region_is_poisoned(void *beg, size_t size);
 
   // Print the description of addr (useful when debugging in gdb).
   void __asan_describe_address(void *addr);
 
+  // Useful for calling from a debugger to get information about an ASan error.
+  // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+  int __asan_report_present();
+
+  // Useful for calling from a debugger to get information about an ASan error.
+  // If an error has been (or is being) reported, the following functions return
+  // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
+  // bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
+  void *__asan_get_report_pc();
+  void *__asan_get_report_bp();
+  void *__asan_get_report_sp();
+  void *__asan_get_report_address();
+  int __asan_get_report_access_type();
+  size_t __asan_get_report_access_size();
+  const char *__asan_get_report_description();
+
+  // Useful for calling from the debugger to get information about a pointer.
+  // Returns the category of the given pointer as a constant string.
+  // Possible return values are "global", "stack", "stack-fake", "heap",
+  // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+  // If global or stack, tries to also return the variable name, address and
+  // size. If heap, tries to return the chunk address and size. 'name' should
+  // point to an allocated buffer of size 'name_size'.
+  const char *__asan_locate_address(void *addr, char *name, size_t name_size,
+                                    void **region_address, size_t *region_size);
+
   // Useful for calling from the debugger to get the allocation stack trace
   // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
   // returns the number of stored frames or 0 on error.
index 43e0c30..3aba519 100644 (file)
@@ -103,7 +103,7 @@ extern "C" {
                                                  const void *end,
                                                  const void *old_mid,
                                                  const void *new_mid);
-  // Returns true if the contiguous container [beg, end) ir properly poisoned
+  // Returns true if the contiguous container [beg, end) is properly poisoned
   // (e.g. with __sanitizer_annotate_contiguous_container), i.e. if
   //  - [beg, mid) is addressable,
   //  - [mid, end) is unaddressable.
index e9fbe6a..87ee5d5 100644 (file)
@@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 
 noinst_LTLIBRARIES = libinterception.la
index 5ac217d..3bb0f12 100644 (file)
@@ -225,7 +225,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
-       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 noinst_LTLIBRARIES = libinterception.la
 interception_files = \
index 1642bd1..f9c2e9b 100644 (file)
@@ -180,7 +180,10 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
 }
 
 static const void **InterestingDLLsAvailable() {
-  const char *InterestingDLLs[] = { "kernel32.dll", "msvcr120.dll", NULL };
+  const char *InterestingDLLs[] = {"kernel32.dll",
+                                   "msvcr110.dll", // VS2012
+                                   "msvcr120.dll", // VS2013
+                                   NULL};
   static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
   if (!result[0]) {
     for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
index fd9eb65..ec386f4 100644 (file)
@@ -40,6 +40,7 @@ C_WARN_FLAGS = $(WARN_FLAGS) -Wstrict-prototypes -Wmissing-prototypes -Wold-styl
 CXX_WARN_FLAGS = $(WARN_FLAGS) -Wno-unused-parameter
 AM_CFLAGS = $(C_WARN_FLAGS)
 AM_CXXFLAGS = $(CXX_WARN_FLAGS) -fno-rtti -fno-exceptions
+AM_CXXFLAGS += -std=c++11
 
 noinst_LTLIBRARIES = libsanitizer_libbacktrace.la
 
index 0dfb53d..a924978 100644 (file)
@@ -270,7 +270,7 @@ WARN_FLAGS = -W -Wall -Wwrite-strings -Wmissing-format-attribute \
 C_WARN_FLAGS = $(WARN_FLAGS) -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition
 CXX_WARN_FLAGS = $(WARN_FLAGS) -Wno-unused-parameter
 AM_CFLAGS = $(C_WARN_FLAGS)
-AM_CXXFLAGS = $(CXX_WARN_FLAGS) -fno-rtti -fno-exceptions
+AM_CXXFLAGS = $(CXX_WARN_FLAGS) -fno-rtti -fno-exceptions -std=c++11
 noinst_LTLIBRARIES = libsanitizer_libbacktrace.la
 libsanitizer_libbacktrace_la_SOURCES = \
        ../../libbacktrace/backtrace.h \
index 7a508c1..2db6ba2 100644 (file)
@@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 
 noinst_LTLIBRARIES = libsanitizer_lsan.la
index 47caebc..8ab9c68 100644 (file)
@@ -260,7 +260,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
-       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 noinst_LTLIBRARIES = libsanitizer_lsan.la
 @LSAN_SUPPORTED_TRUE@toolexeclib_LTLIBRARIES = liblsan.la
index 57888e3..ee2fc02 100644 (file)
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 
-#define GET_STACK_TRACE(max_size, fast)                                     \
-  StackTrace stack;                                                         \
-  {                                                                         \
-    uptr stack_top = 0, stack_bottom = 0;                                   \
-    ThreadContext *t;                                                       \
-    if (fast && (t = CurrentThreadContext())) {                             \
-      stack_top = t->stack_end();                                           \
-      stack_bottom = t->stack_begin();                                      \
-    }                                                                       \
-    stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
-                 /* context */ 0, stack_top, stack_bottom, fast);           \
+#define GET_STACK_TRACE(max_size, fast)                                        \
+  BufferedStackTrace stack;                                                    \
+  {                                                                            \
+    uptr stack_top = 0, stack_bottom = 0;                                      \
+    ThreadContext *t;                                                          \
+    if (fast && (t = CurrentThreadContext())) {                                \
+      stack_top = t->stack_end();                                              \
+      stack_bottom = t->stack_begin();                                         \
+    }                                                                          \
+    stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),    \
+                 /* context */ 0, stack_top, stack_bottom, fast);              \
   }
 
 #define GET_STACK_TRACE_FATAL \
index cda2b86..2d406a0 100644 (file)
@@ -61,7 +61,7 @@ static void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
   ChunkMetadata *m = Metadata(p);
   CHECK(m);
   m->tag = DisabledInThisThread() ? kIgnored : kDirectlyLeaked;
-  m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
+  m->stack_trace_id = StackDepotPut(stack);
   m->requested_size = size;
   atomic_store(reinterpret_cast<atomic_uint8_t *>(m), 1, memory_order_relaxed);
 }
index e340b89..aa79a7e 100644 (file)
@@ -353,9 +353,7 @@ static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
 
 static void PrintStackTraceById(u32 stack_trace_id) {
   CHECK(stack_trace_id);
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(stack_trace_id, &size);
-  StackTrace::PrintStack(trace, size);
+  StackDepotGet(stack_trace_id).Print();
 }
 
 // ForEachChunk callback. Aggregates information about unreachable chunks into
@@ -370,10 +368,9 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
     uptr resolution = flags()->resolution;
     u32 stack_trace_id = 0;
     if (resolution > 0) {
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(m.stack_trace_id(), &size);
-      size = Min(size, resolution);
-      stack_trace_id = StackDepotPut(trace, size);
+      StackTrace stack = StackDepotGet(m.stack_trace_id());
+      stack.size = Min(stack.size, resolution);
+      stack_trace_id = StackDepotPut(stack);
     } else {
       stack_trace_id = m.stack_trace_id();
     }
@@ -449,8 +446,11 @@ void DoLeakCheck() {
     PrintMatchedSuppressions();
   if (unsuppressed_count > 0) {
     param.leak_report.PrintSummary();
-    if (flags()->exitcode)
+    if (flags()->exitcode) {
+      if (common_flags()->coverage)
+        __sanitizer_cov_dump();
       internal__exit(flags()->exitcode);
+    }
   }
 }
 
@@ -482,11 +482,10 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
 }
 
 static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
-  uptr size = 0;
-  const uptr *trace = StackDepotGet(stack_trace_id, &size);
-  for (uptr i = 0; i < size; i++) {
-    Suppression *s =
-        GetSuppressionForAddr(StackTrace::GetPreviousInstructionPc(trace[i]));
+  StackTrace stack = StackDepotGet(stack_trace_id);
+  for (uptr i = 0; i < stack.size; i++) {
+    Suppression *s = GetSuppressionForAddr(
+        StackTrace::GetPreviousInstructionPc(stack.trace[i]));
     if (s) return s;
   }
   return 0;
index c318fbc..b17156c 100644 (file)
@@ -92,11 +92,10 @@ void ProcessGlobalRegions(Frontier *frontier) {
 
 static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
   CHECK(stack_id);
-  uptr size = 0;
-  const uptr *trace = map->Get(stack_id, &size);
+  StackTrace stack = map->Get(stack_id);
   // The top frame is our malloc/calloc/etc. The next frame is the caller.
-  if (size >= 2)
-    return trace[1];
+  if (stack.size >= 2)
+    return stack.trace[1];
   return 0;
 }
 
index bc1f18c..c5da0c1 100644 (file)
@@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 if LIBBACKTRACE_SUPPORTED
 AM_CXXFLAGS += -DSANITIZER_LIBBACKTRACE -DSANITIZER_CP_DEMANGLE \
               -I $(top_srcdir)/../libbacktrace \
@@ -44,6 +45,7 @@ sanitizer_common_files = \
        sanitizer_stackdepot.cc \
        sanitizer_stacktrace.cc \
        sanitizer_stacktrace_libcdep.cc \
+       sanitizer_stacktrace_printer.cc \
        sanitizer_stoptheworld_linux_libcdep.cc \
        sanitizer_suppressions.cc \
        sanitizer_symbolizer.cc \
index d82b483..db02613 100644 (file)
@@ -78,6 +78,7 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
        sanitizer_procmaps_linux.lo sanitizer_procmaps_mac.lo \
        sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
        sanitizer_stacktrace_libcdep.lo \
+       sanitizer_stacktrace_printer.lo \
        sanitizer_stoptheworld_linux_libcdep.lo \
        sanitizer_suppressions.lo sanitizer_symbolizer.lo \
        sanitizer_symbolizer_libbacktrace.lo \
@@ -252,7 +253,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
-       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) \
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11 \
        $(am__append_1)
 ACLOCAL_AMFLAGS = -I m4
 noinst_LTLIBRARIES = libsanitizer_common.la
@@ -283,6 +284,7 @@ sanitizer_common_files = \
        sanitizer_stackdepot.cc \
        sanitizer_stacktrace.cc \
        sanitizer_stacktrace_libcdep.cc \
+       sanitizer_stacktrace_printer.cc \
        sanitizer_stoptheworld_linux_libcdep.cc \
        sanitizer_suppressions.cc \
        sanitizer_symbolizer.cc \
@@ -414,6 +416,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_printer.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_linux_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_suppressions.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@
index fb39412..dd5539a 100644 (file)
@@ -459,6 +459,11 @@ class SizeClassAllocator64 {
     }
   }
 
+  static uptr AdditionalSize() {
+    return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
+                     GetPageSizeCached());
+  }
+
   typedef SizeClassMap SizeClassMapT;
   static const uptr kNumClasses = SizeClassMap::kNumClasses;
   static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -488,11 +493,6 @@ class SizeClassAllocator64 {
   };
   COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
 
-  static uptr AdditionalSize() {
-    return RoundUpTo(sizeof(RegionInfo) * kNumClassesRounded,
-                     GetPageSizeCached());
-  }
-
   RegionInfo *GetRegionInfo(uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
     RegionInfo *regions = reinterpret_cast<RegionInfo*>(kSpaceBeg + kSpaceSize);
@@ -1013,12 +1013,15 @@ class LargeMmapAllocator {
     if (map_size < size) return AllocatorReturnNull();  // Overflow.
     uptr map_beg = reinterpret_cast<uptr>(
         MmapOrDie(map_size, "LargeMmapAllocator"));
+    CHECK(IsAligned(map_beg, page_size_));
     MapUnmapCallback().OnMap(map_beg, map_size);
     uptr map_end = map_beg + map_size;
     uptr res = map_beg + page_size_;
     if (res & (alignment - 1))  // Align.
       res += alignment - (res & (alignment - 1));
-    CHECK_EQ(0, res & (alignment - 1));
+    CHECK(IsAligned(res, alignment));
+    CHECK(IsAligned(res, page_size_));
+    CHECK_GE(res + size, map_beg);
     CHECK_LE(res + size, map_end);
     Header *h = GetHeader(res);
     h->size = size;
index d4da320..f06efff 100644 (file)
@@ -153,23 +153,12 @@ const char *StripPathPrefix(const char *filepath,
   return pos;
 }
 
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
-                         int line, int column) {
-  CHECK(file);
-  buffer->append("%s",
-                 StripPathPrefix(file, common_flags()->strip_path_prefix));
-  if (line > 0) {
-    buffer->append(":%d", line);
-    if (column > 0)
-      buffer->append(":%d", column);
-  }
-}
-
-void PrintModuleAndOffset(InternalScopedString *buffer, const char *module,
-                          uptr offset) {
-  buffer->append("(%s+0x%zx)",
-                 StripPathPrefix(module, common_flags()->strip_path_prefix),
-                 offset);
+const char *StripModuleName(const char *module) {
+  if (module == 0)
+    return 0;
+  if (const char *slash_pos = internal_strrchr(module, '/'))
+    return slash_pos + 1;
+  return module;
 }
 
 void ReportErrorSummary(const char *error_message) {
@@ -215,17 +204,6 @@ bool LoadedModule::containsAddress(uptr address) const {
   return false;
 }
 
-char *StripModuleName(const char *module) {
-  if (module == 0)
-    return 0;
-  const char *short_module_name = internal_strrchr(module, '/');
-  if (short_module_name)
-    short_module_name += 1;
-  else
-    short_module_name = module;
-  return internal_strdup(short_module_name);
-}
-
 static atomic_uintptr_t g_total_mmaped;
 
 void IncreaseTotalMmap(uptr size) {
index a9db108..a892491 100644 (file)
@@ -170,10 +170,8 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size);
 // Error report formatting.
 const char *StripPathPrefix(const char *filepath,
                             const char *strip_file_prefix);
-void PrintSourceLocation(InternalScopedString *buffer, const char *file,
-                         int line, int column);
-void PrintModuleAndOffset(InternalScopedString *buffer,
-                          const char *module, uptr offset);
+// Strip the directories from the module name.
+const char *StripModuleName(const char *module);
 
 // OS
 void DisableCoreDumperIfNecessary();
@@ -207,9 +205,6 @@ void SleepForMillis(int millis);
 u64 NanoTime();
 int Atexit(void (*function)(void));
 void SortArray(uptr *array, uptr size);
-// Strip the directories from the module name, return a new string allocated
-// with internal_strdup.
-char *StripModuleName(const char *module);
 
 // Exit
 void NORETURN Abort();
index f55a31d..10f3218 100644 (file)
 #define va_copy(dst, src) ((dst) = (src))
 #endif // _WIN32
 
+#if SANITIZER_FREEBSD
+#define pthread_setname_np pthread_set_name_np
+#endif
+
 #ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
 #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
 #endif
index 9b02cd7..214e8a9 100644 (file)
@@ -36,6 +36,7 @@
 #include "sanitizer_mutex.h"
 #include "sanitizer_procmaps.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
 #include "sanitizer_flags.h"
 
 atomic_uint32_t dump_once_guard;  // Ensure that CovDump runs only once.
@@ -61,6 +62,9 @@ class CoverageData {
   void AfterFork(int child_pid);
   void Extend(uptr npcs);
   void Add(uptr pc);
+  void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+                 uptr cache_size);
+  void DumpCallerCalleePairs();
 
   uptr *data();
   uptr size();
@@ -83,6 +87,14 @@ class CoverageData {
   uptr pc_array_mapped_size;
   // Descriptor of the file mapped pc array.
   int pc_fd;
+
+  // Caller-Callee (cc) array, size and current index.
+  static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
+  uptr **cc_array;
+  atomic_uintptr_t cc_array_index;
+  atomic_uintptr_t cc_array_size;
+
+
   StaticSpinMutex mu;
 
   void DirectOpen();
@@ -116,6 +128,11 @@ void CoverageData::Init() {
     atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
     atomic_store(&pc_array_index, 0, memory_order_relaxed);
   }
+
+  cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
+      sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
+  atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
+  atomic_store(&cc_array_index, 0, memory_order_relaxed);
 }
 
 void CoverageData::ReInit() {
@@ -184,6 +201,38 @@ void CoverageData::Add(uptr pc) {
   pc_array[idx] = pc;
 }
 
+// Registers a pair caller=>callee.
+// When a given caller is seen for the first time, the callee_cache is added
+// to the global array cc_array, callee_cache[0] is set to caller and
+// callee_cache[1] is set to cache_size.
+// Then we are trying to add callee to callee_cache [2,cache_size) if it is
+// not there yet.
+// If the cache is full we drop the callee (may want to fix this later).
+void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
+                             uptr cache_size) {
+  if (!cc_array) return;
+  atomic_uintptr_t *atomic_callee_cache =
+      reinterpret_cast<atomic_uintptr_t *>(callee_cache);
+  uptr zero = 0;
+  if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
+                                     memory_order_seq_cst)) {
+    uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
+    CHECK_LT(idx * sizeof(uptr),
+             atomic_load(&cc_array_size, memory_order_acquire));
+    callee_cache[1] = cache_size;
+    cc_array[idx] = callee_cache;
+  }
+  CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
+  for (uptr i = 2; i < cache_size; i++) {
+    uptr was = 0;
+    if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
+                                       memory_order_seq_cst))
+      return;
+    if (was == callee)  // Already have this callee.
+      return;
+  }
+}
+
 uptr *CoverageData::data() {
   return pc_array;
 }
@@ -266,6 +315,45 @@ static int CovOpenFile(bool packed, const char* name) {
   return fd;
 }
 
+// This function dumps the caller=>callee pairs into a file as a sequence of
+// lines like "module_name offset".
+void CoverageData::DumpCallerCalleePairs() {
+  uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
+  if (!max_idx) return;
+  auto sym = Symbolizer::GetOrInit();
+  if (!sym)
+    return;
+  InternalScopedString out(32 << 20);
+  uptr total = 0;
+  for (uptr i = 0; i < max_idx; i++) {
+    uptr *cc_cache = cc_array[i];
+    CHECK(cc_cache);
+    uptr caller = cc_cache[0];
+    uptr n_callees = cc_cache[1];
+    const char *caller_module_name = "<unknown>";
+    uptr caller_module_address = 0;
+    sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
+                                     &caller_module_address);
+    for (uptr j = 2; j < n_callees; j++) {
+      uptr callee = cc_cache[j];
+      if (!callee) break;
+      total++;
+      const char *callee_module_name = "<unknown>";
+      uptr callee_module_address = 0;
+      sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
+                                       &callee_module_address);
+      out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
+                 caller_module_address, callee_module_name,
+                 callee_module_address);
+    }
+  }
+  int fd = CovOpenFile(false, "caller-callee");
+  if (fd < 0) return;
+  internal_write(fd, out.data(), out.length());
+  internal_close(fd);
+  VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
+}
+
 // Dump the coverage on disk.
 static void CovDump() {
   if (!common_flags()->coverage || common_flags()->coverage_direct) return;
@@ -297,7 +385,7 @@ static void CovDump() {
         CHECK_LE(diff, 0xffffffffU);
         offsets.push_back(static_cast<u32>(diff));
       }
-      char *module_name = StripModuleName(module.data());
+      const char *module_name = StripModuleName(module.data());
       if (cov_sandboxed) {
         if (cov_fd >= 0) {
           CovWritePacked(internal_getpid(), module_name, offsets.data(),
@@ -317,11 +405,11 @@ static void CovDump() {
                   vb - old_vb);
         }
       }
-      InternalFree(module_name);
     }
   }
   if (cov_fd >= 0)
     internal_close(cov_fd);
+  coverage_data.DumpCallerCalleePairs();
 #endif  // !SANITIZER_WINDOWS
 }
 
@@ -357,6 +445,11 @@ extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() {
   coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()));
 }
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
+  coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
+                          callee, callee_cache16, 16);
+}
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
   coverage_data.Init();
index a134053..b88814b 100644 (file)
@@ -78,7 +78,7 @@ void CovUpdateMapping(uptr caller_pc) {
 
   text.append("%d\n", sizeof(uptr) * 8);
   for (int i = 0; i < n_modules; ++i) {
-    char *module_name = StripModuleName(modules[i].full_name());
+    const char *module_name = StripModuleName(modules[i].full_name());
     for (unsigned j = 0; j < modules[i].n_ranges(); ++j) {
       if (modules[i].address_range_executable(j)) {
         uptr start = modules[i].address_range_start(j);
@@ -89,7 +89,6 @@ void CovUpdateMapping(uptr caller_pc) {
           cached_mapping.SetModuleRange(start, end);
       }
     }
-    InternalFree(module_name);
   }
 
   int err;
index 476f793..d7e7118 100644 (file)
@@ -37,6 +37,7 @@ void SetCommonFlagsDefaults(CommonFlags *f) {
   f->external_symbolizer_path = 0;
   f->allow_addr2line = false;
   f->strip_path_prefix = "";
+  f->fast_unwind_on_check = false;
   f->fast_unwind_on_fatal = false;
   f->fast_unwind_on_malloc = true;
   f->handle_ioctl = false;
@@ -64,6 +65,8 @@ void SetCommonFlagsDefaults(CommonFlags *f) {
   f->suppressions = "";
   f->print_suppressions = true;
   f->disable_coredump = (SANITIZER_WORDSIZE == 64);
+  f->symbolize_inline_frames = true;
+  f->stack_trace_format = "DEFAULT";
 }
 
 void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
@@ -79,6 +82,9 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
       "unavailable.");
   ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix",
       "Strips this prefix from file paths in error reports.");
+  ParseFlag(str, &f->fast_unwind_on_check, "fast_unwind_on_check",
+      "If available, use the fast frame-pointer-based unwinder on "
+      "internal CHECK failures.");
   ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal",
       "If available, use the fast frame-pointer-based unwinder on fatal "
       "errors.");
@@ -152,6 +158,12 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
       "Disable core dumping. By default, disable_core=1 on 64-bit to avoid "
       "dumping a 16T+ core file. Ignored on OSes that don't dump core by"
       "default and for sanitizers that don't reserve lots of virtual memory.");
+  ParseFlag(str, &f->symbolize_inline_frames, "symbolize_inline_frames",
+            "Print inlined frames in stacktraces. Defaults to true.");
+  ParseFlag(str, &f->stack_trace_format, "stack_trace_format",
+            "Format string used to render stack frames. "
+            "See sanitizer_stacktrace_printer.h for the format description. "
+            "Use DEFAULT to get default format.");
 
   // Do a sanity check for certain flags.
   if (f->malloc_context_size < 1)
index a906c9e..b7a5013 100644 (file)
@@ -30,6 +30,7 @@ struct CommonFlags {
   const char *external_symbolizer_path;
   bool allow_addr2line;
   const char *strip_path_prefix;
+  bool fast_unwind_on_check;
   bool fast_unwind_on_fatal;
   bool fast_unwind_on_malloc;
   bool handle_ioctl;
@@ -58,6 +59,8 @@ struct CommonFlags {
   const char *suppressions;
   bool print_suppressions;
   bool disable_coredump;
+  bool symbolize_inline_frames;
+  const char *stack_trace_format;
 };
 
 inline CommonFlags *common_flags() {
index 2c2a1d7..17b931c 100644 (file)
@@ -158,7 +158,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
   // pthread_get_stacksize_np() returns an incorrect stack size for the main
   // thread on Mavericks. See
   // https://code.google.com/p/address-sanitizer/issues/detail?id=261
-  if ((GetMacosVersion() == MACOS_VERSION_MAVERICKS) && at_initialization &&
+  if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization &&
       stacksize == (1 << 19))  {
     struct rlimit rl;
     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
@@ -295,6 +295,7 @@ MacosVersion GetMacosVersionInternal() {
         case '1': return MACOS_VERSION_LION;
         case '2': return MACOS_VERSION_MOUNTAIN_LION;
         case '3': return MACOS_VERSION_MAVERICKS;
+        case '4': return MACOS_VERSION_YOSEMITE;
         default: return MACOS_VERSION_UNKNOWN;
       }
     }
index 6305529..47739f7 100644 (file)
@@ -23,7 +23,8 @@ enum MacosVersion {
   MACOS_VERSION_SNOW_LEOPARD,
   MACOS_VERSION_LION,
   MACOS_VERSION_MOUNTAIN_LION,
-  MACOS_VERSION_MAVERICKS
+  MACOS_VERSION_MAVERICKS,
+  MACOS_VERSION_YOSEMITE,
 };
 
 MacosVersion GetMacosVersion();
index 14594d5..7064b71 100644 (file)
@@ -47,7 +47,7 @@
 # define SANITIZER_WINDOWS 0
 #endif
 
-#if defined(__ANDROID__) || defined(ANDROID)
+#if defined(__ANDROID__)
 # define SANITIZER_ANDROID 1
 #else
 # define SANITIZER_ANDROID 0
@@ -79,7 +79,7 @@
 // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
 // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
 #ifndef SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__aarch64__)
+# if defined(__aarch64__) || defined(__mips64)
 #  define SANITIZER_CAN_USE_ALLOCATOR64 0
 # else
 #  define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
 # endif
 #endif
 
+#ifdef __mips__
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10)
+#else
+# define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12)
+#endif
+
 #endif // SANITIZER_PLATFORM_H
index 81a0992..fc2d7ba 100644 (file)
 #define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD
 
 #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
+  SI_FREEBSD || SI_LINUX_NOT_ANDROID
 
 #define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID
 
 #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
+    SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
 #define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
 #define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
 
index a1f0432..8779d8a 100644 (file)
@@ -36,7 +36,6 @@
 #define uid_t __kernel_uid_t
 #define gid_t __kernel_gid_t
 #define off_t __kernel_off_t
-#define time_t __kernel_time_t
 // This header seems to contain the definitions of _kernel_ stat* structs.
 #include <asm/stat.h>
 #undef ino_t
@@ -61,7 +60,7 @@ namespace __sanitizer {
 }  // namespace __sanitizer
 
 #if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\
-                            && !defined(__mips__) && !defined(__sparc__)
+                            && !defined(__mips__)
 COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
 #endif
 
index f5678dc..13d908e 100644 (file)
 
 #include "sanitizer_platform.h"
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
-
+// Tests in this file assume that off_t-dependent data structures match the
+// libc ABI. For example, struct dirent here is what readdir() function (as
+// exported from libc) returns, and not the user-facing "dirent", which
+// depends on _FILE_OFFSET_BITS setting.
+// To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
+#ifdef _FILE_OFFSET_BITS
+#undef _FILE_OFFSET_BITS
+#endif
+#if SANITIZER_FREEBSD
+#define _WANT_RTENTRY
+#include <sys/param.h>
+#include <sys/socketvar.h>
+#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <errno.h>
@@ -551,7 +563,9 @@ namespace __sanitizer {
   unsigned IOCTL_PPPIOCSMAXCID = PPPIOCSMAXCID;
   unsigned IOCTL_PPPIOCSMRU = PPPIOCSMRU;
   unsigned IOCTL_PPPIOCSXASYNCMAP = PPPIOCSXASYNCMAP;
+  unsigned IOCTL_SIOCADDRT = SIOCADDRT;
   unsigned IOCTL_SIOCDARP = SIOCDARP;
+  unsigned IOCTL_SIOCDELRT = SIOCDELRT;
   unsigned IOCTL_SIOCDRARP = SIOCDRARP;
   unsigned IOCTL_SIOCGARP = SIOCGARP;
   unsigned IOCTL_SIOCGIFENCAP = SIOCGIFENCAP;
@@ -637,8 +651,6 @@ namespace __sanitizer {
 #if SANITIZER_LINUX || SANITIZER_FREEBSD
   unsigned IOCTL_MTIOCGET = MTIOCGET;
   unsigned IOCTL_MTIOCTOP = MTIOCTOP;
-  unsigned IOCTL_SIOCADDRT = SIOCADDRT;
-  unsigned IOCTL_SIOCDELRT = SIOCDELRT;
   unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
   unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
   unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
index 284be11..139fe0a 100644 (file)
@@ -72,14 +72,6 @@ namespace __sanitizer {
   const unsigned struct_kernel_stat_sz = 144;
   #endif
   const unsigned struct_kernel_stat64_sz = 104;
-#elif defined(__sparc__) && defined(__arch64__)
-  const unsigned struct___old_kernel_stat_sz = 0;
-  const unsigned struct_kernel_stat_sz = 104;
-  const unsigned struct_kernel_stat64_sz = 144;
-#elif defined(__sparc__) && !defined(__arch64__)
-  const unsigned struct___old_kernel_stat_sz = 0;
-  const unsigned struct_kernel_stat_sz = 64;
-  const unsigned struct_kernel_stat64_sz = 104;
 #endif
   struct __sanitizer_perf_event_attr {
     unsigned type;
@@ -102,7 +94,7 @@ namespace __sanitizer {
 
 #if defined(__powerpc64__)
   const unsigned struct___old_kernel_stat_sz = 0;
-#elif !defined(__sparc__)
+#else
   const unsigned struct___old_kernel_stat_sz = 32;
 #endif
 
@@ -181,18 +173,6 @@ namespace __sanitizer {
     unsigned short __pad1;
     unsigned long __unused1;
     unsigned long __unused2;
-#elif defined(__sparc__)
-# if defined(__arch64__)
-    unsigned mode;
-    unsigned short __pad1;
-# else
-    unsigned short __pad1;
-    unsigned short mode;
-    unsigned short __pad2;
-# endif
-    unsigned short __seq;
-    unsigned long long __unused1;
-    unsigned long long __unused2;
 #else
     unsigned short mode;
     unsigned short __pad1;
@@ -210,26 +190,6 @@ namespace __sanitizer {
 
   struct __sanitizer_shmid_ds {
     __sanitizer_ipc_perm shm_perm;
-  #if defined(__sparc__)
-  # if !defined(__arch64__)
-    u32 __pad1;
-  # endif
-    long shm_atime;
-  # if !defined(__arch64__)
-    u32 __pad2;
-  # endif
-    long shm_dtime;
-  # if !defined(__arch64__)
-    u32 __pad3;
-  # endif
-    long shm_ctime;
-    uptr shm_segsz;
-    int shm_cpid;
-    int shm_lpid;
-    unsigned long shm_nattch;
-    unsigned long __glibc_reserved1;
-    unsigned long __glibc_reserved2;
-  #else    
   #ifndef __powerpc__
     uptr shm_segsz;
   #elif !defined(__powerpc64__)
@@ -267,7 +227,6 @@ namespace __sanitizer {
     uptr __unused4;
     uptr __unused5;
   #endif
-#endif
   };
 #elif SANITIZER_FREEBSD
   struct __sanitizer_ipc_perm {
@@ -511,7 +470,7 @@ namespace __sanitizer {
   typedef long __sanitizer___kernel_off_t;
 #endif
 
-#if defined(__powerpc__) || defined(__aarch64__) || defined(__mips__)
+#if defined(__powerpc__) || defined(__mips__)
   typedef unsigned int __sanitizer___kernel_old_uid_t;
   typedef unsigned int __sanitizer___kernel_old_gid_t;
 #else
@@ -564,13 +523,9 @@ namespace __sanitizer {
 #else
     __sanitizer_sigset_t sa_mask;
 #ifndef __mips__
-#if defined(__sparc__)
-    unsigned long sa_flags;
-#else
     int sa_flags;
 #endif
 #endif
-#endif
 #if SANITIZER_LINUX
     void (*sa_restorer)();
 #endif
@@ -790,7 +745,7 @@ struct __sanitizer_obstack {
 
 #define IOC_NRBITS 8
 #define IOC_TYPEBITS 8
-#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || defined(__sparc__)
+#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
 #define IOC_SIZEBITS 13
 #define IOC_DIRBITS 3
 #define IOC_NONE 1U
@@ -820,17 +775,7 @@ struct __sanitizer_obstack {
 #define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
 #define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
 #define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
-
-#if defined(__sparc__)
-// In sparc the 14 bits SIZE field overlaps with the
-// least significant bit of DIR, so either IOC_READ or
-// IOC_WRITE shall be 1 in order to get a non-zero SIZE.
-# define IOC_SIZE(nr)                       \
-  ((((((nr) >> 29) & 0x7) & (4U|2U)) == 0)? \
-   0 : (((nr) >> 16) & 0x3fff))
-#else
 #define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
-#endif
 
   extern unsigned struct_arpreq_sz;
   extern unsigned struct_ifreq_sz;
index 24e99f9..229870e 100644 (file)
@@ -82,9 +82,12 @@ uptr GetMaxVirtualAddress() {
   // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
   // Note that with 'ulimit -s unlimited' the stack is moved away from the top
   // of the address space, so simply checking the stack address is not enough.
-  return (1ULL << 44) - 1;  // 0x00000fffffffffffUL
+  // This should (does) work for both PowerPC64 Endian modes.
+  return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
 # elif defined(__aarch64__)
   return (1ULL << 39) - 1;
+# elif defined(__mips64)
+  return (1ULL << 40) - 1;
 # else
   return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
 # endif
index fc0c357..599f2c5 100644 (file)
@@ -111,7 +111,7 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
   int result = 0;
   result += AppendString(buff, buff_end, -1, "0x");
   result += AppendUnsigned(buff, buff_end, ptr_value, 16,
-                           (SANITIZER_WORDSIZE == 64) ? 12 : 8, true);
+                           SANITIZER_POINTER_FORMAT_LENGTH, true);
   return result;
 }
 
index e1915cb..a3c9c06 100644 (file)
 
 namespace __sanitizer {
 
-struct StackDepotDesc {
-  const uptr *stack;
-  uptr size;
-  u32 hash() const {
-    // murmur2
-    const u32 m = 0x5bd1e995;
-    const u32 seed = 0x9747b28c;
-    const u32 r = 24;
-    u32 h = seed ^ (size * sizeof(uptr));
-    for (uptr i = 0; i < size; i++) {
-      u32 k = stack[i];
-      k *= m;
-      k ^= k >> r;
-      k *= m;
-      h *= m;
-      h ^= k;
-    }
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-    return h;
-  }
-  bool is_valid() { return size > 0 && stack; }
-};
-
 struct StackDepotNode {
   StackDepotNode *link;
   u32 id;
@@ -56,28 +31,49 @@ struct StackDepotNode {
   static const u32 kUseCountMask = (1 << kUseCountBits) - 1;
   static const u32 kHashMask = ~kUseCountMask;
 
-  typedef StackDepotDesc args_type;
+  typedef StackTrace args_type;
   bool eq(u32 hash, const args_type &args) const {
     u32 hash_bits =
         atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask;
     if ((hash & kHashMask) != hash_bits || args.size != size) return false;
     uptr i = 0;
     for (; i < size; i++) {
-      if (stack[i] != args.stack[i]) return false;
+      if (stack[i] != args.trace[i]) return false;
     }
     return true;
   }
   static uptr storage_size(const args_type &args) {
     return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr);
   }
+  static u32 hash(const args_type &args) {
+    // murmur2
+    const u32 m = 0x5bd1e995;
+    const u32 seed = 0x9747b28c;
+    const u32 r = 24;
+    u32 h = seed ^ (args.size * sizeof(uptr));
+    for (uptr i = 0; i < args.size; i++) {
+      u32 k = args.trace[i];
+      k *= m;
+      k ^= k >> r;
+      k *= m;
+      h *= m;
+      h ^= k;
+    }
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+    return h;
+  }
+  static bool is_valid(const args_type &args) {
+    return args.size > 0 && args.trace;
+  }
   void store(const args_type &args, u32 hash) {
     atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed);
     size = args.size;
-    internal_memcpy(stack, args.stack, size * sizeof(uptr));
+    internal_memcpy(stack, args.trace, size * sizeof(uptr));
   }
   args_type load() const {
-    args_type ret = {&stack[0], size};
-    return ret;
+    return args_type(&stack[0], size);
   }
   StackDepotHandle get_handle() { return StackDepotHandle(this); }
 
@@ -97,8 +93,6 @@ void StackDepotHandle::inc_use_count_unsafe() {
       StackDepotNode::kUseCountMask;
   CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount);
 }
-uptr StackDepotHandle::size() { return node_->size; }
-uptr *StackDepotHandle::stack() { return &node_->stack[0]; }
 
 // FIXME(dvyukov): this single reserved bit is used in TSan.
 typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog>
@@ -109,21 +103,17 @@ StackDepotStats *StackDepotGetStats() {
   return theDepot.GetStats();
 }
 
-u32 StackDepotPut(const uptr *stack, uptr size) {
-  StackDepotDesc desc = {stack, size};
-  StackDepotHandle h = theDepot.Put(desc);
+u32 StackDepotPut(StackTrace stack) {
+  StackDepotHandle h = theDepot.Put(stack);
   return h.valid() ? h.id() : 0;
 }
 
-StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) {
-  StackDepotDesc desc = {stack, size};
-  return theDepot.Put(desc);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack) {
+  return theDepot.Put(stack);
 }
 
-const uptr *StackDepotGet(u32 id, uptr *size) {
-  StackDepotDesc desc = theDepot.Get(id);
-  *size = desc.size;
-  return desc.stack;
+StackTrace StackDepotGet(u32 id) {
+  return theDepot.Get(id);
 }
 
 void StackDepotLockAll() {
@@ -154,18 +144,15 @@ StackDepotReverseMap::StackDepotReverseMap()
   InternalSort(&map_, map_.size(), IdDescPair::IdComparator);
 }
 
-const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) {
-  if (!map_.size()) return 0;
+StackTrace StackDepotReverseMap::Get(u32 id) {
+  if (!map_.size())
+    return StackTrace();
   IdDescPair pair = {id, 0};
   uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
                                   IdDescPair::IdComparator);
-  if (idx > map_.size()) {
-    *size = 0;
-    return 0;
-  }
-  StackDepotNode *desc = map_[idx].desc;
-  *size = desc->size;
-  return desc->stack;
+  if (idx > map_.size())
+    return StackTrace();
+  return map_[idx].desc->load();
 }
 
 }  // namespace __sanitizer
index 2b1da4e..aad9bfb 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_stacktrace.h"
 
 namespace __sanitizer {
 
@@ -26,17 +27,15 @@ struct StackDepotHandle {
   u32 id();
   int use_count();
   void inc_use_count_unsafe();
-  uptr size();
-  uptr *stack();
 };
 
 const int kStackDepotMaxUseCount = 1U << 20;
 
 StackDepotStats *StackDepotGetStats();
-u32 StackDepotPut(const uptr *stack, uptr size);
-StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size);
+u32 StackDepotPut(StackTrace stack);
+StackDepotHandle StackDepotPut_WithHandle(StackTrace stack);
 // Retrieves a stored stack trace by the id.
-const uptr *StackDepotGet(u32 id, uptr *size);
+StackTrace StackDepotGet(u32 id);
 
 void StackDepotLockAll();
 void StackDepotUnlockAll();
@@ -48,7 +47,7 @@ void StackDepotUnlockAll();
 class StackDepotReverseMap {
  public:
   StackDepotReverseMap();
-  const uptr *Get(u32 id, uptr *size);
+  StackTrace Get(u32 id);
 
  private:
   struct IdDescPair {
index b9dedec..05b6309 100644 (file)
@@ -95,8 +95,8 @@ typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type
 StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args,
                                                       bool *inserted) {
   if (inserted) *inserted = false;
-  if (!args.is_valid()) return handle_type();
-  uptr h = args.hash();
+  if (!Node::is_valid(args)) return handle_type();
+  uptr h = Node::hash(args);
   atomic_uintptr_t *p = &tab[h % kTabSize];
   uptr v = atomic_load(p, memory_order_consume);
   Node *s = (Node *)(v & ~1);
index 0ce5ae4..9b99b5b 100644 (file)
@@ -23,7 +23,7 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
 #if defined(__powerpc__) || defined(__powerpc64__)
   // PCs are always 4 byte aligned.
   return pc - 4;
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined(__mips__)
   return pc - 8;
 #else
   return pc - 1;
@@ -34,6 +34,15 @@ uptr StackTrace::GetCurrentPc() {
   return GET_CALLER_PC();
 }
 
+void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+  size = cnt + !!extra_top_pc;
+  CHECK_LE(size, kStackTraceMax);
+  internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+  if (extra_top_pc)
+    trace_buffer[cnt] = extra_top_pc;
+  top_frame_bp = 0;
+}
+
 // Check if given pointer points into allocated stack area.
 static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) {
   return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr);
@@ -49,32 +58,40 @@ static inline uhwptr *GetCanonicFrame(uptr bp,
   if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0;
   uhwptr *bp_prev = (uhwptr *)bp;
   if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev;
-  return bp_prev - 1;
+  // The next frame pointer does not look right. This could be a GCC frame, step
+  // back by 1 word and try again.
+  if (IsValidFrame((uptr)bp_prev[-1], stack_top, stack_bottom))
+    return bp_prev - 1;
+  // Nope, this does not look right either. This means the frame after next does
+  // not have a valid frame pointer, but we can still extract the caller PC.
+  // Unfortunately, there is no way to decide between GCC and LLVM frame
+  // layouts. Assume LLVM.
+  return bp_prev;
 #else
   return (uhwptr*)bp;
 #endif
 }
 
-void StackTrace::FastUnwindStack(uptr pc, uptr bp,
-                                 uptr stack_top, uptr stack_bottom,
-                                 uptr max_depth) {
+void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
+                                         uptr stack_bottom, uptr max_depth) {
   CHECK_GE(max_depth, 2);
-  trace[0] = pc;
+  trace_buffer[0] = pc;
   size = 1;
   if (stack_top < 4096) return;  // Sanity check for stack top.
   uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom);
-  uhwptr *prev_frame = 0;
+  // Lowest possible address that makes sense as the next frame pointer.
+  // Goes up as we walk the stack.
+  uptr bottom = stack_bottom;
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
-  while (frame > prev_frame &&
-         IsValidFrame((uptr)frame, stack_top, stack_bottom) &&
+  while (IsValidFrame((uptr)frame, stack_top, bottom) &&
          IsAligned((uptr)frame, sizeof(*frame)) &&
          size < max_depth) {
     uhwptr pc1 = frame[1];
     if (pc1 != pc) {
-      trace[size++] = (uptr) pc1;
+      trace_buffer[size++] = (uptr) pc1;
     }
-    prev_frame = frame;
-    frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom);
+    bottom = (uptr)frame;
+    frame = GetCanonicFrame((uptr)frame[0], stack_top, bottom);
   }
 }
 
@@ -82,15 +99,15 @@ static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
   return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
 }
 
-void StackTrace::PopStackFrames(uptr count) {
+void BufferedStackTrace::PopStackFrames(uptr count) {
   CHECK_LT(count, size);
   size -= count;
   for (uptr i = 0; i < size; ++i) {
-    trace[i] = trace[i + count];
+    trace_buffer[i] = trace_buffer[i + count];
   }
 }
 
-uptr StackTrace::LocatePcInTrace(uptr pc) {
+uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
   // Use threshold to find PC in stack trace, as PC we want to unwind from may
   // slightly differ from return address in the actual unwinded stack trace.
   const int kPcThreshold = 288;
index 0e0f170..31495cf 100644 (file)
@@ -27,44 +27,49 @@ static const uptr kStackTraceMax = 256;
 # define SANITIZER_CAN_FAST_UNWIND 1
 #endif
 
+// Fast unwind is the only option on Mac for now; we will need to
+// revisit this macro when slow unwind works on Mac, see
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+#if SANITIZER_MAC
+# define SANITIZER_CAN_SLOW_UNWIND 0
+#else
+# define SANITIZER_CAN_SLOW_UNWIND 1
+#endif
+
 struct StackTrace {
-  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
-                                     int out_size);
-  uptr top_frame_bp;
+  const uptr *trace;
   uptr size;
-  uptr trace[kStackTraceMax];
 
-  // Prints a symbolized stacktrace, followed by an empty line.
-  static void PrintStack(const uptr *addr, uptr size);
-  void Print() const {
-    PrintStack(trace, size);
-  }
+  StackTrace() : trace(nullptr), size(0) {}
+  StackTrace(const uptr *trace, uptr size) : trace(trace), size(size) {}
 
-  void CopyFrom(const uptr *src, uptr src_size) {
-    top_frame_bp = 0;
-    size = src_size;
-    if (size > kStackTraceMax) size = kStackTraceMax;
-    for (uptr i = 0; i < size; i++)
-      trace[i] = src[i];
-  }
+  // Prints a symbolized stacktrace, followed by an empty line.
+  void Print() const;
 
   static bool WillUseFastUnwind(bool request_fast_unwind) {
-    // Check if fast unwind is available. Fast unwind is the only option on Mac.
-    // It is also the only option on FreeBSD as the slow unwinding that
-    // leverages _Unwind_Backtrace() yields the call stack of the signal's
-    // handler and not of the code that raised the signal (as it does on Linux).
     if (!SANITIZER_CAN_FAST_UNWIND)
       return false;
-    else if (SANITIZER_MAC != 0 || SANITIZER_FREEBSD != 0)
+    else if (!SANITIZER_CAN_SLOW_UNWIND)
       return true;
     return request_fast_unwind;
   }
 
-  void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
-              uptr stack_bottom, bool request_fast_unwind);
-
   static uptr GetCurrentPc();
   static uptr GetPreviousInstructionPc(uptr pc);
+  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
+                                    int out_size);
+};
+
+// StackTrace that owns the buffer used to store the addresses.
+struct BufferedStackTrace : public StackTrace {
+  uptr trace_buffer[kStackTraceMax];
+  uptr top_frame_bp;  // Optional bp of a top frame.
+
+  BufferedStackTrace() : StackTrace(trace_buffer, 0), top_frame_bp(0) {}
+
+  void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
+  void Unwind(uptr max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
+              uptr stack_bottom, bool request_fast_unwind);
 
  private:
   void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
@@ -74,6 +79,9 @@ struct StackTrace {
                                   uptr max_depth);
   void PopStackFrames(uptr count);
   uptr LocatePcInTrace(uptr pc);
+
+  BufferedStackTrace(const BufferedStackTrace &);
+  void operator=(const BufferedStackTrace &);
 };
 
 }  // namespace __sanitizer
index 5dcc0e9..2d55b73 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common.h"
+#include "sanitizer_placement_new.h"
 #include "sanitizer_stacktrace.h"
+#include "sanitizer_stacktrace_printer.h"
 #include "sanitizer_symbolizer.h"
 
 namespace __sanitizer {
 
-static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
-                                  uptr pc) {
-  buffer->append("    #%zu 0x%zx", frame_num, pc);
-}
-
-void StackTrace::PrintStack(const uptr *addr, uptr size) {
-  if (addr == 0 || size == 0) {
+void StackTrace::Print() const {
+  if (trace == nullptr || size == 0) {
     Printf("    <empty stack>\n\n");
     return;
   }
-  InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
-  InternalScopedBuffer<AddressInfo> addr_frames(64);
+  const int kMaxAddrFrames = 64;
+  InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
+  for (uptr i = 0; i < kMaxAddrFrames; i++)
+    new(&addr_frames[i]) AddressInfo();
   InternalScopedString frame_desc(GetPageSizeCached() * 2);
   uptr frame_num = 0;
-  for (uptr i = 0; i < size && addr[i]; i++) {
+  for (uptr i = 0; i < size && trace[i]; i++) {
     // PCs in stack traces are actually the return addresses, that is,
     // addresses of the next instructions after the call.
-    uptr pc = GetPreviousInstructionPc(addr[i]);
+    uptr pc = GetPreviousInstructionPc(trace[i]);
     uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
-        pc, addr_frames.data(), addr_frames.size());
+        pc, addr_frames.data(), kMaxAddrFrames);
     if (addr_frames_num == 0) {
-      frame_desc.clear();
-      PrintStackFramePrefix(&frame_desc, frame_num, pc);
-      frame_desc.append(" (<unknown module>)");
-      Printf("%s\n", frame_desc.data());
-      frame_num++;
-      continue;
+      addr_frames[0].address = pc;
+      addr_frames_num = 1;
     }
     for (uptr j = 0; j < addr_frames_num; j++) {
       AddressInfo &info = addr_frames[j];
       frame_desc.clear();
-      PrintStackFramePrefix(&frame_desc, frame_num, pc);
-      if (info.function) {
-        frame_desc.append(" in %s", info.function);
-        // Print offset in function if we don't know the source file.
-        if (!info.file && info.function_offset != AddressInfo::kUnknown)
-          frame_desc.append("+0x%zx", info.function_offset);
-      }
-      if (info.file) {
-        frame_desc.append(" ");
-        PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
-      } else if (info.module) {
-        frame_desc.append(" ");
-        PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
-      }
+      RenderFrame(&frame_desc, common_flags()->stack_trace_format, frame_num++,
+                  info, common_flags()->strip_path_prefix);
       Printf("%s\n", frame_desc.data());
-      frame_num++;
       info.Clear();
     }
   }
@@ -69,9 +51,9 @@ void StackTrace::PrintStack(const uptr *addr, uptr size) {
   Printf("\n");
 }
 
-void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
-                        uptr stack_top, uptr stack_bottom,
-                        bool request_fast_unwind) {
+void BufferedStackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
+                                uptr stack_top, uptr stack_bottom,
+                                bool request_fast_unwind) {
   top_frame_bp = (max_depth > 0) ? bp : 0;
   // Avoid doing any work for small max_depth.
   if (max_depth == 0) {
@@ -80,7 +62,7 @@ void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, void *context,
   }
   if (max_depth == 1) {
     size = 1;
-    trace[0] = pc;
+    trace_buffer[0] = pc;
     return;
   }
   if (!WillUseFastUnwind(request_fast_unwind)) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
new file mode 100644 (file)
index 0000000..300b490
--- /dev/null
@@ -0,0 +1,130 @@
+//===-- sanitizer_common.cc -----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_stacktrace_printer.h"
+
+namespace __sanitizer {
+
+static const char *StripFunctionName(const char *function, const char *prefix) {
+  if (function == 0) return 0;
+  if (prefix == 0) return function;
+  uptr prefix_len = internal_strlen(prefix);
+  if (0 == internal_strncmp(function, prefix, prefix_len))
+    return function + prefix_len;
+  return function;
+}
+
+static const char kDefaultFormat[] = "    #%n %p %F %L";
+
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+                 const AddressInfo &info, const char *strip_path_prefix,
+                 const char *strip_func_prefix) {
+  if (0 == internal_strcmp(format, "DEFAULT"))
+    format = kDefaultFormat;
+  for (const char *p = format; *p != '\0'; p++) {
+    if (*p != '%') {
+      buffer->append("%c", *p);
+      continue;
+    }
+    p++;
+    switch (*p) {
+    case '%':
+      buffer->append("%%");
+      break;
+    // Frame number and all fields of AddressInfo structure.
+    case 'n':
+      buffer->append("%zu", frame_no);
+      break;
+    case 'p':
+      buffer->append("0x%zx", info.address);
+      break;
+    case 'm':
+      buffer->append("%s", StripPathPrefix(info.module, strip_path_prefix));
+      break;
+    case 'o':
+      buffer->append("0x%zx", info.module_offset);
+      break;
+    case 'f':
+      buffer->append("%s", StripFunctionName(info.function, strip_func_prefix));
+      break;
+    case 'q':
+      buffer->append("0x%zx", info.function_offset != AddressInfo::kUnknown
+                                  ? info.function_offset
+                                  : 0x0);
+      break;
+    case 's':
+      buffer->append("%s", StripPathPrefix(info.file, strip_path_prefix));
+      break;
+    case 'l':
+      buffer->append("%d", info.line);
+      break;
+    case 'c':
+      buffer->append("%d", info.column);
+      break;
+    // Smarter special cases.
+    case 'F':
+      // Function name and offset, if file is unknown.
+      if (info.function) {
+        buffer->append("in %s",
+                       StripFunctionName(info.function, strip_func_prefix));
+        if (!info.file && info.function_offset != AddressInfo::kUnknown)
+          buffer->append("+0x%zx", info.function_offset);
+      }
+      break;
+    case 'S':
+      // File/line information.
+      RenderSourceLocation(buffer, info.file, info.line, info.column,
+                           strip_path_prefix);
+      break;
+    case 'L':
+      // Source location, or module location.
+      if (info.file) {
+        RenderSourceLocation(buffer, info.file, info.line, info.column,
+                             strip_path_prefix);
+      } else if (info.module) {
+        RenderModuleLocation(buffer, info.module, info.module_offset,
+                             strip_path_prefix);
+      } else {
+        buffer->append("(<unknown module>)");
+      }
+      break;
+    case 'M':
+      // Module basename and offset, or PC.
+      if (info.module)
+        buffer->append("(%s+%p)", StripModuleName(info.module),
+                       (void *)info.module_offset);
+      else
+        buffer->append("(%p)", (void *)info.address);
+      break;
+    default:
+      Report("Unsupported specifier in stack frame format: %c (0x%zx)!\n",
+             *p, *p);
+      Die();
+    }
+  }
+}
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+                          int line, int column, const char *strip_path_prefix) {
+  buffer->append("%s", StripPathPrefix(file, strip_path_prefix));
+  if (line > 0) {
+    buffer->append(":%d", line);
+    if (column > 0)
+      buffer->append(":%d", column);
+  }
+}
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+                          uptr offset, const char *strip_path_prefix) {
+  buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
+                 offset);
+}
+
+}  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
new file mode 100644 (file)
index 0000000..54e2fb0
--- /dev/null
@@ -0,0 +1,60 @@
+//===-- sanitizer_stacktrace_printer.h --------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers' run-time libraries.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_STACKTRACE_PRINTER_H
+#define SANITIZER_STACKTRACE_PRINTER_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// Render the contents of "info" structure, which represents the contents of
+// stack frame "frame_no" and appends it to the "buffer". "format" is a
+// string with placeholders, which is copied to the output with
+// placeholders substituted with the contents of "info". For example,
+// format string
+//   "  frame %n: function %F at %S"
+// will be turned into
+//   "  frame 10: function foo::bar() at my/file.cc:10"
+// You may additionally pass "strip_path_prefix" to strip prefixes of paths to
+// source files and modules, and "strip_func_prefix" to strip prefixes of
+// function names.
+// Here's the full list of available placeholders:
+//   %% - represents a '%' character;
+//   %n - frame number (copy of frame_no);
+//   %p - PC in hex format;
+//   %m - path to module (binary or shared object);
+//   %o - offset in the module in hex format;
+//   %f - function name;
+//   %q - offset in the function in hex format (*if available*);
+//   %s - path to source file;
+//   %l - line in the source file;
+//   %c - column in the source file;
+//   %F - if function is known to be <foo>, prints "in <foo>", possibly
+//        followed by the offset in this function, but only if source file
+//        is unknown;
+//   %S - prints file/line/column information;
+//   %L - prints location information: file/line/column, if it is known, or
+//        module+offset if it is known, or (<unknown module>) string.
+//   %M - prints module basename and offset, if it is known, or PC.
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+                 const AddressInfo &info, const char *strip_path_prefix = "",
+                 const char *strip_func_prefix = "");
+
+void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+                          int line, int column, const char *strip_path_prefix);
+
+void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+                          uptr offset, const char *strip_path_prefix);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_STACKTRACE_PRINTER_H
index 73a68b2..2ff9937 100644 (file)
@@ -59,13 +59,23 @@ struct AddressInfo {
   }
 };
 
+// For now, DataInfo is used to describe global variable.
 struct DataInfo {
-  uptr address;
   char *module;
   uptr module_offset;
   char *name;
   uptr start;
   uptr size;
+
+  DataInfo() {
+    internal_memset(this, 0, sizeof(DataInfo));
+  }
+
+  void Clear() {
+    InternalFree(module);
+    InternalFree(name);
+    internal_memset(this, 0, sizeof(DataInfo));
+  }
 };
 
 class Symbolizer {
index 86d32e5..9050794 100644 (file)
@@ -166,7 +166,7 @@ uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
 }
 
 bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
-  backtrace_syminfo((backtrace_state *)state_, info->address,
+  backtrace_syminfo((backtrace_state *)state_, info->start,
                     SymbolizeDataCallback, ErrorCallback, info);
   return true;
 }
index 4f30225..ccd2d70 100644 (file)
@@ -339,12 +339,19 @@ class LLVMSymbolizerProcess : public SymbolizerProcess {
     const char* const kSymbolizerArch = "--default-arch=x86_64";
 #elif defined(__i386__)
     const char* const kSymbolizerArch = "--default-arch=i386";
-#elif defined(__powerpc64__)
+#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__)
     const char* const kSymbolizerArch = "--default-arch=powerpc64";
+#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
+    const char* const kSymbolizerArch = "--default-arch=powerpc64le";
 #else
     const char* const kSymbolizerArch = "--default-arch=unknown";
 #endif
-    execl(path_to_binary, path_to_binary, kSymbolizerArch, (char *)0);
+
+    const char *const inline_flag = common_flags()->symbolize_inline_frames
+                                        ? "--inlining=true"
+                                        : "--inlining=false";
+    execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch,
+          (char *)0);
   }
 };
 
@@ -580,8 +587,7 @@ class POSIXSymbolizer : public Symbolizer {
       return false;
     const char *module_name = module->full_name();
     uptr module_offset = addr - module->base_address();
-    internal_memset(info, 0, sizeof(*info));
-    info->address = addr;
+    info->Clear();
     info->module = internal_strdup(module_name);
     info->module_offset = module_offset;
     // First, try to use libbacktrace symbolizer (if it's available).
index c49113e..b2ca931 100644 (file)
@@ -93,7 +93,7 @@ uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
 }
 
 struct UnwindTraceArg {
-  StackTrace *stack;
+  BufferedStackTrace *stack;
   uptr max_depth;
 };
 
@@ -101,27 +101,27 @@ _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
   UnwindTraceArg *arg = (UnwindTraceArg*)param;
   CHECK_LT(arg->stack->size, arg->max_depth);
   uptr pc = Unwind_GetIP(ctx);
-  arg->stack->trace[arg->stack->size++] = pc;
+  arg->stack->trace_buffer[arg->stack->size++] = pc;
   if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
   return UNWIND_CONTINUE;
 }
 
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
   CHECK_GE(max_depth, 2);
   size = 0;
   UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
   _Unwind_Backtrace(Unwind_Trace, &arg);
   // We need to pop a few frames so that pc is on top.
   uptr to_pop = LocatePcInTrace(pc);
-  // trace[0] belongs to the current function so we always pop it.
-  if (to_pop == 0)
+  // trace_buffer[0] belongs to the current function so we always pop it.
+  if (to_pop == 0 && size > 1)
     to_pop = 1;
   PopStackFrames(to_pop);
-  trace[0] = pc;
+  trace_buffer[0] = pc;
 }
 
-void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
-                                            uptr max_depth) {
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+                                                    uptr max_depth) {
   CHECK_GE(max_depth, 2);
   if (!unwind_backtrace_signal_arch) {
     SlowUnwindStack(pc, max_depth);
@@ -143,7 +143,7 @@ void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
   // +2 compensate for libcorkscrew unwinder returning addresses of call
   // instructions instead of raw return addresses.
   for (sptr i = 0; i < res; ++i)
-    trace[size++] = frames[i].absolute_pc + 2;
+    trace_buffer[size++] = frames[i].absolute_pc + 2;
 }
 
 }  // namespace __sanitizer
index 9f24510..fbccef1 100644 (file)
@@ -442,7 +442,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
 }
 
 #if !SANITIZER_GO
-void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
+void BufferedStackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
   CHECK_GE(max_depth, 2);
   // FIXME: CaptureStackBackTrace might be too slow for us.
   // FIXME: Compare with StackWalk64.
@@ -457,8 +457,8 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
   PopStackFrames(pc_location);
 }
 
-void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
-                                            uptr max_depth) {
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+                                                    uptr max_depth) {
   CONTEXT ctx = *(CONTEXT *)context;
   STACKFRAME64 stack_frame;
   memset(&stack_frame, 0, sizeof(stack_frame));
@@ -481,7 +481,7 @@ void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
                      &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
                      &SymGetModuleBase64, NULL) &&
          size < Min(max_depth, kStackTraceMax)) {
-    trace[size++] = (uptr)stack_frame.AddrPC.Offset;
+    trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
   }
 }
 #endif  // #if !SANITIZER_GO
index ab4748e..3896a8b 100644 (file)
@@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 
 toolexeclib_LTLIBRARIES = libtsan.la
index c6f1ecf..32e454f 100644 (file)
@@ -276,7 +276,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
-       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 toolexeclib_LTLIBRARIES = libtsan.la
 tsan_files = \
index a8528cb..076de73 100644 (file)
@@ -41,7 +41,6 @@ const unsigned kMaxTidInClock = kMaxTid * 2;  // This includes msb 'freed' bit.
 const int kClkBits = 42;
 const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
 const uptr kShadowStackSize = 64 * 1024;
-const uptr kTraceStackSize = 256;
 
 #ifdef TSAN_SHADOW_COUNT
 # if TSAN_SHADOW_COUNT == 2 \
@@ -172,7 +171,6 @@ struct Context;
 struct ReportStack;
 class ReportDesc;
 class RegionAlloc;
-class StackTrace;
 
 // Descriptor of user's memory block.
 struct MBlock {
index a74a668..1058203 100644 (file)
@@ -46,7 +46,8 @@ static bool bogusfd(int fd) {
 }
 
 static FdSync *allocsync(ThreadState *thr, uptr pc) {
-  FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync));
+  FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
+      false);
   atomic_store(&s->rc, 1, memory_order_relaxed);
   return s;
 }
@@ -63,7 +64,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
       CHECK_NE(s, &fdctx.globsync);
       CHECK_NE(s, &fdctx.filesync);
       CHECK_NE(s, &fdctx.socksync);
-      user_free(thr, pc, s);
+      user_free(thr, pc, s, false);
     }
   }
 }
@@ -76,13 +77,13 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
   if (l1 == 0) {
     uptr size = kTableSizeL2 * sizeof(FdDesc);
     // We need this to reside in user memory to properly catch races on it.
-    void *p = user_alloc(thr, pc, size);
+    void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
     internal_memset(p, 0, size);
     MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
     if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
       l1 = (uptr)p;
     else
-      user_free(thr, pc, p);
+      user_free(thr, pc, p, false);
   }
   return &((FdDesc*)l1)[fd % kTableSizeL2];  // NOLINT
 }
index 02bf652..6059f27 100644 (file)
@@ -97,6 +97,7 @@ void InitializeFlags(Flags *f, const char *env) {
   cf->allow_addr2line = true;
   cf->detect_deadlocks = true;
   cf->print_suppressions = false;
+  cf->stack_trace_format = "    #%n %f %S %M";
 
   // Let a frontend override.
   ParseFlags(f, __tsan_default_options());
index b49622b..7f1b6e4 100644 (file)
 
 using namespace __tsan;  // NOLINT
 
+#if SANITIZER_FREEBSD
+#define __errno_location __error
+#define __libc_malloc __malloc
+#define __libc_realloc __realloc
+#define __libc_calloc __calloc
+#define __libc_free __free
+#define stdout __stdoutp
+#define stderr __stderrp
+#endif
+
 const int kSigCount = 65;
 
 struct my_siginfo_t {
@@ -60,7 +70,9 @@ extern "C" void *__libc_malloc(uptr size);
 extern "C" void *__libc_calloc(uptr size, uptr n);
 extern "C" void *__libc_realloc(void *ptr, uptr size);
 extern "C" void __libc_free(void *ptr);
+#if !SANITIZER_FREEBSD
 extern "C" int mallopt(int param, int value);
+#endif
 extern __sanitizer_FILE *stdout, *stderr;
 const int PTHREAD_MUTEX_RECURSIVE = 1;
 const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
@@ -91,19 +103,19 @@ typedef void (*sighandler_t)(int sig);
 
 #define errno (*__errno_location())
 
-// 16K loaded modules should be enough for everyone.
-static const uptr kMaxModules = 1 << 14;
-static LoadedModule *modules;
-static uptr nmodules;
-
 struct sigaction_t {
   union {
     sighandler_t sa_handler;
     void (*sa_sigaction)(int sig, my_siginfo_t *siginfo, void *uctx);
   };
+#if SANITIZER_FREEBSD
+  int sa_flags;
+  __sanitizer_sigset_t sa_mask;
+#else
   __sanitizer_sigset_t sa_mask;
   int sa_flags;
   void (*sa_restorer)();
+#endif
 };
 
 const sighandler_t SIG_DFL = (sighandler_t)0;
@@ -202,7 +214,7 @@ ScopedInterceptor::~ScopedInterceptor() {
     ThreadState *thr = cur_thread(); \
     const uptr caller_pc = GET_CALLER_PC(); \
     ScopedInterceptor si(thr, #func, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+    const uptr pc = StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -218,7 +230,11 @@ ScopedInterceptor::~ScopedInterceptor() {
 
 #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
 #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
-#define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#if SANITIZER_FREEBSD
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
+#else
+# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
+#endif
 
 #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
 
@@ -271,63 +287,24 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
   return res;
 }
 
-class AtExitContext {
- public:
-  AtExitContext()
-    : mtx_(MutexTypeAtExit, StatMtxAtExit)
-    , stack_(MBlockAtExit) {
-  }
-
-  typedef void(*atexit_cb_t)();
-
-  int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
-             atexit_cb_t f, void *arg, void *dso) {
-    Lock l(&mtx_);
-    Release(thr, pc, (uptr)this);
-    atexit_t *a = stack_.PushBack();
-    a->cb = f;
-    a->arg = arg;
-    a->dso = dso;
-    a->is_on_exit = is_on_exit;
-    return 0;
-  }
-
-  void exit(ThreadState *thr, uptr pc) {
-    for (;;) {
-      atexit_t a = {};
-      {
-        Lock l(&mtx_);
-        if (stack_.Size() != 0) {
-          a = stack_[stack_.Size() - 1];
-          stack_.PopBack();
-          Acquire(thr, pc, (uptr)this);
-        }
-      }
-      if (a.cb == 0)
-        break;
-      VPrintf(2, "#%d: executing atexit func %p(%p) dso=%p\n",
-          thr->tid, a.cb, a.arg, a.dso);
-      if (a.is_on_exit)
-        ((void(*)(int status, void *arg))a.cb)(0, a.arg);
-      else
-        ((void(*)(void *arg, void *dso))a.cb)(a.arg, a.dso);
-    }
-  }
-
- private:
-  struct atexit_t {
-    atexit_cb_t cb;
-    void *arg;
-    void *dso;
-    bool is_on_exit;
-  };
-
-  static const int kMaxAtExit = 1024;
-  Mutex mtx_;
-  Vector<atexit_t> stack_;
+// The sole reason tsan wraps atexit callbacks is to establish synchronization
+// between callback setup and callback execution.
+struct AtExitCtx {
+  void (*f)();
+  void *arg;
 };
 
-static AtExitContext *atexit_ctx;
+static void at_exit_wrapper(void *arg) {
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  Acquire(thr, pc, (uptr)arg);
+  AtExitCtx *ctx = (AtExitCtx*)arg;
+  ((void(*)(void *arg))ctx->f)(ctx->arg);
+  __libc_free(ctx);
+}
+
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+      void *arg, void *dso);
 
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
   if (cur_thread()->in_symbolizer)
@@ -335,40 +312,51 @@ TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
   // We want to setup the atexit callback even if we are in ignored lib
   // or after fork.
   SCOPED_INTERCEPTOR_RAW(atexit, f);
-  return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0, 0);
+  return setup_at_exit_wrapper(thr, pc, (void(*)())f, 0, 0);
 }
 
-TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
   if (cur_thread()->in_symbolizer)
     return 0;
-  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
-  return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg, 0);
+  SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+  return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso);
 }
 
-bool IsSaticModule(void *dso) {
-  if (modules == 0)
-    return false;
-  for (uptr i = 0; i < nmodules; i++) {
-    if (modules[i].containsAddress((uptr)dso))
-      return true;
-  }
-  return false;
+static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
+      void *arg, void *dso) {
+  AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+  ctx->f = f;
+  ctx->arg = arg;
+  Release(thr, pc, (uptr)ctx);
+  // Memory allocation in __cxa_atexit will race with free during exit,
+  // because we do not see synchronization around atexit callback list.
+  ThreadIgnoreBegin(thr, pc);
+  int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso);
+  ThreadIgnoreEnd(thr, pc);
+  return res;
 }
 
-TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+static void on_exit_wrapper(int status, void *arg) {
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  Acquire(thr, pc, (uptr)arg);
+  AtExitCtx *ctx = (AtExitCtx*)arg;
+  ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
+  __libc_free(ctx);
+}
+
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
   if (cur_thread()->in_symbolizer)
     return 0;
-  SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
-  // If it's the main executable or a statically loaded library,
-  // we will call the callback.
-  if (dso == 0 || IsSaticModule(dso))
-    return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg, dso);
-
-  // Dynamically load module, don't know when to call the callback for it.
+  SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+  AtExitCtx *ctx = (AtExitCtx*)__libc_malloc(sizeof(AtExitCtx));
+  ctx->f = (void(*)())f;
+  ctx->arg = arg;
+  Release(thr, pc, (uptr)ctx);
   // Memory allocation in __cxa_atexit will race with free during exit,
   // because we do not see synchronization around atexit callback list.
   ThreadIgnoreBegin(thr, pc);
-  int res = REAL(__cxa_atexit)(f, arg, dso);
+  int res = REAL(on_exit)(on_exit_wrapper, ctx);
   ThreadIgnoreEnd(thr, pc);
   return res;
 }
@@ -406,7 +394,11 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
 }
 
 static void LongJmp(ThreadState *thr, uptr *env) {
+#if SANITIZER_FREEBSD
+  uptr mangled_sp = env[2];
+#else
   uptr mangled_sp = env[6];
+#endif  // SANITIZER_FREEBSD
   // Find the saved buf by mangled_sp.
   for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
     JmpBuf *buf = &thr->jmp_bufs[i];
@@ -751,6 +743,7 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
                            int flags, int fd, u64 off) {
   SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off);
@@ -764,6 +757,10 @@ TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
   }
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64)
+#else
+#define TSAN_MAYBE_INTERCEPT_MMAP64
+#endif
 
 TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
   SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz);
@@ -772,10 +769,15 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
   return user_alloc(thr, pc, sz, align);
 }
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
+#else
+#define TSAN_MAYBE_INTERCEPT_MEMALIGN
+#endif
 
 TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
@@ -787,11 +789,16 @@ TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
   sz = RoundUp(sz, GetPageSizeCached());
   return user_alloc(thr, pc, sz, GetPageSizeCached());
 }
+#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
+#else
+#define TSAN_MAYBE_INTERCEPT_PVALLOC
+#endif
 
 TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
   SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
@@ -863,11 +870,13 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
     ThreadState *thr = cur_thread();
     // Thread-local state is not initialized yet.
     ScopedIgnoreInterceptors ignore;
+    ThreadIgnoreBegin(thr, 0);
     if (pthread_setspecific(g_thread_finalize_key,
                             (void *)kPthreadDestructorIterations)) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
     }
+    ThreadIgnoreEnd(thr, 0);
     while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
       pthread_yield();
     atomic_store(&p->tid, 0, memory_order_release);
@@ -1336,73 +1345,135 @@ TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) {
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
   return REAL(__xstat)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___XSTAT TSAN_INTERCEPT(__xstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(stat, path, buf);
+  return REAL(stat)(path, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
   return REAL(__xstat)(0, path, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
   return REAL(__xstat64)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___XSTAT64 TSAN_INTERCEPT(__xstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___XSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
   return REAL(__xstat64)(0, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_STAT64 TSAN_INTERCEPT(stat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_STAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
   return REAL(__lxstat)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___LXSTAT TSAN_INTERCEPT(__lxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(lstat, path, buf);
+  return REAL(lstat)(path, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
   return REAL(__lxstat)(0, path, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
   return REAL(__lxstat64)(version, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64 TSAN_INTERCEPT(__lxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___LXSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
   return REAL(__lxstat64)(0, path, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_LSTAT64 TSAN_INTERCEPT(lstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_LSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat)(version, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT
+#endif
 
 TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+#if SANITIZER_FREEBSD
+  SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(fstat)(fd, buf);
+#else
   SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat)(0, fd, buf);
+#endif
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat64)(version, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT___FXSTAT64
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
   SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(__fxstat64)(0, fd, buf);
 }
+#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_FSTAT64
+#endif
 
 TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
@@ -1412,6 +1483,7 @@ TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
   return fd;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
   SCOPED_TSAN_INTERCEPTOR(open64, name, flags, mode);
   int fd = REAL(open64)(name, flags, mode);
@@ -1419,6 +1491,10 @@ TSAN_INTERCEPTOR(int, open64, const char *name, int flags, int mode) {
     FdFileCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64)
+#else
+#define TSAN_MAYBE_INTERCEPT_OPEN64
+#endif
 
 TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
@@ -1428,6 +1504,7 @@ TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
   return fd;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
   SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
   int fd = REAL(creat64)(name, mode);
@@ -1435,6 +1512,10 @@ TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
     FdFileCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64)
+#else
+#define TSAN_MAYBE_INTERCEPT_CREAT64
+#endif
 
 TSAN_INTERCEPTOR(int, dup, int oldfd) {
   SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
@@ -1460,6 +1541,7 @@ TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
   return newfd2;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
   SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
   int fd = REAL(eventfd)(initval, flags);
@@ -1467,7 +1549,12 @@ TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
     FdEventCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_EVENTFD
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
   SCOPED_TSAN_INTERCEPTOR(signalfd, fd, mask, flags);
   if (fd >= 0)
@@ -1477,7 +1564,12 @@ TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
     FdSignalCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd)
+#else
+#define TSAN_MAYBE_INTERCEPT_SIGNALFD
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, inotify_init, int fake) {
   SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
   int fd = REAL(inotify_init)(fake);
@@ -1485,7 +1577,12 @@ TSAN_INTERCEPTOR(int, inotify_init, int fake) {
     FdInotifyCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
   SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
   int fd = REAL(inotify_init1)(flags);
@@ -1493,6 +1590,10 @@ TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
     FdInotifyCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1)
+#else
+#define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1
+#endif
 
 TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) {
   SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol);
@@ -1535,6 +1636,7 @@ TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_create, int size) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
   int fd = REAL(epoll_create)(size);
@@ -1542,7 +1644,12 @@ TSAN_INTERCEPTOR(int, epoll_create, int size) {
     FdPollCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE TSAN_INTERCEPT(epoll_create)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
   SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
   int fd = REAL(epoll_create1)(flags);
@@ -1550,6 +1657,10 @@ TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
     FdPollCreate(thr, pc, fd);
   return fd;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1 TSAN_INTERCEPT(epoll_create1)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1
+#endif
 
 TSAN_INTERCEPTOR(int, close, int fd) {
   SCOPED_TSAN_INTERCEPTOR(close, fd);
@@ -1558,14 +1669,20 @@ TSAN_INTERCEPTOR(int, close, int fd) {
   return REAL(close)(fd);
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, __close, int fd) {
   SCOPED_TSAN_INTERCEPTOR(__close, fd);
   if (fd >= 0)
     FdClose(thr, pc, fd);
   return REAL(__close)(fd);
 }
+#define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close)
+#else
+#define TSAN_MAYBE_INTERCEPT___CLOSE
+#endif
 
 // glibc guts
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
   SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
   int fds[64];
@@ -1576,6 +1693,10 @@ TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
   }
   REAL(__res_iclose)(state, free_addr);
 }
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose)
+#else
+#define TSAN_MAYBE_INTERCEPT___RES_ICLOSE
+#endif
 
 TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
@@ -1642,6 +1763,7 @@ TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
   SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
   void *res = REAL(tmpfile64)(fake);
@@ -1652,6 +1774,10 @@ TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
   }
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64)
+#else
+#define TSAN_MAYBE_INTERCEPT_TMPFILE64
+#endif
 
 TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
   // libc file streams can call user-supplied functions, see fopencookie.
@@ -1698,6 +1824,7 @@ TSAN_INTERCEPTOR(void*, opendir, char *path) {
   return res;
 }
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
   SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
   if (epfd >= 0)
@@ -1709,7 +1836,12 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
   int res = REAL(epoll_ctl)(epfd, op, fd, ev);
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL TSAN_INTERCEPT(epoll_ctl)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_CTL
+#endif
 
+#if !SANITIZER_FREEBSD
 TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
   SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
   if (epfd >= 0)
@@ -1719,6 +1851,10 @@ TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
     FdAcquire(thr, pc, epfd);
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT TSAN_INTERCEPT(epoll_wait)
+#else
+#define TSAN_MAYBE_INTERCEPT_EPOLL_WAIT
+#endif
 
 namespace __tsan {
 
@@ -1746,12 +1882,12 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
   // from rtl_generic_sighandler) we have not yet received the reraised
   // signal; and it looks too fragile to intercept all ways to reraise a signal.
   if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
-    __tsan::StackTrace stack;
-    stack.ObtainCurrent(thr, pc);
+    VarSizeStackTrace stack;
+    ObtainCurrentStack(thr, pc, &stack);
     ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeErrnoInSignal);
     if (!IsFiredSuppression(ctx, rep, stack)) {
-      rep.AddStack(&stack, true);
+      rep.AddStack(stack, true);
       OutputReport(thr, rep);
     }
   }
@@ -2226,8 +2362,6 @@ namespace __tsan {
 
 static void finalize(void *arg) {
   ThreadState *thr = cur_thread();
-  uptr pc = 0;
-  atexit_ctx->exit(thr, pc);
   int status = Finalize(thr);
   // Make sure the output is not lost.
   // Flushing all the streams here may freeze the process if a child thread is
@@ -2250,8 +2384,10 @@ void InitializeInterceptors() {
   REAL(memcmp) = internal_memcmp;
 
   // Instruct libc malloc to consume less memory.
+#if !SANITIZER_FREEBSD
   mallopt(1, 0);  // M_MXFAST
   mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
+#endif
 
   InitializeCommonInterceptors();
 
@@ -2273,11 +2409,11 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(free);
   TSAN_INTERCEPT(cfree);
   TSAN_INTERCEPT(mmap);
-  TSAN_INTERCEPT(mmap64);
+  TSAN_MAYBE_INTERCEPT_MMAP64;
   TSAN_INTERCEPT(munmap);
-  TSAN_INTERCEPT(memalign);
+  TSAN_MAYBE_INTERCEPT_MEMALIGN;
   TSAN_INTERCEPT(valloc);
-  TSAN_INTERCEPT(pvalloc);
+  TSAN_MAYBE_INTERCEPT_PVALLOC;
   TSAN_INTERCEPT(posix_memalign);
 
   TSAN_INTERCEPT(strlen);
@@ -2340,38 +2476,38 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(sem_getvalue);
 
   TSAN_INTERCEPT(stat);
-  TSAN_INTERCEPT(__xstat);
-  TSAN_INTERCEPT(stat64);
-  TSAN_INTERCEPT(__xstat64);
+  TSAN_MAYBE_INTERCEPT___XSTAT;
+  TSAN_MAYBE_INTERCEPT_STAT64;
+  TSAN_MAYBE_INTERCEPT___XSTAT64;
   TSAN_INTERCEPT(lstat);
-  TSAN_INTERCEPT(__lxstat);
-  TSAN_INTERCEPT(lstat64);
-  TSAN_INTERCEPT(__lxstat64);
+  TSAN_MAYBE_INTERCEPT___LXSTAT;
+  TSAN_MAYBE_INTERCEPT_LSTAT64;
+  TSAN_MAYBE_INTERCEPT___LXSTAT64;
   TSAN_INTERCEPT(fstat);
-  TSAN_INTERCEPT(__fxstat);
-  TSAN_INTERCEPT(fstat64);
-  TSAN_INTERCEPT(__fxstat64);
+  TSAN_MAYBE_INTERCEPT___FXSTAT;
+  TSAN_MAYBE_INTERCEPT_FSTAT64;
+  TSAN_MAYBE_INTERCEPT___FXSTAT64;
   TSAN_INTERCEPT(open);
-  TSAN_INTERCEPT(open64);
+  TSAN_MAYBE_INTERCEPT_OPEN64;
   TSAN_INTERCEPT(creat);
-  TSAN_INTERCEPT(creat64);
+  TSAN_MAYBE_INTERCEPT_CREAT64;
   TSAN_INTERCEPT(dup);
   TSAN_INTERCEPT(dup2);
   TSAN_INTERCEPT(dup3);
-  TSAN_INTERCEPT(eventfd);
-  TSAN_INTERCEPT(signalfd);
-  TSAN_INTERCEPT(inotify_init);
-  TSAN_INTERCEPT(inotify_init1);
+  TSAN_MAYBE_INTERCEPT_EVENTFD;
+  TSAN_MAYBE_INTERCEPT_SIGNALFD;
+  TSAN_MAYBE_INTERCEPT_INOTIFY_INIT;
+  TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1;
   TSAN_INTERCEPT(socket);
   TSAN_INTERCEPT(socketpair);
   TSAN_INTERCEPT(connect);
   TSAN_INTERCEPT(bind);
   TSAN_INTERCEPT(listen);
-  TSAN_INTERCEPT(epoll_create);
-  TSAN_INTERCEPT(epoll_create1);
+  TSAN_MAYBE_INTERCEPT_EPOLL_CREATE;
+  TSAN_MAYBE_INTERCEPT_EPOLL_CREATE1;
   TSAN_INTERCEPT(close);
-  TSAN_INTERCEPT(__close);
-  TSAN_INTERCEPT(__res_iclose);
+  TSAN_MAYBE_INTERCEPT___CLOSE;
+  TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
   TSAN_INTERCEPT(pipe);
   TSAN_INTERCEPT(pipe2);
 
@@ -2381,7 +2517,7 @@ void InitializeInterceptors() {
 
   TSAN_INTERCEPT(unlink);
   TSAN_INTERCEPT(tmpfile);
-  TSAN_INTERCEPT(tmpfile64);
+  TSAN_MAYBE_INTERCEPT_TMPFILE64;
   TSAN_INTERCEPT(fread);
   TSAN_INTERCEPT(fwrite);
   TSAN_INTERCEPT(abort);
@@ -2389,8 +2525,8 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(rmdir);
   TSAN_INTERCEPT(opendir);
 
-  TSAN_INTERCEPT(epoll_ctl);
-  TSAN_INTERCEPT(epoll_wait);
+  TSAN_MAYBE_INTERCEPT_EPOLL_CTL;
+  TSAN_MAYBE_INTERCEPT_EPOLL_WAIT;
 
   TSAN_INTERCEPT(sigaction);
   TSAN_INTERCEPT(signal);
@@ -2413,9 +2549,6 @@ void InitializeInterceptors() {
   // Need to setup it, because interceptors check that the function is resolved.
   // But atexit is emitted directly into the module, so can't be resolved.
   REAL(atexit) = (int(*)(void(*)()))unreachable;
-  atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
-      AtExitContext();
-
   if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
     Printf("ThreadSanitizer: failed to setup atexit callback\n");
     Die();
@@ -2427,11 +2560,6 @@ void InitializeInterceptors() {
   }
 
   FdInit();
-
-  // Remember list of loaded libraries for atexit interceptors.
-  modules = (LoadedModule*)MmapOrDie(sizeof(*modules)*kMaxModules,
-      "LoadedModule");
-  nmodules = GetListOfModules(modules, kMaxModules, 0);
 }
 
 void *internal_start_thread(void(*func)(void *arg), void *arg) {
index 85de2e6..b44e568 100644 (file)
@@ -52,7 +52,7 @@ class ScopedAnnotation {
     StatInc(thr, StatAnnotation); \
     StatInc(thr, Stat##typ); \
     ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \
-    const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+    const uptr pc = StackTrace::GetCurrentPc(); \
     (void)pc; \
 /**/
 
@@ -452,4 +452,6 @@ const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
 
 void INTERFACE_ATTRIBUTE
 AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
+void INTERFACE_ATTRIBUTE
+AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
 }  // extern "C"
index 316614d..15fc21c 100644 (file)
@@ -472,7 +472,7 @@ static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
 
 #define SCOPED_ATOMIC(func, ...) \
     const uptr callpc = (uptr)__builtin_return_address(0); \
-    uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+    uptr pc = StackTrace::GetCurrentPc(); \
     mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
     ThreadState *const thr = cur_thread(); \
     if (thr->ignore_interceptors) \
index 03a9e28..6e1ec6d 100644 (file)
@@ -59,7 +59,7 @@ static JavaContext *jctx;
 #define SCOPED_JAVA_FUNC(func) \
   ThreadState *thr = cur_thread(); \
   const uptr caller_pc = GET_CALLER_PC(); \
-  const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+  const uptr pc = StackTrace::GetCurrentPc(); \
   (void)pc; \
   ScopedJavaFunc scoped(thr, caller_pc); \
 /**/
index 2eae60d..d89610a 100644 (file)
@@ -64,17 +64,17 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
   if (atomic_load(&thr->in_signal_handler, memory_order_relaxed) == 0 ||
       !flags()->report_signal_unsafe)
     return;
-  StackTrace stack;
-  stack.ObtainCurrent(thr, pc);
+  VarSizeStackTrace stack;
+  ObtainCurrentStack(thr, pc, &stack);
   ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(ReportTypeSignalUnsafe);
   if (!IsFiredSuppression(ctx, rep, stack)) {
-    rep.AddStack(&stack, true);
+    rep.AddStack(stack, true);
     OutputReport(thr, rep);
   }
 }
 
-void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
   if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
     return AllocatorReturnNull();
   void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
@@ -82,15 +82,17 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
     return 0;
   if (ctx && ctx->initialized)
     OnUserAlloc(thr, pc, (uptr)p, sz, true);
-  SignalUnsafeCall(thr, pc);
+  if (signal)
+    SignalUnsafeCall(thr, pc);
   return p;
 }
 
-void user_free(ThreadState *thr, uptr pc, void *p) {
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
   if (ctx && ctx->initialized)
     OnUserFree(thr, pc, (uptr)p, true);
   allocator()->Deallocate(&thr->alloc_cache, p);
-  SignalUnsafeCall(thr, pc);
+  if (signal)
+    SignalUnsafeCall(thr, pc);
 }
 
 void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
index ab8eb83..fe020af 100644 (file)
@@ -24,9 +24,9 @@ void AllocatorPrintStats();
 
 // For user allocations.
 void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
-                 uptr align = kDefaultAlignment);
+                 uptr align = kDefaultAlignment, bool signal = true);
 // Does not accept NULL.
-void user_free(ThreadState *thr, uptr pc, void *p);
+void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
 void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
 void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
 uptr user_alloc_usable_size(const void *p);
index b7a6376..35837d2 100644 (file)
 // Platform-specific code.
 //===----------------------------------------------------------------------===//
 
+#ifndef TSAN_PLATFORM_H
+#define TSAN_PLATFORM_H
+
+#if !defined(__LP64__) && !defined(_WIN64)
+# error "Only 64-bit is supported"
+#endif
+
+#include "tsan_defs.h"
+#include "tsan_trace.h"
+
+namespace __tsan {
+
+#if !defined(TSAN_GO)
+
 /*
-C++ linux memory layout:
-0000 0000 0000 - 03c0 0000 0000: protected
-03c0 0000 0000 - 1000 0000 0000: shadow
-1000 0000 0000 - 3000 0000 0000: protected
+C/C++ on linux and freebsd
+0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings
+0100 0000 0000 - 0200 0000 0000: -
+0200 0000 0000 - 1000 0000 0000: shadow
+1000 0000 0000 - 3000 0000 0000: -
 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 6000 0000 0000: protected
+4000 0000 0000 - 6000 0000 0000: -
 6000 0000 0000 - 6200 0000 0000: traces
 6200 0000 0000 - 7d00 0000 0000: -
 7d00 0000 0000 - 7e00 0000 0000: heap
-7e00 0000 0000 - 7fff ffff ffff: modules and main thread stack
+7e00 0000 0000 - 7e80 0000 0000: -
+7e80 0000 0000 - 8000 0000 0000: modules and main thread stack
+*/
 
-Go linux and darwin memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
-0000 1000 0000 - 00f8 0000 0000: -
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg   = 0x600000000000ull;
+const uptr kTraceMemEnd   = 0x620000000000ull;
+const uptr kShadowBeg     = 0x020000000000ull;
+const uptr kShadowEnd     = 0x100000000000ull;
+const uptr kHeapMemBeg    = 0x7d0000000000ull;
+const uptr kHeapMemEnd    = 0x7e0000000000ull;
+const uptr kLoAppMemBeg   = 0x000000001000ull;
+const uptr kLoAppMemEnd   = 0x010000000000ull;
+const uptr kHiAppMemBeg   = 0x7e8000000000ull;
+const uptr kHiAppMemEnd   = 0x800000000000ull;
+const uptr kAppMemMsk     = 0x7c0000000000ull;
+const uptr kAppMemXor     = 0x020000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return (mem >= kHeapMemBeg && mem < kHeapMemEnd) ||
+         (mem >= kLoAppMemBeg && mem < kLoAppMemEnd) ||
+         (mem >= kHiAppMemBeg && mem < kHiAppMemEnd);
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (((x) & ~(kAppMemMsk | (kShadowCell - 1)))
+      ^ kAppMemXor) * kShadowCnt;
+}
+
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((((x) & ~(kAppMemMsk | (kMetaShadowCell - 1)))
+      ^ kAppMemXor) / kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  if (s >= MemToShadow(kLoAppMemBeg) && s <= MemToShadow(kLoAppMemEnd - 1))
+    return (s / kShadowCnt) ^ kAppMemXor;
+  else
+    return ((s / kShadowCnt) ^ kAppMemXor) | kAppMemMsk;
+}
+
+static USED uptr UserRegions[] = {
+  kLoAppMemBeg, kLoAppMemEnd,
+  kHiAppMemBeg, kHiAppMemEnd,
+  kHeapMemBeg,  kHeapMemEnd,
+};
+
+#elif defined(TSAN_GO) && !SANITIZER_WINDOWS
+
+/* Go on linux, darwin and freebsd
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00c0 0000 0000: -
 00c0 0000 0000 - 00e0 0000 0000: heap
-00e0 0000 0000 - 1000 0000 0000: -
-1000 0000 0000 - 1380 0000 0000: shadow
-1460 0000 0000 - 2000 0000 0000: -
+00e0 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2380 0000 0000: shadow
+2380 0000 0000 - 3000 0000 0000: -
 3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
 4000 0000 0000 - 6000 0000 0000: -
 6000 0000 0000 - 6200 0000 0000: traces
-6200 0000 0000 - 7fff ffff ffff: -
+6200 0000 0000 - 8000 0000 0000: -
+*/
+
+const uptr kMetaShadowBeg = 0x300000000000ull;
+const uptr kMetaShadowEnd = 0x400000000000ull;
+const uptr kTraceMemBeg   = 0x600000000000ull;
+const uptr kTraceMemEnd   = 0x620000000000ull;
+const uptr kShadowBeg     = 0x200000000000ull;
+const uptr kShadowEnd     = 0x238000000000ull;
+const uptr kAppMemBeg     = 0x000000001000ull;
+const uptr kAppMemEnd     = 0x00e000000000ull;
+
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
+
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
+}
+
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
+
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
+}
 
-Go windows memory layout:
-0000 0000 0000 - 0000 1000 0000: executable
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+      kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg);
+}
+
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  return (s & ~kShadowBeg) / kShadowCnt;
+}
+
+static USED uptr UserRegions[] = {
+  kAppMemBeg, kAppMemEnd,
+};
+
+#elif defined(TSAN_GO) && SANITIZER_WINDOWS
+
+/* Go on windows
+0000 0000 1000 - 0000 1000 0000: executable
 0000 1000 0000 - 00f8 0000 0000: -
 00c0 0000 0000 - 00e0 0000 0000: heap
 00e0 0000 0000 - 0100 0000 0000: -
-0100 0000 0000 - 0560 0000 0000: shadow
+0100 0000 0000 - 0380 0000 0000: shadow
+0380 0000 0000 - 0560 0000 0000: -
 0560 0000 0000 - 0760 0000 0000: traces
 0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects)
-07d0 0000 0000 - 07ff ffff ffff: -
+07d0 0000 0000 - 8000 0000 0000: -
 */
 
-#ifndef TSAN_PLATFORM_H
-#define TSAN_PLATFORM_H
-
-#include "tsan_defs.h"
-#include "tsan_trace.h"
-
-#if defined(__LP64__) || defined(_WIN64)
-namespace __tsan {
-
-#if defined(TSAN_GO)
-static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x04dfffffffffULL;
-# if SANITIZER_WINDOWS
-static const uptr kLinuxShadowMsk = 0x010000000000ULL;
-static const uptr kMetaShadow     = 0x076000000000ULL;
-static const uptr kMetaSize       = 0x007000000000ULL;
-# else  // if SANITIZER_WINDOWS
-static const uptr kLinuxShadowMsk = 0x200000000000ULL;
-static const uptr kMetaShadow     = 0x300000000000ULL;
-static const uptr kMetaSize       = 0x100000000000ULL;
-# endif  // if SANITIZER_WINDOWS
-#else  // defined(TSAN_GO)
-static const uptr kMetaShadow     = 0x300000000000ULL;
-static const uptr kMetaSize       = 0x100000000000ULL;
-static const uptr kLinuxAppMemBeg = 0x7cf000000000ULL;
-static const uptr kLinuxAppMemEnd = 0x7fffffffffffULL;
-#endif
+const uptr kMetaShadowBeg = 0x076000000000ull;
+const uptr kMetaShadowEnd = 0x07d000000000ull;
+const uptr kTraceMemBeg   = 0x056000000000ull;
+const uptr kTraceMemEnd   = 0x076000000000ull;
+const uptr kShadowBeg     = 0x010000000000ull;
+const uptr kShadowEnd     = 0x038000000000ull;
+const uptr kAppMemBeg     = 0x000000001000ull;
+const uptr kAppMemEnd     = 0x00e000000000ull;
 
-static const uptr kLinuxAppMemMsk = 0x7c0000000000ULL;
+ALWAYS_INLINE
+bool IsAppMem(uptr mem) {
+  return mem >= kAppMemBeg && mem < kAppMemEnd;
+}
 
-#if SANITIZER_WINDOWS
-const uptr kTraceMemBegin = 0x056000000000ULL;
-#else
-const uptr kTraceMemBegin = 0x600000000000ULL;
-#endif
-const uptr kTraceMemSize = 0x020000000000ULL;
-
-// This has to be a macro to allow constant initialization of constants below.
-#ifndef TSAN_GO
-#define MemToShadow(addr) \
-    ((((uptr)addr) & ~(kLinuxAppMemMsk | (kShadowCell - 1))) * kShadowCnt)
-#define MemToMeta(addr) \
-    (u32*)(((((uptr)addr) & ~(kLinuxAppMemMsk | (kMetaShadowCell - 1))) \
-    / kMetaShadowCell * kMetaShadowSize) | kMetaShadow)
-#else
-#define MemToShadow(addr) \
-    (((((uptr)addr) & ~(kShadowCell - 1)) * kShadowCnt) | kLinuxShadowMsk)
-#define MemToMeta(addr) \
-    (u32*)(((((uptr)addr) & ~(kMetaShadowCell - 1)) \
-    / kMetaShadowCell * kMetaShadowSize) | kMetaShadow)
-#endif
+ALWAYS_INLINE
+bool IsShadowMem(uptr mem) {
+  return mem >= kShadowBeg && mem <= kShadowEnd;
+}
 
-static const uptr kLinuxShadowBeg = MemToShadow(kLinuxAppMemBeg);
-static const uptr kLinuxShadowEnd =
-    MemToShadow(kLinuxAppMemEnd) | 0xff;
+ALWAYS_INLINE
+bool IsMetaMem(uptr mem) {
+  return mem >= kMetaShadowBeg && mem <= kMetaShadowEnd;
+}
 
-static inline bool IsAppMem(uptr mem) {
-#if defined(TSAN_GO)
-  return mem <= kLinuxAppMemEnd;
-#else
-  return mem >= kLinuxAppMemBeg && mem <= kLinuxAppMemEnd;
-#endif
+ALWAYS_INLINE
+uptr MemToShadow(uptr x) {
+  DCHECK(IsAppMem(x));
+  return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg;
 }
 
-static inline bool IsShadowMem(uptr mem) {
-  return mem >= kLinuxShadowBeg && mem <= kLinuxShadowEnd;
+ALWAYS_INLINE
+u32 *MemToMeta(uptr x) {
+  DCHECK(IsAppMem(x));
+  return (u32*)(((x & ~(kMetaShadowCell - 1)) / \
+      kMetaShadowCell * kMetaShadowSize) | kMetaShadowEnd);
 }
 
-static inline uptr ShadowToMem(uptr shadow) {
-  CHECK(IsShadowMem(shadow));
-#ifdef TSAN_GO
-  return (shadow & ~kLinuxShadowMsk) / kShadowCnt;
-#else
-  return (shadow / kShadowCnt) | kLinuxAppMemMsk;
-#endif
+ALWAYS_INLINE
+uptr ShadowToMem(uptr s) {
+  CHECK(IsShadowMem(s));
+  // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection.
+  return (x & ~kShadowBeg) / kShadowCnt;
 }
 
-void FlushShadowMemory();
-void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
-uptr GetRSS();
+static USED uptr UserRegions[] = {
+  kAppMemBeg, kAppMemEnd,
+};
 
-void InitializePlatform();
-void FinalizePlatform();
+#else
+# error "Unknown platform"
+#endif
 
 // The additional page is to catch shadow stack overflow as paging fault.
 // Windows wants 64K alignment for mmaps.
@@ -135,18 +234,23 @@ const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace)
     + (64 << 10) + (64 << 10) - 1) & ~((64 << 10) - 1);
 
 uptr ALWAYS_INLINE GetThreadTrace(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
-  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize;
+  DCHECK_LT(p, kTraceMemEnd);
   return p;
 }
 
 uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
-  uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+  uptr p = kTraceMemBeg + (uptr)tid * kTotalTraceSize
       + kTraceSize * sizeof(Event);
-  DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
+  DCHECK_LT(p, kTraceMemEnd);
   return p;
 }
 
+void InitializePlatform();
+void FlushShadowMemory();
+void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
+uptr GetRSS();
+
 void *internal_start_thread(void(*func)(void*), void *arg);
 void internal_join_thread(void *th);
 
@@ -162,8 +266,4 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
 
 }  // namespace __tsan
 
-#else  // defined(__LP64__) || defined(_WIN64)
-# error "Only 64-bit is supported"
-#endif
-
 #endif  // TSAN_PLATFORM_H
index ba81fd2..3259131 100644 (file)
@@ -7,7 +7,7 @@
 //
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
-// Linux-specific code.
+// Linux- and FreeBSD-specific code.
 //===----------------------------------------------------------------------===//
 
 
@@ -18,6 +18,7 @@
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 #include "sanitizer_common/sanitizer_stoptheworld.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
 #include "tsan_flags.h"
@@ -60,6 +61,9 @@ void *__libc_stack_end = 0;
 
 namespace __tsan {
 
+static uptr g_data_start;
+static uptr g_data_end;
+
 const uptr kPageSize = 4096;
 
 enum {
@@ -74,22 +78,26 @@ enum {
   MemCount  = 8,
 };
 
-void FillProfileCallback(uptr start, uptr rss, bool file,
+void FillProfileCallback(uptr p, uptr rss, bool file,
                          uptr *mem, uptr stats_size) {
   mem[MemTotal] += rss;
-  start >>= 40;
-  if (start < 0x10)
+  if (p >= kShadowBeg && p < kShadowEnd)
     mem[MemShadow] += rss;
-  else if (start >= 0x20 && start < 0x30)
-    mem[file ? MemFile : MemMmap] += rss;
-  else if (start >= 0x30 && start < 0x40)
+  else if (p >= kMetaShadowBeg && p < kMetaShadowEnd)
     mem[MemMeta] += rss;
-  else if (start >= 0x7e)
+#ifndef TSAN_GO
+  else if (p >= kHeapMemBeg && p < kHeapMemEnd)
+    mem[MemHeap] += rss;
+  else if (p >= kLoAppMemBeg && p < kLoAppMemEnd)
     mem[file ? MemFile : MemMmap] += rss;
-  else if (start >= 0x60 && start < 0x62)
+  else if (p >= kHiAppMemBeg && p < kHiAppMemEnd)
+    mem[file ? MemFile : MemMmap] += rss;
+#else
+  else if (p >= kAppMemBeg && p < kAppMemEnd)
+    mem[file ? MemFile : MemMmap] += rss;
+#endif
+  else if (p >= kTraceMemBeg && p < kTraceMemEnd)
     mem[MemTrace] += rss;
-  else if (start >= 0x7d && start < 0x7e)
-    mem[MemHeap] += rss;
   else
     mem[MemOther] += rss;
 }
@@ -97,12 +105,14 @@ void FillProfileCallback(uptr start, uptr rss, bool file,
 void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
   uptr mem[MemCount] = {};
   __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+  StackDepotStats *stacks = StackDepotGetStats();
   internal_snprintf(buf, buf_size,
       "RSS %zd MB: shadow:%zd meta:%zd file:%zd mmap:%zd"
-      " trace:%zd heap:%zd other:%zd nthr=%zd/%zd\n",
+      " trace:%zd heap:%zd other:%zd stacks=%zd[%zd] nthr=%zd/%zd\n",
       mem[MemTotal] >> 20, mem[MemShadow] >> 20, mem[MemMeta] >> 20,
       mem[MemFile] >> 20, mem[MemMmap] >> 20, mem[MemTrace] >> 20,
       mem[MemHeap] >> 20, mem[MemOther] >> 20,
+      stacks->allocated >> 20, stacks->n_uniq_ids,
       nlive, nthread);
 }
 
@@ -137,7 +147,7 @@ uptr GetRSS() {
 void FlushShadowMemoryCallback(
     const SuspendedThreadsList &suspended_threads_list,
     void *argument) {
-  FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
+  FlushUnneededShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg);
 }
 #endif
 
@@ -218,12 +228,12 @@ static void MapRodata() {
 
 void InitializeShadowMemory() {
   // Map memory shadow.
-  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
-    kLinuxShadowEnd - kLinuxShadowBeg);
-  if (shadow != kLinuxShadowBeg) {
+  uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+    kShadowEnd - kShadowBeg);
+  if (shadow != kShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
-               "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
+               "to link with -pie (%p, %p).\n", shadow, kShadowBeg);
     Die();
   }
   // This memory range is used for thread stacks and large user mmaps.
@@ -235,78 +245,42 @@ void InitializeShadowMemory() {
       0x10000000000ULL * kShadowMultiplier, MADV_NOHUGEPAGE);
 #endif
   DPrintf("memory shadow: %zx-%zx (%zuGB)\n",
-      kLinuxShadowBeg, kLinuxShadowEnd,
-      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
+      kShadowBeg, kShadowEnd,
+      (kShadowEnd - kShadowBeg) >> 30);
 
   // Map meta shadow.
-  if (MemToMeta(kLinuxAppMemBeg) < (u32*)kMetaShadow) {
-    Printf("ThreadSanitizer: bad meta shadow (%p -> %p < %p)\n",
-        kLinuxAppMemBeg, MemToMeta(kLinuxAppMemBeg), kMetaShadow);
-    Die();
-  }
-  if (MemToMeta(kLinuxAppMemEnd) >= (u32*)(kMetaShadow + kMetaSize)) {
-    Printf("ThreadSanitizer: bad meta shadow (%p -> %p >= %p)\n",
-        kLinuxAppMemEnd, MemToMeta(kLinuxAppMemEnd), kMetaShadow + kMetaSize);
-    Die();
-  }
-  uptr meta = (uptr)MmapFixedNoReserve(kMetaShadow, kMetaSize);
-  if (meta != kMetaShadow) {
+  uptr meta_size = kMetaShadowEnd - kMetaShadowBeg;
+  uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size);
+  if (meta != kMetaShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
-               "to link with -pie (%p, %p).\n", meta, kMetaShadow);
+               "to link with -pie (%p, %p).\n", meta, kMetaShadowBeg);
     Die();
   }
   DPrintf("meta shadow: %zx-%zx (%zuGB)\n",
-      kMetaShadow, kMetaShadow + kMetaSize, kMetaSize >> 30);
-
-  // Protect gaps.
-  const uptr kClosedLowBeg  = 0x200000;
-  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
-  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
-  const uptr kClosedMidEnd = min(min(kLinuxAppMemBeg, kTraceMemBegin),
-      kMetaShadow);
-
-  ProtectRange(kClosedLowBeg, kClosedLowEnd);
-  ProtectRange(kClosedMidBeg, kClosedMidEnd);
-  VPrintf(2, "kClosedLow   %zx-%zx (%zuGB)\n",
-      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
-  VPrintf(2, "kClosedMid   %zx-%zx (%zuGB)\n",
-      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
-  VPrintf(2, "app mem: %zx-%zx (%zuGB)\n",
-      kLinuxAppMemBeg, kLinuxAppMemEnd,
-      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
-  VPrintf(2, "stack: %zx\n", (uptr)&shadow);
+      meta, meta + meta_size, meta_size >> 30);
 
   MapRodata();
 }
-#endif
-
-static uptr g_data_start;
-static uptr g_data_end;
-
-#ifndef TSAN_GO
-static void CheckPIE() {
-  // Ensure that the binary is indeed compiled with -pie.
-  MemoryMappingLayout proc_maps(true);
-  uptr start, end;
-  if (proc_maps.Next(&start, &end,
-                     /*offset*/0, /*filename*/0, /*filename_size*/0,
-                     /*protection*/0)) {
-    if ((u64)start < kLinuxAppMemBeg) {
-      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
-             "something is mapped at 0x%zx < 0x%zx)\n",
-             start, kLinuxAppMemBeg);
-      Printf("FATAL: Make sure to compile with -fPIE"
-             " and to link with -pie.\n");
-      Die();
-    }
-  }
-}
 
 static void InitDataSeg() {
   MemoryMappingLayout proc_maps(true);
   uptr start, end, offset;
   char name[128];
+#if SANITIZER_FREEBSD
+  // On FreeBSD BSS is usually the last block allocated within the
+  // low range and heap is the last block allocated within the range
+  // 0x800000000-0x8ffffffff.
+  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
+                        /*protection*/ 0)) {
+    DPrintf("%p-%p %p %s\n", start, end, offset, name);
+    if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
+        name[0] == '\0') {
+      g_data_start = start;
+      g_data_end = end;
+    }
+  }
+#else
   bool prev_is_data = false;
   while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
                         /*protection*/ 0)) {
@@ -322,12 +296,35 @@ static void InitDataSeg() {
       g_data_end = end;
     prev_is_data = is_data;
   }
+#endif
   DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
   CHECK_LT(g_data_start, g_data_end);
   CHECK_GE((uptr)&g_data_start, g_data_start);
   CHECK_LT((uptr)&g_data_start, g_data_end);
 }
 
+static void CheckAndProtect() {
+  // Ensure that the binary is indeed compiled with -pie.
+  MemoryMappingLayout proc_maps(true);
+  uptr p, end;
+  while (proc_maps.Next(&p, &end, 0, 0, 0, 0)) {
+    if (IsAppMem(p))
+      continue;
+    if (p >= kHeapMemEnd &&
+        p < kHeapMemEnd + PrimaryAllocator::AdditionalSize())
+      continue;
+    if (p >= 0xf000000000000000ull)  // vdso
+      break;
+    Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+    Die();
+  }
+
+  ProtectRange(kLoAppMemEnd, kShadowBeg);
+  ProtectRange(kShadowEnd, kMetaShadowBeg);
+  ProtectRange(kMetaShadowEnd, kTraceMemBeg);
+  ProtectRange(kTraceMemEnd, kHeapMemBeg);
+  ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg);
+}
 #endif  // #ifndef TSAN_GO
 
 void InitializePlatform() {
@@ -363,7 +360,7 @@ void InitializePlatform() {
   }
 
 #ifndef TSAN_GO
-  CheckPIE();
+  CheckAndProtect();
   InitTlsSize();
   InitDataSeg();
 #endif
@@ -426,4 +423,4 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
 
 }  // namespace __tsan
 
-#endif  // SANITIZER_LINUX
+#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
index 95527c7..2091318 100644 (file)
@@ -54,20 +54,20 @@ uptr GetRSS() {
 
 #ifndef TSAN_GO
 void InitializeShadowMemory() {
-  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
-    kLinuxShadowEnd - kLinuxShadowBeg);
-  if (shadow != kLinuxShadowBeg) {
+  uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg,
+    kShadowEnd - kShadowBeg);
+  if (shadow != kShadowBeg) {
     Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
     Printf("FATAL: Make sure to compile with -fPIE and "
            "to link with -pie.\n");
     Die();
   }
-  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
-      kLinuxShadowBeg, kLinuxShadowEnd,
-      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
-  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
-      kLinuxAppMemBeg, kLinuxAppMemEnd,
-      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
+  DPrintf("kShadow %zx-%zx (%zuGB)\n",
+      kShadowBeg, kShadowEnd,
+      (kShadowEnd - kShadowBeg) >> 30);
+  DPrintf("kAppMem %zx-%zx (%zuGB)\n",
+      kAppMemBeg, kAppMemEnd,
+      (kAppMemEnd - kAppMemBeg) >> 30);
 }
 #endif
 
@@ -75,10 +75,6 @@ void InitializePlatform() {
   DisableCoreDumperIfNecessary();
 }
 
-void FinalizePlatform() {
-  fflush(0);
-}
-
 #ifndef TSAN_GO
 int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
     void *abstime), void *c, void *m, void *abstime,
index d6e9e6d..3f81c54 100644 (file)
@@ -36,10 +36,6 @@ uptr GetRSS() {
 void InitializePlatform() {
 }
 
-void FinalizePlatform() {
-  fflush(0);
-}
-
 }  // namespace __tsan
 
 #endif  // SANITIZER_WINDOWS
index b14856c..6feab81 100644 (file)
 #include "tsan_report.h"
 #include "tsan_platform.h"
 #include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
 
 namespace __tsan {
 
+ReportStack::ReportStack() : next(nullptr), info(), suppressable(false) {}
+
+ReportStack *ReportStack::New(uptr addr) {
+  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportStack));
+  ReportStack *res = new(mem) ReportStack();
+  res->info.address = addr;
+  return res;
+}
+
+ReportLocation::ReportLocation(ReportLocationType type)
+    : type(type), global(), heap_chunk_start(0), heap_chunk_size(0), tid(0),
+      fd(0), suppressable(false), stack(nullptr) {}
+
+ReportLocation *ReportLocation::New(ReportLocationType type) {
+  void *mem = internal_alloc(MBlockReportStack, sizeof(ReportLocation));
+  return new(mem) ReportLocation(type);
+}
+
 class Decorator: public __sanitizer::SanitizerCommonDecorator {
  public:
   Decorator() : SanitizerCommonDecorator() { }
@@ -68,6 +88,8 @@ static const char *ReportTypeString(ReportType typ) {
     return "data race on vptr (ctor/dtor vs virtual call)";
   if (typ == ReportTypeUseAfterFree)
     return "heap-use-after-free";
+  if (typ == ReportTypeVptrUseAfterFree)
+    return "heap-use-after-free (virtual call vs free)";
   if (typ == ReportTypeThreadLeak)
     return "thread leak";
   if (typ == ReportTypeMutexDestroyLocked)
@@ -94,14 +116,11 @@ void PrintStack(const ReportStack *ent) {
     Printf("    [failed to restore the stack]\n\n");
     return;
   }
-  for (int i = 0; ent; ent = ent->next, i++) {
-    Printf("    #%d %s %s:%d", i, ent->func, ent->file, ent->line);
-    if (ent->col)
-      Printf(":%d", ent->col);
-    if (ent->module && ent->offset)
-      Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
-    else
-      Printf(" (%p)\n", (void*)ent->pc);
+  for (int i = 0; ent && ent->info.address; ent = ent->next, i++) {
+    InternalScopedString res(2 * GetPageSizeCached());
+    RenderFrame(&res, common_flags()->stack_trace_format, i, ent->info,
+                common_flags()->strip_path_prefix, "__interceptor_");
+    Printf("%s\n", res.data());
   }
   Printf("\n");
 }
@@ -143,12 +162,15 @@ static void PrintLocation(const ReportLocation *loc) {
   bool print_stack = false;
   Printf("%s", d.Location());
   if (loc->type == ReportLocationGlobal) {
+    const DataInfo &global = loc->global;
     Printf("  Location is global '%s' of size %zu at %p (%s+%p)\n\n",
-               loc->name, loc->size, loc->addr, loc->module, loc->offset);
+           global.name, global.size, global.start,
+           StripModuleName(global.module), global.module_offset);
   } else if (loc->type == ReportLocationHeap) {
     char thrbuf[kThreadBufSize];
     Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
-        loc->size, loc->addr, thread_name(thrbuf, loc->tid));
+           loc->heap_chunk_size, loc->heap_chunk_start,
+           thread_name(thrbuf, loc->tid));
     print_stack = true;
   } else if (loc->type == ReportLocationStack) {
     Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
@@ -301,8 +323,10 @@ void PrintReport(const ReportDesc *rep) {
   if (rep->typ == ReportTypeThreadLeak && rep->count > 1)
     Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
 
-  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
-    ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+  if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep))) {
+    const AddressInfo &info = ent->info;
+    ReportErrorSummary(rep_typ_str, info.file, info.line, info.function);
+  }
 
   Printf("==================\n");
 }
@@ -317,8 +341,9 @@ void PrintStack(const ReportStack *ent) {
     return;
   }
   for (int i = 0; ent; ent = ent->next, i++) {
-    Printf("  %s()\n      %s:%d +0x%zx\n",
-        ent->func, ent->file, ent->line, (void*)ent->offset);
+    const AddressInfo &info = ent->info;
+    Printf("  %s()\n      %s:%d +0x%zx\n", info.function, info.file, info.line,
+           (void *)info.module_offset);
   }
 }
 
index 0bde59b..3d99c7a 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef TSAN_REPORT_H
 #define TSAN_REPORT_H
 
+#include "sanitizer_common/sanitizer_symbolizer.h"
 #include "tsan_defs.h"
 #include "tsan_vector.h"
 
@@ -20,6 +21,7 @@ enum ReportType {
   ReportTypeRace,
   ReportTypeVptrRace,
   ReportTypeUseAfterFree,
+  ReportTypeVptrUseAfterFree,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
   ReportTypeMutexDoubleLock,
@@ -33,14 +35,12 @@ enum ReportType {
 
 struct ReportStack {
   ReportStack *next;
-  char *module;
-  uptr offset;
-  uptr pc;
-  char *func;
-  char *file;
-  int line;
-  int col;
+  AddressInfo info;
   bool suppressable;
+  static ReportStack *New(uptr addr);
+
+ private:
+  ReportStack();
 };
 
 struct ReportMopMutex {
@@ -70,17 +70,17 @@ enum ReportLocationType {
 
 struct ReportLocation {
   ReportLocationType type;
-  uptr addr;
-  uptr size;
-  char *module;
-  uptr offset;
+  DataInfo global;
+  uptr heap_chunk_start;
+  uptr heap_chunk_size;
   int tid;
   int fd;
-  char *name;
-  char *file;
-  int line;
   bool suppressable;
   ReportStack *stack;
+
+  static ReportLocation *New(ReportLocationType type);
+ private:
+  explicit ReportLocation(ReportLocationType type);
 };
 
 struct ReportThread {
index f5942bc..bf971b6 100644 (file)
@@ -259,8 +259,8 @@ void MapShadow(uptr addr, uptr size) {
 
 void MapThreadTrace(uptr addr, uptr size) {
   DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
-  CHECK_GE(addr, kTraceMemBegin);
-  CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
+  CHECK_GE(addr, kTraceMemBeg);
+  CHECK_LE(addr + size, kTraceMemEnd);
   CHECK_EQ(addr, addr & ~((64 << 10) - 1));  // windows wants 64K alignment
   uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
   if (addr1 != addr) {
@@ -270,6 +270,28 @@ void MapThreadTrace(uptr addr, uptr size) {
   }
 }
 
+static void CheckShadowMapping() {
+  for (uptr i = 0; i < ARRAY_SIZE(UserRegions); i += 2) {
+    const uptr beg = UserRegions[i];
+    const uptr end = UserRegions[i + 1];
+    VPrintf(3, "checking shadow region %p-%p\n", beg, end);
+    for (uptr p0 = beg; p0 <= end; p0 += (end - beg) / 4) {
+      for (int x = -1; x <= 1; x++) {
+        const uptr p = p0 + x;
+        if (p < beg || p >= end)
+          continue;
+        const uptr s = MemToShadow(p);
+        VPrintf(3, "  checking pointer %p -> %p\n", p, s);
+        CHECK(IsAppMem(p));
+        CHECK(IsShadowMem(s));
+        CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s));
+        const uptr m = (uptr)MemToMeta(p);
+        CHECK(IsMetaMem(m));
+      }
+    }
+  }
+}
+
 void Initialize(ThreadState *thr) {
   // Thread safe because done before all threads exist.
   static bool is_initialized = false;
@@ -289,6 +311,7 @@ void Initialize(ThreadState *thr) {
   InitializeAllocator();
 #endif
   InitializeInterceptors();
+  CheckShadowMapping();
   InitializePlatform();
   InitializeMutex();
   InitializeDynamicAnnotations();
@@ -437,8 +460,8 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {
     thr->shadow_stack_pos[0] = pc;
     thr->shadow_stack_pos++;
   }
-  u32 id = StackDepotPut(thr->shadow_stack,
-                         thr->shadow_stack_pos - thr->shadow_stack);
+  u32 id = StackDepotPut(
+      StackTrace(thr->shadow_stack, thr->shadow_stack_pos - thr->shadow_stack));
   if (pc != 0)
     thr->shadow_stack_pos--;
   return id;
@@ -451,7 +474,7 @@ void TraceSwitch(ThreadState *thr) {
   unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
   TraceHeader *hdr = &thr_trace->headers[trace];
   hdr->epoch0 = thr->fast_state.epoch();
-  hdr->stack0.ObtainCurrent(thr, 0);
+  ObtainCurrentStack(thr, 0, &hdr->stack0);
   hdr->mset0 = thr->mset;
   thr->nomalloc--;
 }
@@ -690,6 +713,8 @@ ALWAYS_INLINE
 bool ContainsSameAccess(u64 *s, u64 a, u64 sync_epoch, bool is_write) {
 #if defined(__SSE3__) && TSAN_SHADOW_COUNT == 4
   bool res = ContainsSameAccessFast(s, a, sync_epoch, is_write);
+  // NOTE: this check can fail if the shadow is concurrently mutated
+  // by other threads.
   DCHECK_EQ(res, ContainsSameAccessSlow(s, a, sync_epoch, is_write));
   return res;
 #else
index c7ea94d..3f78731 100644 (file)
 namespace __tsan {
 
 #ifndef TSAN_GO
-const uptr kAllocatorSpace = 0x7d0000000000ULL;
-const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
-
 struct MapUnmapCallback;
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0,
+typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0,
     DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator;
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
 typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator;
@@ -499,9 +496,9 @@ class ScopedReport {
   explicit ScopedReport(ReportType typ);
   ~ScopedReport();
 
-  void AddMemoryAccess(uptr addr, Shadow s, const StackTrace *stack,
+  void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
                        const MutexSet *mset);
-  void AddStack(const StackTrace *stack, bool suppressable = false);
+  void AddStack(StackTrace stack, bool suppressable = false);
   void AddThread(const ThreadContext *tctx, bool suppressable = false);
   void AddThread(int unique_tid, bool suppressable = false);
   void AddUniqueTid(int unique_tid);
@@ -525,7 +522,20 @@ class ScopedReport {
   void operator = (const ScopedReport&);
 };
 
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset);
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+                  MutexSet *mset);
+
+template<typename StackTraceTy>
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+  uptr size = thr->shadow_stack_pos - thr->shadow_stack;
+  uptr start = 0;
+  if (size + !!toppc > kStackTraceMax) {
+    start = size + !!toppc - kStackTraceMax;
+    size = kStackTraceMax - !!toppc;
+  }
+  stack->Init(&thr->shadow_stack[start], size, toppc);
+}
+
 
 void StatAggregate(u64 *dst, u64 *src);
 void StatOutput(u64 *stat);
@@ -552,9 +562,8 @@ void ForkChildAfter(ThreadState *thr, uptr pc);
 
 void ReportRace(ThreadState *thr);
 bool OutputReport(ThreadState *thr, const ScopedReport &srep);
-bool IsFiredSuppression(Context *ctx,
-                        const ScopedReport &srep,
-                        const StackTrace &trace);
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+                        StackTrace trace);
 bool IsExpectedReport(uptr addr, uptr size);
 void PrintMatchedBenignRaces();
 bool FrameIsInternal(const ReportStack *frame);
@@ -575,7 +584,7 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent);
 u32 CurrentStackId(ThreadState *thr, uptr pc);
 ReportStack *SymbolizeStackId(u32 stack_id);
 void PrintCurrentStack(ThreadState *thr, uptr pc);
-void PrintCurrentStackSlow();  // uses libunwind
+void PrintCurrentStackSlow(uptr pc);  // uses libunwind
 
 void Initialize(ThreadState *thr);
 int Finalize(ThreadState *thr);
index 71a2ecd..6df36a5 100644 (file)
@@ -170,10 +170,15 @@ setjmp:
   CFI_ADJUST_CFA_OFFSET(8)
   CFI_REL_OFFSET(%rdi, 0)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 8(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 16(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // restore env parameter
@@ -197,10 +202,15 @@ _setjmp:
   CFI_ADJUST_CFA_OFFSET(8)
   CFI_REL_OFFSET(%rdi, 0)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 8(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 16(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // restore env parameter
@@ -231,10 +241,15 @@ sigsetjmp:
   sub $8, %rsp
   CFI_ADJUST_CFA_OFFSET(8)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 24(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 32(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // unalign stack frame
@@ -272,10 +287,15 @@ __sigsetjmp:
   sub $8, %rsp
   CFI_ADJUST_CFA_OFFSET(8)
   // obtain %rsp
+#if defined(__FreeBSD__)
+  lea 24(%rsp), %rdi
+  mov %rdi, %rsi
+#else
   lea 32(%rsp), %rdi
   mov %rdi, %rsi
   xor %fs:0x30, %rsi  // magic mangling of rsp (see libc setjmp)
   rol $0x11, %rsi
+#endif
   // call tsan interceptor
   call __tsan_setjmp
   // unalign stack frame
@@ -296,7 +316,7 @@ __sigsetjmp:
   CFI_ENDPROC
 .size __sigsetjmp, .-__sigsetjmp
 
-#ifdef __linux__
+#if defined(__FreeBSD__) || defined(__linux__)
 /* We do not need executable stack.  */
 .section        .note.GNU-stack,"",@progbits
 #endif
index cc18313..d731b4b 100644 (file)
@@ -57,9 +57,9 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
   ThreadRegistryLock l(ctx->thread_registry);
   ScopedReport rep(typ);
   rep.AddMutex(mid);
-  StackTrace trace;
-  trace.ObtainCurrent(thr, pc);
-  rep.AddStack(&trace, true);
+  VarSizeStackTrace trace;
+  ObtainCurrentStack(thr, pc, &trace);
+  rep.AddStack(trace, true);
   rep.AddLocation(addr, 1);
   OutputReport(thr, rep);
 }
@@ -122,12 +122,12 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
     ThreadRegistryLock l(ctx->thread_registry);
     ScopedReport rep(ReportTypeMutexDestroyLocked);
     rep.AddMutex(mid);
-    StackTrace trace;
-    trace.ObtainCurrent(thr, pc);
-    rep.AddStack(&trace);
+    VarSizeStackTrace trace;
+    ObtainCurrentStack(thr, pc, &trace);
+    rep.AddStack(trace);
     FastState last(last_lock);
     RestoreStack(last.tid(), last.epoch(), &trace, 0);
-    rep.AddStack(&trace, true);
+    rep.AddStack(trace, true);
     rep.AddLocation(addr, 1);
     OutputReport(thr, rep);
   }
@@ -470,21 +470,17 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
     rep.AddUniqueTid((int)r->loop[i].thr_ctx);
     rep.AddThread((int)r->loop[i].thr_ctx);
   }
-  InternalScopedBuffer<StackTrace> stacks(2 * DDReport::kMaxLoopSize);
   uptr dummy_pc = 0x42;
   for (int i = 0; i < r->n; i++) {
-    uptr size;
     for (int j = 0; j < (flags()->second_deadlock_stack ? 2 : 1); j++) {
       u32 stk = r->loop[i].stk[j];
       if (stk) {
-        const uptr *trace = StackDepotGet(stk, &size);
-        stacks[i].Init(const_cast<uptr *>(trace), size);
+        rep.AddStack(StackDepotGet(stk), true);
       } else {
         // Sometimes we fail to extract the stack trace (FIXME: investigate),
         // but we should still produce some stack trace in the report.
-        stacks[i].Init(&dummy_pc, 1);
+        rep.AddStack(StackTrace(&dummy_pc, 1), true);
       }
-      rep.AddStack(&stacks[i], true);
     }
   }
   OutputReport(thr, rep);
index eafd1f4..11ec838 100644 (file)
@@ -28,7 +28,7 @@ namespace __tsan {
 
 using namespace __sanitizer;  // NOLINT
 
-static ReportStack *SymbolizeStack(const StackTrace& trace);
+static ReportStack *SymbolizeStack(StackTrace trace);
 
 void TsanCheckFailed(const char *file, int line, const char *cond,
                      u64 v1, u64 v2) {
@@ -39,7 +39,7 @@ void TsanCheckFailed(const char *file, int line, const char *cond,
   Printf("FATAL: ThreadSanitizer CHECK failed: "
          "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
          file, line, cond, (uptr)v1, (uptr)v2);
-  PrintCurrentStackSlow();
+  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
   Die();
 }
 
@@ -57,27 +57,16 @@ bool WEAK OnReport(const ReportDesc *rep, bool suppressed) {
 static void StackStripMain(ReportStack *stack) {
   ReportStack *last_frame = 0;
   ReportStack *last_frame2 = 0;
-  const char *prefix = "__interceptor_";
-  uptr prefix_len = internal_strlen(prefix);
-  const char *path_prefix = common_flags()->strip_path_prefix;
-  uptr path_prefix_len = internal_strlen(path_prefix);
-  char *pos;
   for (ReportStack *ent = stack; ent; ent = ent->next) {
-    if (ent->func && 0 == internal_strncmp(ent->func, prefix, prefix_len))
-      ent->func += prefix_len;
-    if (ent->file && (pos = internal_strstr(ent->file, path_prefix)))
-      ent->file = pos + path_prefix_len;
-    if (ent->file && ent->file[0] == '.' && ent->file[1] == '/')
-      ent->file += 2;
     last_frame2 = last_frame;
     last_frame = ent;
   }
 
   if (last_frame2 == 0)
     return;
-  const char *last = last_frame->func;
+  const char *last = last_frame->info.function;
 #ifndef TSAN_GO
-  const char *last2 = last_frame2->func;
+  const char *last2 = last_frame2->info.function;
   // Strip frame above 'main'
   if (last2 && 0 == internal_strcmp(last2, "main")) {
     last_frame2->next = 0;
@@ -105,39 +94,36 @@ static void StackStripMain(ReportStack *stack) {
 ReportStack *SymbolizeStackId(u32 stack_id) {
   if (stack_id == 0)
     return 0;
-  uptr ssz = 0;
-  const uptr *stack = StackDepotGet(stack_id, &ssz);
-  if (stack == 0)
-    return 0;
-  StackTrace trace;
-  trace.Init(stack, ssz);
-  return SymbolizeStack(trace);
+  StackTrace stack = StackDepotGet(stack_id);
+  if (stack.trace == nullptr)
+    return nullptr;
+  return SymbolizeStack(stack);
 }
 
-static ReportStack *SymbolizeStack(const StackTrace& trace) {
-  if (trace.IsEmpty())
+static ReportStack *SymbolizeStack(StackTrace trace) {
+  if (trace.size == 0)
     return 0;
   ReportStack *stack = 0;
-  for (uptr si = 0; si < trace.Size(); si++) {
-    const uptr pc = trace.Get(si);
+  for (uptr si = 0; si < trace.size; si++) {
+    const uptr pc = trace.trace[si];
 #ifndef TSAN_GO
     // We obtain the return address, that is, address of the next instruction,
     // so offset it by 1 byte.
-    const uptr pc1 = __sanitizer::StackTrace::GetPreviousInstructionPc(pc);
+    const uptr pc1 = StackTrace::GetPreviousInstructionPc(pc);
 #else
     // FIXME(dvyukov): Go sometimes uses address of a function as top pc.
     uptr pc1 = pc;
-    if (si != trace.Size() - 1)
+    if (si != trace.size - 1)
       pc1 -= 1;
 #endif
     ReportStack *ent = SymbolizeCode(pc1);
     CHECK_NE(ent, 0);
     ReportStack *last = ent;
     while (last->next) {
-      last->pc = pc;  // restore original pc for report
+      last->info.address = pc;  // restore original pc for report
       last = last->next;
     }
-    last->pc = pc;  // restore original pc for report
+    last->info.address = pc;  // restore original pc for report
     last->next = stack;
     stack = ent;
   }
@@ -160,14 +146,14 @@ ScopedReport::~ScopedReport() {
   DestroyAndFree(rep_);
 }
 
-void ScopedReport::AddStack(const StackTrace *stack, bool suppressable) {
+void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
   ReportStack **rs = rep_->stacks.PushBack();
-  *rs = SymbolizeStack(*stack);
+  *rs = SymbolizeStack(stack);
   (*rs)->suppressable = suppressable;
 }
 
-void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
-    const StackTrace *stack, const MutexSet *mset) {
+void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+                                   const MutexSet *mset) {
   void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
   ReportMop *mop = new(mem) ReportMop;
   rep_->mops.PushBack(mop);
@@ -176,7 +162,7 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
   mop->size = s.size();
   mop->write = s.IsWrite();
   mop->atomic = s.IsAtomic();
-  mop->stack = SymbolizeStack(*stack);
+  mop->stack = SymbolizeStack(stack);
   if (mop->stack)
     mop->stack->suppressable = true;
   for (uptr i = 0; i < mset->Size(); i++) {
@@ -315,13 +301,11 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
   int creat_tid = -1;
   u32 creat_stack = 0;
   if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = ReportLocationFD;
+    ReportLocation *loc = ReportLocation::New(ReportLocationFD);
     loc->fd = fd;
     loc->tid = creat_tid;
     loc->stack = SymbolizeStackId(creat_stack);
+    rep_->locs.PushBack(loc);
     ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
     if (tctx)
       AddThread(tctx);
@@ -336,33 +320,25 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
   }
   if (b != 0) {
     ThreadContext *tctx = FindThreadByTidLocked(b->tid);
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = ReportLocationHeap;
-    loc->addr = (uptr)allocator()->GetBlockBegin((void*)addr);
-    loc->size = b->siz;
+    ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
+    loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
+    loc->heap_chunk_size = b->siz;
     loc->tid = tctx ? tctx->tid : b->tid;
-    loc->name = 0;
-    loc->file = 0;
-    loc->line = 0;
-    loc->stack = 0;
     loc->stack = SymbolizeStackId(b->stk);
+    rep_->locs.PushBack(loc);
     if (tctx)
       AddThread(tctx);
     return;
   }
   bool is_stack = false;
   if (ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack)) {
-    void *mem = internal_alloc(MBlockReportLoc, sizeof(ReportLocation));
-    ReportLocation *loc = new(mem) ReportLocation();
-    rep_->locs.PushBack(loc);
-    loc->type = is_stack ? ReportLocationStack : ReportLocationTLS;
+    ReportLocation *loc =
+        ReportLocation::New(is_stack ? ReportLocationStack : ReportLocationTLS);
     loc->tid = tctx->tid;
+    rep_->locs.PushBack(loc);
     AddThread(tctx);
   }
-  ReportLocation *loc = SymbolizeData(addr);
-  if (loc) {
+  if (ReportLocation *loc = SymbolizeData(addr)) {
     loc->suppressable = true;
     rep_->locs.PushBack(loc);
     return;
@@ -384,7 +360,8 @@ const ReportDesc *ScopedReport::GetReport() const {
   return rep_;
 }
 
-void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
+void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
+                  MutexSet *mset) {
   // This function restores stack trace and mutex set for the thread/epoch.
   // It does so by getting stack trace and mutex set at the beginning of
   // trace part, and then replaying the trace till the given epoch.
@@ -409,13 +386,13 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
   DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
           tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
   InternalScopedBuffer<uptr> stack(kShadowStackSize);
-  for (uptr i = 0; i < hdr->stack0.Size(); i++) {
-    stack[i] = hdr->stack0.Get(i);
+  for (uptr i = 0; i < hdr->stack0.size; i++) {
+    stack[i] = hdr->stack0.trace[i];
     DPrintf2("  #%02lu: pc=%zx\n", i, stack[i]);
   }
   if (mset)
     *mset = hdr->mset0;
-  uptr pos = hdr->stack0.Size();
+  uptr pos = hdr->stack0.size;
   Event *events = (Event*)GetThreadTrace(tid);
   for (uptr i = ebegin; i <= eend; i++) {
     Event ev = events[i];
@@ -450,13 +427,13 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
   stk->Init(stack.data(), pos);
 }
 
-static bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
-    uptr addr_min, uptr addr_max) {
+static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+                             uptr addr_min, uptr addr_max) {
   bool equal_stack = false;
   RacyStacks hash;
   if (flags()->suppress_equal_stacks) {
-    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
-    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
     for (uptr i = 0; i < ctx->racy_stacks.Size(); i++) {
       if (hash == ctx->racy_stacks[i]) {
         DPrintf("ThreadSanitizer: suppressing report as doubled (stack)\n");
@@ -489,12 +466,12 @@ static bool HandleRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
   return false;
 }
 
-static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
-    uptr addr_min, uptr addr_max) {
+static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
+                          uptr addr_min, uptr addr_max) {
   if (flags()->suppress_equal_stacks) {
     RacyStacks hash;
-    hash.hash[0] = md5_hash(traces[0].Begin(), traces[0].Size() * sizeof(uptr));
-    hash.hash[1] = md5_hash(traces[1].Begin(), traces[1].Size() * sizeof(uptr));
+    hash.hash[0] = md5_hash(traces[0].trace, traces[0].size * sizeof(uptr));
+    hash.hash[1] = md5_hash(traces[1].trace, traces[1].size * sizeof(uptr));
     ctx->racy_stacks.PushBack(hash);
   }
   if (flags()->suppress_equal_addresses) {
@@ -535,15 +512,14 @@ bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
   return true;
 }
 
-bool IsFiredSuppression(Context *ctx,
-                        const ScopedReport &srep,
-                        const StackTrace &trace) {
+bool IsFiredSuppression(Context *ctx, const ScopedReport &srep,
+                        StackTrace trace) {
   for (uptr k = 0; k < ctx->fired_suppressions.size(); k++) {
     if (ctx->fired_suppressions[k].type != srep.GetReport()->typ)
       continue;
-    for (uptr j = 0; j < trace.Size(); j++) {
+    for (uptr j = 0; j < trace.size; j++) {
       FiredSuppression *s = &ctx->fired_suppressions[k];
-      if (trace.Get(j) == s->pc) {
+      if (trace.trace[j] == s->pc) {
         if (s->supp)
           s->supp->hit_count++;
         return true;
@@ -570,10 +546,13 @@ static bool IsFiredSuppression(Context *ctx,
 }
 
 bool FrameIsInternal(const ReportStack *frame) {
-  return frame != 0 && frame->file != 0
-      && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
-          internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
-          internal_strstr(frame->file, "tsan_interface_"));
+  if (frame == 0)
+    return false;
+  const char *file = frame->info.file;
+  return file != 0 &&
+         (internal_strstr(file, "tsan_interceptors.cc") ||
+          internal_strstr(file, "sanitizer_common_interceptors.inc") ||
+          internal_strstr(file, "tsan_interface_"));
 }
 
 static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
@@ -625,7 +604,9 @@ void ReportRace(ThreadState *thr) {
   ThreadRegistryLock l0(ctx->thread_registry);
 
   ReportType typ = ReportTypeRace;
-  if (thr->is_vptr_access)
+  if (thr->is_vptr_access && freed)
+    typ = ReportTypeVptrUseAfterFree;
+  else if (thr->is_vptr_access)
     typ = ReportTypeVptrRace;
   else if (freed)
     typ = ReportTypeUseAfterFree;
@@ -633,9 +614,9 @@ void ReportRace(ThreadState *thr) {
   if (IsFiredSuppression(ctx, rep, addr))
     return;
   const uptr kMop = 2;
-  StackTrace traces[kMop];
+  VarSizeStackTrace traces[kMop];
   const uptr toppc = TraceTopPC(thr);
-  traces[0].ObtainCurrent(thr, toppc);
+  ObtainCurrentStack(thr, toppc, &traces[0]);
   if (IsFiredSuppression(ctx, rep, traces[0]))
     return;
   InternalScopedBuffer<MutexSet> mset2(1);
@@ -650,7 +631,7 @@ void ReportRace(ThreadState *thr) {
 
   for (uptr i = 0; i < kMop; i++) {
     Shadow s(thr->racy_state[i]);
-    rep.AddMemoryAccess(addr, s, &traces[i],
+    rep.AddMemoryAccess(addr, s, traces[i],
                         i == 0 ? &thr->mset : mset2.data());
   }
 
@@ -680,26 +661,33 @@ void ReportRace(ThreadState *thr) {
 }
 
 void PrintCurrentStack(ThreadState *thr, uptr pc) {
-  StackTrace trace;
-  trace.ObtainCurrent(thr, pc);
+  VarSizeStackTrace trace;
+  ObtainCurrentStack(thr, pc, &trace);
   PrintStack(SymbolizeStack(trace));
 }
 
-void PrintCurrentStackSlow() {
+void PrintCurrentStackSlow(uptr pc) {
 #ifndef TSAN_GO
-  __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
-      sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
-  ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(), 0, 0,
-                 0, 0, false);
+  BufferedStackTrace *ptrace =
+      new(internal_alloc(MBlockStackTrace, sizeof(BufferedStackTrace)))
+          BufferedStackTrace();
+  ptrace->Unwind(kStackTraceMax, pc, 0, 0, 0, 0, false);
   for (uptr i = 0; i < ptrace->size / 2; i++) {
-    uptr tmp = ptrace->trace[i];
-    ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
-    ptrace->trace[ptrace->size - i - 1] = tmp;
+    uptr tmp = ptrace->trace_buffer[i];
+    ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
+    ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
   }
-  StackTrace trace;
-  trace.Init(ptrace->trace, ptrace->size);
-  PrintStack(SymbolizeStack(trace));
+  PrintStack(SymbolizeStack(*ptrace));
 #endif
 }
 
 }  // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
+}
+}  // extern "C"
index 45bd251..3734e0e 100644 (file)
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
 //===----------------------------------------------------------------------===//
-//#include "sanitizer_common/sanitizer_placement_new.h"
 #include "tsan_stack_trace.h"
 #include "tsan_rtl.h"
 #include "tsan_mman.h"
 
 namespace __tsan {
 
-StackTrace::StackTrace()
-    : n_()
-    , s_()
-    , c_() {
-}
-
-StackTrace::StackTrace(uptr *buf, uptr cnt)
-    : n_()
-    , s_(buf)
-    , c_(cnt) {
-  CHECK_NE(buf, 0);
-  CHECK_NE(cnt, 0);
-}
-
-StackTrace::~StackTrace() {
-  Reset();
-}
+VarSizeStackTrace::VarSizeStackTrace()
+    : StackTrace(nullptr, 0), trace_buffer(nullptr) {}
 
-void StackTrace::Reset() {
-  if (s_ && !c_) {
-    CHECK_NE(n_, 0);
-    internal_free(s_);
-    s_ = 0;
-  }
-  n_ = 0;
+VarSizeStackTrace::~VarSizeStackTrace() {
+  ResizeBuffer(0);
 }
 
-void StackTrace::Init(const uptr *pcs, uptr cnt) {
-  Reset();
-  if (cnt == 0)
-    return;
-  if (c_) {
-    CHECK_NE(s_, 0);
-    CHECK_LE(cnt, c_);
-  } else {
-    s_ = (uptr*)internal_alloc(MBlockStackTrace, cnt * sizeof(s_[0]));
-  }
-  n_ = cnt;
-  internal_memcpy(s_, pcs, cnt * sizeof(s_[0]));
-}
-
-void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
-  Reset();
-  n_ = thr->shadow_stack_pos - thr->shadow_stack;
-  if (n_ + !!toppc == 0)
-    return;
-  uptr start = 0;
-  if (c_) {
-    CHECK_NE(s_, 0);
-    if (n_ + !!toppc > c_) {
-      start = n_ - c_ + !!toppc;
-      n_ = c_ - !!toppc;
-    }
-  } else {
-    // Cap potentially huge stacks.
-    if (n_ + !!toppc > kTraceStackSize) {
-      start = n_ - kTraceStackSize + !!toppc;
-      n_ = kTraceStackSize - !!toppc;
-    }
-    s_ = (uptr*)internal_alloc(MBlockStackTrace,
-                               (n_ + !!toppc) * sizeof(s_[0]));
-  }
-  for (uptr i = 0; i < n_; i++)
-    s_[i] = thr->shadow_stack[start + i];
-  if (toppc) {
-    s_[n_] = toppc;
-    n_++;
+void VarSizeStackTrace::ResizeBuffer(uptr new_size) {
+  if (trace_buffer) {
+    internal_free(trace_buffer);
   }
-}
-
-void StackTrace::CopyFrom(const StackTrace& other) {
-  Reset();
-  Init(other.Begin(), other.Size());
-}
-
-bool StackTrace::IsEmpty() const {
-  return n_ == 0;
-}
-
-uptr StackTrace::Size() const {
-  return n_;
-}
-
-uptr StackTrace::Get(uptr i) const {
-  CHECK_LT(i, n_);
-  return s_[i];
-}
-
-const uptr *StackTrace::Begin() const {
-  return s_;
+  trace_buffer =
+      (new_size > 0)
+          ? (uptr *)internal_alloc(MBlockStackTrace,
+                                   new_size * sizeof(trace_buffer[0]))
+          : nullptr;
+  trace = trace_buffer;
+  size = new_size;
+}
+
+void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) {
+  ResizeBuffer(cnt + !!extra_top_pc);
+  internal_memcpy(trace_buffer, pcs, cnt * sizeof(trace_buffer[0]));
+  if (extra_top_pc)
+    trace_buffer[cnt] = extra_top_pc;
 }
 
 }  // namespace __tsan
index ce0cb88..b097a9b 100644 (file)
 #ifndef TSAN_STACK_TRACE_H
 #define TSAN_STACK_TRACE_H
 
-//#include "sanitizer_common/sanitizer_atomic.h"
-//#include "sanitizer_common/sanitizer_common.h"
-//#include "sanitizer_common/sanitizer_deadlock_detector_interface.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
 #include "tsan_defs.h"
-//#include "tsan_clock.h"
-//#include "tsan_mutex.h"
-//#include "tsan_dense_alloc.h"
 
 namespace __tsan {
 
-class StackTrace {
- public:
-  StackTrace();
-  // Initialized the object in "static mode",
-  // in this mode it never calls malloc/free but uses the provided buffer.
-  StackTrace(uptr *buf, uptr cnt);
-  ~StackTrace();
-  void Reset();
-
-  void Init(const uptr *pcs, uptr cnt);
-  void ObtainCurrent(ThreadState *thr, uptr toppc);
-  bool IsEmpty() const;
-  uptr Size() const;
-  uptr Get(uptr i) const;
-  const uptr *Begin() const;
-  void CopyFrom(const StackTrace& other);
+// StackTrace which calls malloc/free to allocate the buffer for
+// addresses in stack traces.
+struct VarSizeStackTrace : public StackTrace {
+  uptr *trace_buffer;  // Owned.
+
+  VarSizeStackTrace();
+  ~VarSizeStackTrace();
+  void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0);
 
  private:
-  uptr n_;
-  uptr *s_;
-  const uptr c_;
+  void ResizeBuffer(uptr new_size);
 
-  StackTrace(const StackTrace&);
-  void operator = (const StackTrace&);
+  VarSizeStackTrace(const VarSizeStackTrace &);
+  void operator=(const VarSizeStackTrace &);
 };
 
 }  // namespace __tsan
index 6b42d3a..76460d9 100644 (file)
@@ -58,6 +58,8 @@ SuppressionType conv(ReportType typ) {
     return SuppressionRace;
   else if (typ == ReportTypeUseAfterFree)
     return SuppressionRace;
+  else if (typ == ReportTypeVptrUseAfterFree)
+    return SuppressionRace;
   else if (typ == ReportTypeThreadLeak)
     return SuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
@@ -89,13 +91,14 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) {
     return 0;
   Suppression *s;
   for (const ReportStack *frame = stack; frame; frame = frame->next) {
-    if (SuppressionContext::Get()->Match(frame->func, stype, &s) ||
-        SuppressionContext::Get()->Match(frame->file, stype, &s) ||
-        SuppressionContext::Get()->Match(frame->module, stype, &s)) {
+    const AddressInfo &info = frame->info;
+    if (SuppressionContext::Get()->Match(info.function, stype, &s) ||
+        SuppressionContext::Get()->Match(info.file, stype, &s) ||
+        SuppressionContext::Get()->Match(info.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
-      return frame->pc;
+      return info.address;
     }
   }
   return 0;
@@ -109,13 +112,13 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) {
   if (stype == SuppressionNone)
     return 0;
   Suppression *s;
-  if (SuppressionContext::Get()->Match(loc->name, stype, &s) ||
-      SuppressionContext::Get()->Match(loc->file, stype, &s) ||
-      SuppressionContext::Get()->Match(loc->module, stype, &s)) {
+  const DataInfo &global = loc->global;
+  if (SuppressionContext::Get()->Match(global.name, stype, &s) ||
+      SuppressionContext::Get()->Match(global.module, stype, &s)) {
       DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ);
       s->hit_count++;
       *sp = s;
-      return loc->addr;
+      return global.start;
   }
   return 0;
 }
index 49ae3df..795f838 100644 (file)
@@ -34,38 +34,6 @@ void ExitSymbolizer() {
   thr->ignore_interceptors--;
 }
 
-ReportStack *NewReportStackEntry(uptr addr) {
-  ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
-                                                  sizeof(ReportStack));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->pc = addr;
-  return ent;
-}
-
-static ReportStack *NewReportStackEntry(const AddressInfo &info) {
-  ReportStack *ent = NewReportStackEntry(info.address);
-  ent->module = StripModuleName(info.module);
-  ent->offset = info.module_offset;
-  if (info.function)
-    ent->func = internal_strdup(info.function);
-  if (info.file)
-    ent->file = internal_strdup(info.file);
-  ent->line = info.line;
-  ent->col = info.column;
-  return ent;
-}
-
-
-  ReportStack *next;
-  char *module;
-  uptr offset;
-  uptr pc;
-  char *func;
-  char *file;
-  int line;
-  int col;
-
-
 // Denotes fake PC values that come from JIT/JAVA/etc.
 // For such PC values __tsan_symbolize_external() will be called.
 const uptr kExternalPCBit = 1ULL << 60;
@@ -93,16 +61,14 @@ ReportStack *SymbolizeCode(uptr addr) {
     static char func_buf[1024];
     static char file_buf[1024];
     int line, col;
+    ReportStack *ent = ReportStack::New(addr);
     if (!__tsan_symbolize_external(addr, func_buf, sizeof(func_buf),
                                   file_buf, sizeof(file_buf), &line, &col))
-      return NewReportStackEntry(addr);
-    ReportStack *ent = NewReportStackEntry(addr);
-    ent->module = 0;
-    ent->offset = 0;
-    ent->func = internal_strdup(func_buf);
-    ent->file = internal_strdup(file_buf);
-    ent->line = line;
-    ent->col = col;
+      return ent;
+    ent->info.function = internal_strdup(func_buf);
+    ent->info.file = internal_strdup(file_buf);
+    ent->info.line = line;
+    ent->info.column = col;
     return ent;
   }
   static const uptr kMaxAddrFrames = 16;
@@ -112,13 +78,12 @@ ReportStack *SymbolizeCode(uptr addr) {
   uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC(
       addr, addr_frames.data(), kMaxAddrFrames);
   if (addr_frames_num == 0)
-    return NewReportStackEntry(addr);
+    return ReportStack::New(addr);
   ReportStack *top = 0;
   ReportStack *bottom = 0;
   for (uptr i = 0; i < addr_frames_num; i++) {
-    ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
-    CHECK(cur_entry);
-    addr_frames[i].Clear();
+    ReportStack *cur_entry = ReportStack::New(addr);
+    cur_entry->info = addr_frames[i];
     if (i == 0)
       top = cur_entry;
     else
@@ -132,16 +97,8 @@ ReportLocation *SymbolizeData(uptr addr) {
   DataInfo info;
   if (!Symbolizer::GetOrInit()->SymbolizeData(addr, &info))
     return 0;
-  ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
-                                                        sizeof(ReportLocation));
-  internal_memset(ent, 0, sizeof(*ent));
-  ent->type = ReportLocationGlobal;
-  ent->module = StripModuleName(info.module);
-  ent->offset = info.module_offset;
-  if (info.name)
-    ent->name = internal_strdup(info.name);
-  ent->addr = info.start;
-  ent->size = info.size;
+  ReportLocation *ent = ReportLocation::New(ReportLocationGlobal);
+  ent->global = info;
   return ent;
 }
 
index af14068..8eceb63 100644 (file)
@@ -40,21 +40,15 @@ enum EventType {
 typedef u64 Event;
 
 struct TraceHeader {
-  StackTrace stack0;  // Start stack for the trace.
-  u64        epoch0;  // Start epoch for the trace.
-  MutexSet   mset0;
-#ifndef TSAN_GO
-  uptr       stack0buf[kTraceStackSize];
-#endif
-
-  TraceHeader()
 #ifndef TSAN_GO
-      : stack0(stack0buf, kTraceStackSize)
+  BufferedStackTrace stack0;  // Start stack for the trace.
 #else
-      : stack0()
+  VarSizeStackTrace stack0;
 #endif
-      , epoch0() {
-  }
+  u64        epoch0;  // Start epoch for the trace.
+  MutexSet   mset0;
+
+  TraceHeader() : stack0(), epoch0() {}
 };
 
 struct Trace {
index e1aa708..ae16767 100644 (file)
@@ -6,6 +6,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 
 toolexeclib_LTLIBRARIES = libubsan.la
index 02902f2..543e4f1 100644 (file)
@@ -256,7 +256,7 @@ gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
        -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
        -fomit-frame-pointer -funwind-tables -fvisibility=hidden \
-       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+       -Wno-variadic-macros $(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=c++11
 ACLOCAL_AMFLAGS = -I m4
 toolexeclib_LTLIBRARIES = libubsan.la
 ubsan_files = \
index 828127a..028ac1a 100644 (file)
@@ -14,6 +14,7 @@
 #include "ubsan_flags.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stacktrace_printer.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
 #include <stdio.h>
 
@@ -31,7 +32,7 @@ static void MaybePrintStackTrace(uptr pc, uptr bp) {
   // under ASan).
   if (StackTrace::WillUseFastUnwind(false))
     return;
-  StackTrace stack;
+  BufferedStackTrace stack;
   stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
   stack.Print();
 }
@@ -44,12 +45,12 @@ static void MaybeReportErrorSummary(Location Loc) {
   if (Loc.isSourceLocation()) {
     SourceLocation SLoc = Loc.getSourceLocation();
     if (!SLoc.isInvalid()) {
-      ReportErrorSummary("runtime-error", SLoc.getFilename(), SLoc.getLine(),
-                         "");
+      ReportErrorSummary("undefined-behavior", SLoc.getFilename(),
+                         SLoc.getLine(), "");
       return;
     }
   }
-  ReportErrorSummary("runtime-error");
+  ReportErrorSummary("undefined-behavior");
 }
 
 namespace {
@@ -127,14 +128,16 @@ static void renderLocation(Location Loc) {
     if (SLoc.isInvalid())
       LocBuffer.append("<unknown>");
     else
-      PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
-                          SLoc.getColumn());
+      RenderSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+                           SLoc.getColumn(), common_flags()->strip_path_prefix);
     break;
   }
-  case Location::LK_Module:
-    PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
-                         Loc.getModuleLocation().getOffset());
+  case Location::LK_Module: {
+    ModuleLocation MLoc = Loc.getModuleLocation();
+    RenderModuleLocation(&LocBuffer, MLoc.getModuleName(), MLoc.getOffset(),
+                         common_flags()->strip_path_prefix);
     break;
+  }
   case Location::LK_Memory:
     LocBuffer.append("%p", Loc.getMemoryLocation());
     break;
index bb9322f..770d3c2 100644 (file)
@@ -28,10 +28,10 @@ static bool ignoreReport(SourceLocation SLoc, ReportOptions Opts) {
 }
 
 namespace __ubsan {
-  const char *TypeCheckKinds[] = {
+const char *TypeCheckKinds[] = {
     "load of", "store to", "reference binding to", "member access within",
-    "member call on", "constructor call on", "downcast of", "downcast of"
-  };
+    "member call on", "constructor call on", "downcast of", "downcast of",
+    "upcast of", "cast to virtual base of"};
 }
 
 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
index d010094..8758f6c 100644 (file)
@@ -113,7 +113,8 @@ __ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize];
 
 /// \brief Determine whether \p Derived has a \p Base base class subobject at
 /// offset \p Offset.
-static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
+static bool isDerivedFromAtOffset(sptr Object,
+                                  const abi::__class_type_info *Derived,
                                   const abi::__class_type_info *Base,
                                   sptr Offset) {
   if (Derived->__type_name == Base->__type_name)
@@ -121,7 +122,7 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return isDerivedFromAtOffset(SI->__base_type, Base, Offset);
+    return isDerivedFromAtOffset(Object, SI->__base_type, Base, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -136,13 +137,13 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // For now, just punt on virtual bases and say 'yes'.
-      // FIXME: OffsetHere is the offset in the vtable of the virtual base
-      //        offset. Read the vbase offset out of the vtable and use it.
-      return true;
-    if (isDerivedFromAtOffset(VTI->base_info[base].__base_type,
-                              Base, Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (isDerivedFromAtOffset(Object + OffsetHere,
+                              VTI->base_info[base].__base_type, Base,
+                              Offset - OffsetHere))
       return true;
   }
 
@@ -151,14 +152,15 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
 
 /// \brief Find the derived-most dynamic base class of \p Derived at offset
 /// \p Offset.
-static const abi::__class_type_info *findBaseAtOffset(
-    const abi::__class_type_info *Derived, sptr Offset) {
+static const abi::__class_type_info *
+findBaseAtOffset(sptr Object, const abi::__class_type_info *Derived,
+                 sptr Offset) {
   if (!Offset)
     return Derived;
 
   if (const abi::__si_class_type_info *SI =
         dynamic_cast<const abi::__si_class_type_info*>(Derived))
-    return findBaseAtOffset(SI->__base_type, Offset);
+    return findBaseAtOffset(Object, SI->__base_type, Offset);
 
   const abi::__vmi_class_type_info *VTI =
     dynamic_cast<const abi::__vmi_class_type_info*>(Derived);
@@ -170,12 +172,13 @@ static const abi::__class_type_info *findBaseAtOffset(
     sptr OffsetHere = VTI->base_info[base].__offset_flags >>
                       abi::__base_class_type_info::__offset_shift;
     if (VTI->base_info[base].__offset_flags &
-          abi::__base_class_type_info::__virtual_mask)
-      // FIXME: Can't handle virtual bases yet.
-      continue;
-    if (const abi::__class_type_info *Base =
-          findBaseAtOffset(VTI->base_info[base].__base_type,
-                           Offset - OffsetHere))
+          abi::__base_class_type_info::__virtual_mask) {
+      sptr VTable = *reinterpret_cast<const sptr *>(Object);
+      OffsetHere = *reinterpret_cast<const sptr *>(VTable + OffsetHere);
+    }
+    if (const abi::__class_type_info *Base = findBaseAtOffset(
+            Object + OffsetHere, VTI->base_info[base].__base_type,
+            Offset - OffsetHere))
       return Base;
   }
 
@@ -227,7 +230,8 @@ bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) {
     return false;
 
   abi::__class_type_info *Base = (abi::__class_type_info*)Type;
-  if (!isDerivedFromAtOffset(Derived, Base, -Vtable->Offset))
+  if (!isDerivedFromAtOffset(reinterpret_cast<sptr>(Object), Derived, Base,
+                             -Vtable->Offset))
     return false;
 
   // Success. Cache this result.
@@ -241,8 +245,9 @@ __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfo(void *Object) {
   if (!Vtable)
     return DynamicTypeInfo(0, 0, 0);
   const abi::__class_type_info *ObjectType = findBaseAtOffset(
-    static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
-    -Vtable->Offset);
+      reinterpret_cast<sptr>(Object),
+      static_cast<const abi::__class_type_info *>(Vtable->TypeInfo),
+      -Vtable->Offset);
   return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
                          ObjectType ? ObjectType->__type_name : "<unknown>");
 }