<div dir="ltr"><div>Reverted in r342922. Still trying to reproduce the errors.<br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Sep 24, 2018 at 2:38 PM, Evgeniy Stepanov via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: eugenis<br>
Date: Mon Sep 24 14:38:42 2018<br>
New Revision: 342921<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=342921&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=342921&view=rev</a><br>
Log:<br>
[hwasan] Record and display stack history in stack-based reports.<br>
<br>
Summary:<br>
Display a list of recent stack frames (not a stack trace!) when<br>
tag-mismatch is detected on a stack address.<br>
<br>
The implementation uses alignment tricks to get both the address of<br>
the history buffer, and the base address of the shadow with a single<br>
8-byte load. See the comment in hwasan_thread_list.h for more<br>
details.<br>
<br>
Developed in collaboration with Kostya Serebryany.<br>
<br>
Reviewers: kcc<br>
<br>
Subscribers: srhines, kubamracek, mgorny, hiraditya, jfb, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D52249" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D52249</a><br>
<br>
Added:<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.h<br>
    compiler-rt/trunk/test/hwasan/<wbr>TestCases/deep-recursion.c<br>
    compiler-rt/trunk/test/hwasan/<wbr>TestCases/rich-stack.c<br>
    compiler-rt/trunk/test/hwasan/<wbr>TestCases/stack-history-<wbr>length.c<br>
Modified:<br>
    compiler-rt/trunk/lib/hwasan/<wbr>CMakeLists.txt<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan.h<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_dynamic_shadow.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_flags.inc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_linux.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_report.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.cc<br>
    compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.h<br>
    compiler-rt/trunk/lib/<wbr>sanitizer_common/sanitizer_<wbr>ring_buffer.h<br>
    compiler-rt/trunk/lib/<wbr>sanitizer_common/tests/<wbr>sanitizer_ring_buffer_test.cc<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/CMakeLists.txt?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/CMakeLists.txt?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>CMakeLists.txt (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>CMakeLists.txt Mon Sep 24 14:38:42 2018<br>
@@ -10,6 +10,7 @@ set(HWASAN_RTL_SOURCES<br>
   hwasan_poisoning.cc<br>
   hwasan_report.cc<br>
   hwasan_thread.cc<br>
+  hwasan_thread_list.cc<br>
   )<br>
<br>
 set(HWASAN_RTL_CXX_SOURCES<br>
@@ -25,8 +26,9 @@ set(HWASAN_RTL_HEADERS<br>
   hwasan_mapping.h<br>
   hwasan_poisoning.h<br>
   hwasan_report.h<br>
-  hwasan_thread.h)<br>
-<br>
+  hwasan_thread.h<br>
+  hwasan_thread_list.h<br>
+  )<br>
<br>
 set(HWASAN_DEFINITIONS)<br>
 append_list_if(COMPILER_RT_<wbr>HWASAN_WITH_INTERCEPTORS HWASAN_WITH_INTERCEPTORS=1 HWASAN_DEFINITIONS)<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan.cc?rev=342921&<wbr>r1=342920&r2=342921&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan.cc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan.cc Mon Sep 24 14:38:42 2018<br>
@@ -17,6 +17,7 @@<br>
 #include "hwasan_poisoning.h"<br>
 #include "hwasan_report.h"<br>
 #include "hwasan_thread.h"<br>
+#include "hwasan_thread_list.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>atomic.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>common.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>flags.h"<br>
@@ -174,7 +175,8 @@ static void HWAsanCheckFailed(const char<br>
 static constexpr uptr kMemoryUsageBufferSize = 4096;<br>
<br>
 static void HwasanFormatMemoryUsage(<wbr>InternalScopedString &s) {<br>
-  auto thread_stats = Thread::GetThreadStats();<br>
+  HwasanThreadList &thread_list = hwasanThreadList();<br>
+  auto thread_stats = thread_list.GetThreadStats();<br>
   auto *sds = StackDepotGetStats();<br>
   AllocatorStatCounters asc;<br>
   GetAllocatorStats(asc);<br>
@@ -184,7 +186,7 @@ static void HwasanFormatMemoryUsage(Inte<br>
       " heap: %zd",<br>
       internal_getpid(), GetRSS(), thread_stats.n_live_threads,<br>
       thread_stats.total_stack_size,<br>
-      thread_stats.n_live_threads * Thread::MemoryUsedPerThread(),<br>
+      thread_stats.n_live_threads * thread_list.<wbr>MemoryUsedPerThread(),<br>
       sds->allocated, sds->n_uniq_ids, asc[AllocatorStatMapped]);<br>
 }<br>
<br>
@@ -253,7 +255,12 @@ void __hwasan_init() {<br>
   __sanitizer_set_report_path(<wbr>common_flags()->log_path);<br>
<br>
   DisableCoreDumperIfNecessary()<wbr>;<br>
+<br>
   __hwasan_shadow_init();<br>
+<br>
+  InitThreads();<br>
+  hwasanThreadList().<wbr>CreateCurrentThread();<br>
+<br>
   MadviseShadow();<br>
<br>
   // This may call libc -> needs initialized shadow.<br>
@@ -268,11 +275,10 @@ void __hwasan_init() {<br>
   InitializeCoverage(common_<wbr>flags()->coverage, common_flags()->coverage_dir);<br>
<br>
   HwasanTSDInit();<br>
+  HwasanTSDThreadInit();<br>
<br>
   HwasanAllocatorInit();<br>
<br>
-  Thread::Create();<br>
-<br>
 #if HWASAN_CONTAINS_UBSAN<br>
   __ubsan::InitAsPlugin();<br>
 #endif<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan.h?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan.h?rev=342921&r1=<wbr>342920&r2=342921&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan.h (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan.h Mon Sep 24 14:38:42 2018<br>
@@ -41,6 +41,10 @@ typedef u8 tag_t;<br>
 const unsigned kAddressTagShift = 56;<br>
 const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;<br>
<br>
+// Minimal alignment of the shadow base address. Determines the space available<br>
+// for threads and stack histories. This is an ABI constant.<br>
+const unsigned kShadowBaseAlignment = 32;<br>
+<br>
 static inline tag_t GetTagFromPointer(uptr p) {<br>
   return p >> kAddressTagShift;<br>
 }<br>
@@ -66,6 +70,7 @@ extern int hwasan_report_count;<br>
<br>
 bool ProtectRange(uptr beg, uptr end);<br>
 bool InitShadow();<br>
+void InitThreads();<br>
 void MadviseShadow();<br>
 char *GetProcSelfMaps();<br>
 void InitializeInterceptors();<br>
@@ -142,6 +147,7 @@ class ScopedThreadLocalStateBackup {<br>
 };<br>
<br>
 void HwasanTSDInit();<br>
+void HwasanTSDThreadInit();<br>
<br>
 void HwasanOnDeadlySignal(int signo, void *info, void *context);<br>
<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_dynamic_shadow.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_dynamic_shadow.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_dynamic_shadow.<wbr>cc?rev=342921&r1=342920&r2=<wbr>342921&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_dynamic_shadow.cc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_dynamic_shadow.cc Mon Sep 24 14:38:42 2018<br>
@@ -13,6 +13,7 @@<br>
 ///<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
<br>
+#include "hwasan.h"<br>
 #include "hwasan_dynamic_shadow.h"<br>
 #include "hwasan_mapping.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>common.h"<br>
@@ -35,12 +36,16 @@ static void UnmapFromTo(uptr from, uptr<br>
   }<br>
 }<br>
<br>
-// Returns an address aligned to 8 pages, such that one page on the left and<br>
-// shadow_size_bytes bytes on the right of it are mapped r/o.<br>
+// Returns an address aligned to kShadowBaseAlignment, such that<br>
+// 2**kShadowBaseAlingment on the left and shadow_size_bytes bytes on the right<br>
+// of it are mapped no access.<br>
 static uptr MapDynamicShadow(uptr shadow_size_bytes) {<br>
   const uptr granularity = GetMmapGranularity();<br>
-  const uptr alignment = granularity << kShadowScale;<br>
-  const uptr left_padding = granularity;<br>
+  const uptr min_alignment = granularity << kShadowScale;<br>
+  const uptr alignment = 1ULL << kShadowBaseAlignment;<br>
+  CHECK_GE(alignment, min_alignment);<br>
+<br>
+  const uptr left_padding = 1ULL << kShadowBaseAlignment;<br>
   const uptr shadow_size =<br>
       RoundUpTo(shadow_size_bytes, granularity);<br>
   const uptr map_size = shadow_size + left_padding + alignment;<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_flags.inc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_flags.inc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_flags.inc?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_flags.inc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_flags.inc Mon Sep 24 14:38:42 2018<br>
@@ -51,3 +51,7 @@ HWASAN_FLAG(int, heap_history_size, 1023<br>
           "to find bugs.")<br>
 HWASAN_FLAG(bool, export_memory_stats, true,<br>
             "Export up-to-date memory stats through /proc")<br>
+HWASAN_FLAG(int, stack_history_size, 1024,<br>
+            "The number of stack frames remembered per thread. "<br>
+            "Affects the quality of stack-related reports, but not the ability "<br>
+            "to find bugs.")<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_linux.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_linux.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_linux.cc?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_linux.cc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_linux.cc Mon Sep 24 14:38:42 2018<br>
@@ -22,6 +22,7 @@<br>
 #include "hwasan_mapping.h"<br>
 #include "hwasan_report.h"<br>
 #include "hwasan_thread.h"<br>
+#include "hwasan_thread_list.h"<br>
<br>
 #include <elf.h><br>
 #include <link.h><br>
@@ -37,6 +38,10 @@<br>
 #include "sanitizer_common/sanitizer_<wbr>common.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>procmaps.h"<br>
<br>
+#if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID<br>
+THREADLOCAL uptr __hwasan_tls;<br>
+#endif<br>
+<br>
 namespace __hwasan {<br>
<br>
 static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {<br>
@@ -179,6 +184,20 @@ bool InitShadow() {<br>
   return true;<br>
 }<br>
<br>
+void InitThreads() {<br>
+  CHECK(__hwasan_shadow_memory_<wbr>dynamic_address);<br>
+  uptr guard_page_size = GetMmapGranularity();<br>
+  uptr thread_space_start =<br>
+      __hwasan_shadow_memory_<wbr>dynamic_address - (1ULL << kShadowBaseAlignment);<br>
+  uptr thread_space_end =<br>
+      __hwasan_shadow_memory_<wbr>dynamic_address - guard_page_size;<br>
+  ReserveShadowMemoryRange(<wbr>thread_space_start, thread_space_end - 1,<br>
+                           "hwasan threads");<br>
+  ProtectGap(thread_space_end,<br>
+             __hwasan_shadow_memory_<wbr>dynamic_address - thread_space_end);<br>
+  InitThreadList(thread_space_<wbr>start, thread_space_end - thread_space_start);<br>
+}<br>
+<br>
 static void MadviseShadowRegion(uptr beg, uptr end) {<br>
   uptr size = end - beg + 1;<br>
   if (common_flags()->no_huge_<wbr>pages_for_shadow)<br>
@@ -214,7 +233,7 @@ void InstallAtExitHandler() {<br>
 // ---------------------- TSD ---------------- {{{1<br>
<br>
 extern "C" void __hwasan_thread_enter() {<br>
-  Thread::Create();<br>
+  hwasanThreadList().<wbr>CreateCurrentThread();<br>
 }<br>
<br>
 extern "C" void __hwasan_thread_exit() {<br>
@@ -222,21 +241,25 @@ extern "C" void __hwasan_thread_exit() {<br>
   // Make sure that signal handler can not see a stale current thread pointer.<br>
   atomic_signal_fence(memory_<wbr>order_seq_cst);<br>
   if (t)<br>
-    t->Destroy();<br>
+    hwasanThreadList().<wbr>ReleaseThread(t);<br>
 }<br>
<br>
 #if HWASAN_WITH_INTERCEPTORS<br>
 static pthread_key_t tsd_key;<br>
 static bool tsd_key_inited = false;<br>
<br>
+void HwasanTSDThreadInit() {<br>
+  if (tsd_key_inited)<br>
+    CHECK_EQ(0, pthread_setspecific(tsd_key,<br>
+                                    (void *)<wbr>GetPthreadDestructorIterations<wbr>()));<br>
+}<br>
+<br>
 void HwasanTSDDtor(void *tsd) {<br>
-  Thread *t = (Thread*)tsd;<br>
-  if (t->destructor_iterations_ > 1) {<br>
-    t->destructor_iterations_--;<br>
-    CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));<br>
+  uptr iterations = (uptr)tsd;<br>
+  if (iterations > 1) {<br>
+    CHECK_EQ(0, pthread_setspecific(tsd_key, (void *)(iterations - 1)));<br>
     return;<br>
   }<br>
-  t->Destroy();<br>
   __hwasan_thread_exit();<br>
 }<br>
<br>
@@ -245,31 +268,26 @@ void HwasanTSDInit() {<br>
   tsd_key_inited = true;<br>
   CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor));<br>
 }<br>
-<br>
-Thread *GetCurrentThread() {<br>
-  return (Thread *)pthread_getspecific(tsd_key)<wbr>;<br>
-}<br>
-<br>
-void SetCurrentThread(Thread *t) {<br>
-  // Make sure that HwasanTSDDtor gets called at the end.<br>
-  CHECK(tsd_key_inited);<br>
-  // Make sure we do not reset the current Thread.<br>
-  CHECK_EQ(0, pthread_getspecific(tsd_key));<br>
-  pthread_setspecific(tsd_key, (void *)t);<br>
-}<br>
-#elif SANITIZER_ANDROID<br>
+#else<br>
 void HwasanTSDInit() {}<br>
-Thread *GetCurrentThread() {<br>
-  return (Thread*)*get_android_tls_ptr(<wbr>);<br>
-}<br>
+void HwasanTSDThreadInit() {}<br>
+#endif<br>
<br>
-void SetCurrentThread(Thread *t) {<br>
-  *get_android_tls_ptr() = (uptr)t;<br>
+#if SANITIZER_ANDROID<br>
+uptr *GetCurrentThreadLongPtr() {<br>
+  return (uptr *)get_android_tls_ptr();<br>
 }<br>
 #else<br>
-#error unsupported configuration !HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID<br>
+uptr *GetCurrentThreadLongPtr() {<br>
+  return &__hwasan_tls;<br>
+}<br>
 #endif<br>
<br>
+Thread *GetCurrentThread() {<br>
+  auto *R = (StackAllocationsRingBuffer*)<wbr>GetCurrentThreadLongPtr();<br>
+  return hwasanThreadList().<wbr>GetThreadByBufferAddress((<wbr>uptr)(R->Next()));<br>
+}<br>
+<br>
 struct AccessInfo {<br>
   uptr addr;<br>
   uptr size;<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_report.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_report.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_report.cc?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_report.cc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_report.cc Mon Sep 24 14:38:42 2018<br>
@@ -16,6 +16,7 @@<br>
 #include "hwasan_allocator.h"<br>
 #include "hwasan_mapping.h"<br>
 #include "hwasan_thread.h"<br>
+#include "hwasan_thread_list.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>allocator_internal.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>common.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>flags.h"<br>
@@ -35,6 +36,31 @@ static StackTrace GetStackTraceFromId(u3<br>
   return res;<br>
 }<br>
<br>
+// A RAII object that holds a copy of the current thread stack ring buffer.<br>
+// The actual stack buffer may change while we are iterating over it (for<br>
+// example, Printf may call syslog() which can itself be built with hwasan).<br>
+class SavedStackAllocations {<br>
+ public:<br>
+  SavedStackAllocations(<wbr>StackAllocationsRingBuffer *rb) {<br>
+    uptr size = rb->size() * sizeof(uptr);<br>
+    void *storage =<br>
+        MmapAlignedOrDieOnFatalError(<wbr>size, size * 2, "saved stack allocations");<br>
+    new (&rb_) StackAllocationsRingBuffer(*<wbr>rb, storage);<br>
+  }<br>
+<br>
+  ~SavedStackAllocations() {<br>
+    StackAllocationsRingBuffer *rb = get();<br>
+    UnmapOrDie(rb->StartOfStorage(<wbr>), rb->size() * sizeof(uptr));<br>
+  }<br>
+<br>
+  StackAllocationsRingBuffer *get() {<br>
+    return (StackAllocationsRingBuffer *)&rb_;<br>
+  }<br>
+<br>
+ private:<br>
+  uptr rb_;<br>
+};<br>
+<br>
 class Decorator: public __sanitizer::<wbr>SanitizerCommonDecorator {<br>
  public:<br>
   Decorator() : SanitizerCommonDecorator() { }<br>
@@ -63,7 +89,9 @@ uptr FindHeapAllocation(<wbr>HeapAllocationsR<br>
   return 0;<br>
 }<br>
<br>
-void PrintAddressDescription(uptr tagged_addr, uptr access_size) {<br>
+void PrintAddressDescription(<br>
+    uptr tagged_addr, uptr access_size,<br>
+    StackAllocationsRingBuffer *current_stack_allocations) {<br>
   Decorator d;<br>
   int num_descriptions_printed = 0;<br>
   uptr untagged_addr = UntagAddr(tagged_addr);<br>
@@ -109,7 +137,7 @@ void PrintAddressDescription(uptr tagged<br>
     }<br>
   }<br>
<br>
-  Thread::VisitAllLiveThreads([&<wbr>](Thread *t) {<br>
+  hwasanThreadList().<wbr>VisitAllLiveThreads([&](Thread *t) {<br>
     // Scan all threads' ring buffers to find if it's a heap-use-after-free.<br>
     HeapAllocationRecord har;<br>
     if (uptr D = FindHeapAllocation(t->heap_<wbr>allocations(), tagged_addr, &har)) {<br>
@@ -145,6 +173,25 @@ void PrintAddressDescription(uptr tagged<br>
       Printf("%s", d.Default());<br>
       t->Announce();<br>
<br>
+      // Temporary report section, needs to be improved.<br>
+      Printf("Previosly allocated frames:\n");<br>
+      auto *sa = (t == GetCurrentThread() && current_stack_allocations)<br>
+                     ? current_stack_allocations<br>
+                     : t->stack_allocations();<br>
+      uptr frames = Min((uptr)flags()->stack_<wbr>history_size, sa->size());<br>
+      for (uptr i = 0; i < frames; i++) {<br>
+        uptr record = (*sa)[i];<br>
+        if (!record)<br>
+          break;<br>
+        uptr sp = (record >> 48) << 4;<br>
+        uptr pc_mask = (1ULL << 48) - 1;<br>
+        uptr pc = record & pc_mask;<br>
+        uptr fixed_pc = StackTrace::<wbr>GetNextInstructionPc(pc);<br>
+        StackTrace stack(&fixed_pc, 1);<br>
+        Printf("record: %p pc: %p sp: %p", record, pc, sp);<br>
+        stack.Print();<br>
+      }<br>
+<br>
       num_descriptions_printed++;<br>
     }<br>
   });<br>
@@ -170,13 +217,16 @@ void ReportStats() {}<br>
 void ReportInvalidAccessInsideAddre<wbr>ssRange(const char *what, const void *start,<br>
                                            uptr size, uptr offset) {<br>
   ScopedErrorReportLock l;<br>
+  SavedStackAllocations current_stack_allocations(<br>
+      GetCurrentThread()->stack_<wbr>allocations());<br>
<br>
   Decorator d;<br>
   Printf("%s", d.Warning());<br>
   Printf("%sTag mismatch in %s%s%s at offset %zu inside [%p, %zu)%s\n",<br>
          d.Warning(), d.Name(), what, d.Warning(), offset, start, size,<br>
          d.Default());<br>
-  PrintAddressDescription((uptr)<wbr>start + offset, 1);<br>
+  PrintAddressDescription((uptr)<wbr>start + offset, 1,<br>
+                          current_stack_allocations.get(<wbr>));<br>
   // if (__sanitizer::Verbosity())<br>
   //   DescribeMemoryRange(start, size);<br>
 }<br>
@@ -224,7 +274,7 @@ void ReportInvalidFree(StackTrace *stack<br>
<br>
   stack->Print();<br>
<br>
-  PrintAddressDescription(<wbr>tagged_addr, 0);<br>
+  PrintAddressDescription(<wbr>tagged_addr, 0, nullptr);<br>
<br>
   PrintTagsAroundAddr(tag_ptr);<br>
<br>
@@ -235,6 +285,8 @@ void ReportInvalidFree(StackTrace *stack<br>
 void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,<br>
                        bool is_store) {<br>
   ScopedErrorReportLock l;<br>
+  SavedStackAllocations current_stack_allocations(<br>
+      GetCurrentThread()->stack_<wbr>allocations());<br>
<br>
   Decorator d;<br>
   Printf("%s", d.Error());<br>
@@ -258,7 +310,8 @@ void ReportTagMismatch(StackTrace *stack<br>
<br>
   stack->Print();<br>
<br>
-  PrintAddressDescription(<wbr>tagged_addr, access_size);<br>
+  PrintAddressDescription(<wbr>tagged_addr, access_size,<br>
+                          current_stack_allocations.get(<wbr>));<br>
   t->Announce();<br>
<br>
   PrintTagsAroundAddr(tag_ptr);<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_thread.cc?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.cc (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.cc Mon Sep 24 14:38:42 2018<br>
@@ -9,6 +9,7 @@<br>
 #include "sanitizer_common/sanitizer_<wbr>placement_new.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>tls_get_addr.h"<br>
<br>
+<br>
 namespace __hwasan {<br>
<br>
 static u32 RandomSeed() {<br>
@@ -24,102 +25,52 @@ static u32 RandomSeed() {<br>
   return seed;<br>
 }<br>
<br>
-Thread *Thread::thread_list_head;<br>
-SpinMutex Thread::thread_list_mutex;<br>
-Thread::ThreadStats Thread::thread_stats;<br>
-<br>
-void Thread::InsertIntoThreadList(<wbr>Thread *t) {<br>
-  CHECK(!t->next_);<br>
-  SpinMutexLock l(&thread_list_mutex);<br>
-  thread_stats.n_live_threads++;<br>
-  thread_stats.total_stack_size += t->stack_size();<br>
-  if (!thread_list_head) {<br>
-    thread_list_head = t;<br>
-    return;<br>
-  }<br>
-  Thread *last = thread_list_head;<br>
-  while (last->next_)<br>
-    last = last->next_;<br>
-  last->next_ = t;<br>
-}<br>
-<br>
-void Thread::RemoveFromThreadList(<wbr>Thread *t) {<br>
-  SpinMutexLock l(&thread_list_mutex);<br>
-  thread_stats.n_live_threads--;<br>
-  thread_stats.total_stack_size -= t->stack_size();<br>
-  if (t == thread_list_head) {<br>
-    thread_list_head = t->next_;<br>
-    t->next_ = nullptr;<br>
-    return;<br>
-  }<br>
-  Thread *prev = thread_list_head;<br>
-  Thread *cur = prev->next_;<br>
-  CHECK(cur);<br>
-  while (cur) {<br>
-    if (cur == t) {<br>
-      prev->next_ = cur->next_;<br>
-      return;<br>
-    }<br>
-    prev = cur;<br>
-    cur = cur->next_;<br>
-  }<br>
-  CHECK(0 && "RemoveFromThreadList: thread not found");<br>
-}<br>
-<br>
-void Thread::Create() {<br>
+void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {<br>
   static u64 unique_id;<br>
-  uptr PageSize = GetPageSizeCached();<br>
-  uptr size = RoundUpTo(sizeof(Thread), PageSize);<br>
-  Thread *thread = (Thread*)MmapOrDie(size, __func__);<br>
-  thread->destructor_iterations_ = GetPthreadDestructorIterations<wbr>();<br>
-  thread->unique_id_ = unique_id++;<br>
-  thread->random_state_ =<br>
-      flags()->random_tags ? RandomSeed() : thread->unique_id_;<br>
+  unique_id_ = unique_id++;<br>
+  random_state_ = flags()->random_tags ? RandomSeed() : unique_id_;<br>
   if (auto sz = flags()->heap_history_size)<br>
-    thread->heap_allocations_ = HeapAllocationsRingBuffer::<wbr>New(sz);<br>
-  SetCurrentThread(thread);<br>
-  thread->Init();<br>
-  InsertIntoThreadList(thread);<br>
-}<br>
+    heap_allocations_ = HeapAllocationsRingBuffer::<wbr>New(sz);<br>
<br>
-uptr Thread::MemoryUsedPerThread() {<br>
-  uptr res = sizeof(Thread);<br>
-  if (auto sz = flags()->heap_history_size)<br>
-    res += HeapAllocationsRingBuffer::<wbr>SizeInBytes(sz);<br>
-  return res;<br>
-}<br>
+  HwasanTSDThreadInit();  // Only needed with interceptors.<br>
+  uptr *ThreadLong = GetCurrentThreadLongPtr();<br>
+  // The following implicitly sets (this) as the current thread.<br>
+  stack_allocations_ = new (ThreadLong)<br>
+      StackAllocationsRingBuffer((<wbr>void *)stack_buffer_start, stack_buffer_size);<br>
+  // Check that it worked.<br>
+  CHECK_EQ(GetCurrentThread(), this);<br>
<br>
-void Thread::Init() {<br>
-  // GetPthreadDestructorIterations may call malloc, so disable the tagging.<br>
+  // ScopedTaggingDisable needs GetCurrentThread to be set up.<br>
   ScopedTaggingDisabler disabler;<br>
<br>
   // If this process is "init" (pid 1), /proc may not be mounted yet.<br>
   if (IsMainThread() && !FileExists("/proc/self/maps")<wbr>) {<br>
     stack_top_ = stack_bottom_ = 0;<br>
     tls_begin_ = tls_end_ = 0;<br>
-    return;<br>
-  }<br>
+  } else {<br>
+    uptr tls_size;<br>
+    uptr stack_size;<br>
+    GetThreadStackAndTls(<wbr>IsMainThread(), &stack_bottom_, &stack_size,<br>
+                         &tls_begin_, &tls_size);<br>
+    stack_top_ = stack_bottom_ + stack_size;<br>
+    tls_end_ = tls_begin_ + tls_size;<br>
<br>
-  uptr tls_size;<br>
-  uptr stack_size;<br>
-  GetThreadStackAndTls(<wbr>IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_,<br>
-                       &tls_size);<br>
-  stack_top_ = stack_bottom_ + stack_size;<br>
-  tls_end_ = tls_begin_ + tls_size;<br>
-<br>
-  int local;<br>
-  CHECK(AddrIsInStack((uptr)&<wbr>local));<br>
-  CHECK(MemIsApp(stack_bottom_))<wbr>;<br>
-  CHECK(MemIsApp(stack_top_ - 1));<br>
-<br>
-  if (stack_bottom_) {<br>
+    int local;<br>
+    CHECK(AddrIsInStack((uptr)&<wbr>local));<br>
     CHECK(MemIsApp(stack_bottom_))<wbr>;<br>
     CHECK(MemIsApp(stack_top_ - 1));<br>
+<br>
+    if (stack_bottom_) {<br>
+      CHECK(MemIsApp(stack_bottom_))<wbr>;<br>
+      CHECK(MemIsApp(stack_top_ - 1));<br>
+    }<br>
   }<br>
+<br>
   if (flags()->verbose_threads) {<br>
     if (IsMainThread()) {<br>
-      Printf("sizeof(Thread): %zd sizeof(RB): %zd\n", sizeof(Thread),<br>
-             heap_allocations_-><wbr>SizeInBytes());<br>
+      Printf("sizeof(Thread): %zd sizeof(HeapRB): %zd sizeof(StackRB): %zd\n",<br>
+             sizeof(Thread), heap_allocations_-><wbr>SizeInBytes(),<br>
+             stack_allocations_->size() * sizeof(uptr));<br>
     }<br>
     Print("Creating  : ");<br>
   }<br>
@@ -137,11 +88,8 @@ void Thread::Destroy() {<br>
     Print("Destroying: ");<br>
   AllocatorSwallowThreadLocalCac<wbr>he(allocator_cache());<br>
   ClearShadowForThreadStackAndTL<wbr>S();<br>
-  RemoveFromThreadList(this);<br>
-  uptr size = RoundUpTo(sizeof(Thread), GetPageSizeCached());<br>
   if (heap_allocations_)<br>
     heap_allocations_->Delete();<br>
-  UnmapOrDie(this, size);<br>
   DTLS_Destroy();<br>
 }<br>
<br>
<br>
Modified: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread.h?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_thread.h?rev=<wbr>342921&r1=342920&r2=342921&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.h (original)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread.h Mon Sep 24 14:38:42 2018<br>
@@ -16,12 +16,15 @@<br>
<br>
 #include "hwasan_allocator.h"<br>
 #include "sanitizer_common/sanitizer_<wbr>common.h"<br>
+#include "sanitizer_common/sanitizer_<wbr>ring_buffer.h"<br>
<br>
 namespace __hwasan {<br>
<br>
+typedef __sanitizer::<wbr>CompactRingBuffer<uptr> StackAllocationsRingBuffer;<br>
+<br>
 class Thread {<br>
  public:<br>
-  static void Create();  // Must be called from the thread itself.<br>
+  void Init(uptr stack_buffer_start, uptr stack_buffer_size);  // Must be called from the thread itself.<br>
   void Destroy();<br>
<br>
   uptr stack_top() { return stack_top_; }<br>
@@ -48,27 +51,15 @@ class Thread {<br>
   void LeaveInterceptorScope() { in_interceptor_scope_--; }<br>
<br>
   AllocatorCache *allocator_cache() { return &allocator_cache_; }<br>
-  HeapAllocationsRingBuffer *heap_allocations() {<br>
-    return heap_allocations_;<br>
-  }<br>
+  HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }<br>
+  StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }<br>
<br>
   tag_t GenerateRandomTag();<br>
<br>
-  int destructor_iterations_;<br>
   void DisableTagging() { tagging_disabled_++; }<br>
   void EnableTagging() { tagging_disabled_--; }<br>
   bool TaggingIsDisabled() const { return tagging_disabled_; }<br>
<br>
-  template <class CB><br>
-  static void VisitAllLiveThreads(CB cb) {<br>
-    SpinMutexLock l(&thread_list_mutex);<br>
-    Thread *t = thread_list_head;<br>
-    while (t) {<br>
-      cb(t);<br>
-      t = t->next_;<br>
-    }<br>
-  }<br>
-<br>
   u64 unique_id() const { return unique_id_; }<br>
   void Announce() {<br>
     if (announced_) return;<br>
@@ -76,22 +67,9 @@ class Thread {<br>
     Print("Thread: ");<br>
   }<br>
<br>
-  struct ThreadStats {<br>
-    uptr n_live_threads;<br>
-    uptr total_stack_size;<br>
-  };<br>
-<br>
-  static ThreadStats GetThreadStats() {<br>
-    SpinMutexLock l(&thread_list_mutex);<br>
-    return thread_stats;<br>
-  }<br>
-<br>
-  static uptr MemoryUsedPerThread();<br>
-<br>
  private:<br>
   // NOTE: There is no Thread constructor. It is allocated<br>
   // via mmap() and *must* be valid in zero-initialized state.<br>
-  void Init();<br>
   void ClearShadowForThreadStackAndTL<wbr>S();<br>
   void Print(const char *prefix);<br>
   uptr stack_top_;<br>
@@ -108,23 +86,23 @@ class Thread {<br>
<br>
   AllocatorCache allocator_cache_;<br>
   HeapAllocationsRingBuffer *heap_allocations_;<br>
+  StackAllocationsRingBuffer *stack_allocations_;<br>
<br>
   static void InsertIntoThreadList(Thread *t);<br>
   static void RemoveFromThreadList(Thread *t);<br>
   Thread *next_;  // All live threads form a linked list.<br>
-  static SpinMutex thread_list_mutex;<br>
-  static Thread *thread_list_head;<br>
-  static ThreadStats thread_stats;<br>
<br>
   u64 unique_id_;  // counting from zero.<br>
<br>
   u32 tagging_disabled_;  // if non-zero, malloc uses zero tag in this thread.<br>
<br>
   bool announced_;<br>
+<br>
+  friend struct ThreadListHead;<br>
 };<br>
<br>
 Thread *GetCurrentThread();<br>
-void SetCurrentThread(Thread *t);<br>
+uptr *GetCurrentThreadLongPtr();<br>
<br>
 struct ScopedTaggingDisabler {<br>
   ScopedTaggingDisabler() { GetCurrentThread()-><wbr>DisableTagging(); }<br>
<br>
Added: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread_list.cc?rev=342921&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_thread_list.cc?<wbr>rev=342921&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.cc (added)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.cc Mon Sep 24 14:38:42 2018<br>
@@ -0,0 +1,15 @@<br>
+#include "hwasan_thread_list.h"<br>
+<br>
+namespace __hwasan {<br>
+static ALIGNED(16) char thread_list_placeholder[<wbr>sizeof(HwasanThreadList)];<br>
+static HwasanThreadList *hwasan_thread_list;<br>
+<br>
+HwasanThreadList &hwasanThreadList() { return *hwasan_thread_list; }<br>
+<br>
+void InitThreadList(uptr storage, uptr size) {<br>
+  CHECK(hwasan_thread_list == nullptr);<br>
+  hwasan_thread_list =<br>
+      new (thread_list_placeholder) HwasanThreadList(storage, size);<br>
+}<br>
+<br>
+} // namespace<br>
<br>
Added: compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_thread_list.h?rev=342921&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>hwasan/hwasan_thread_list.h?<wbr>rev=342921&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.h (added)<br>
+++ compiler-rt/trunk/lib/hwasan/<wbr>hwasan_thread_list.h Mon Sep 24 14:38:42 2018<br>
@@ -0,0 +1,200 @@<br>
+//===-- hwasan_thread_list.h ------------------------------<wbr>------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+//<br>
+// This file is a part of HWAddressSanitizer.<br>
+//<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+<br>
+// HwasanThreadList is a registry for live threads, as well as an allocator for<br>
+// HwasanThread objects and their stack history ring buffers. There are<br>
+// constraints on memory layout of the shadow region and CompactRingBuffer that<br>
+// are part of the ABI contract between compiler-rt and llvm.<br>
+//<br>
+// * Start of the shadow memory region is aligned to 2**kShadowBaseAlignment.<br>
+// * All stack ring buffers are located within (2**kShadowBaseAlignment)<br>
+// sized region below and adjacent to the shadow region.<br>
+// * Each ring buffer has a size of (2**N)*4096 where N is in [0, 8), and is<br>
+// aligned to twice its size. The value of N can be different for each buffer.<br>
+//<br>
+// These constrains guarantee that, given an address A of any element of the<br>
+// ring buffer,<br>
+//     A_next = (A + sizeof(uptr)) & ~((1 << (N + 13)) - 1)<br>
+//   is the address of the next element of that ring buffer (with wrap-around).<br>
+// And, with K = kShadowBaseAlignment,<br>
+//     S = (A | ((1 << K) - 1)) + 1<br>
+//   (align up to kShadowBaseAlignment) is the start of the shadow region.<br>
+//<br>
+// These calculations are used in compiler instrumentation to update the ring<br>
+// buffer and obtain the base address of shadow using only two inputs: address<br>
+// of the current element of the ring buffer, and N (i.e. size of the ring<br>
+// buffer). Since the value of N is very limited, we pack both inputs into a<br>
+// single thread-local word as<br>
+//   (1 << (N + 56)) | A<br>
+// See the implementation of class CompactRingBuffer, which is what is stored in<br>
+// said thread-local word.<br>
+//<br>
+// Note the unusual way of aligning up the address of the shadow:<br>
+//   (A | ((1 << K) - 1)) + 1<br>
+// It is only correct if A is not already equal to the shadow base address, but<br>
+// it saves 2 instructions on AArch64.<br>
+<br>
+#include "hwasan.h"<br>
+#include "hwasan_allocator.h"<br>
+#include "hwasan_flags.h"<br>
+#include "hwasan_thread.h"<br>
+<br>
+#include "sanitizer_common/sanitizer_<wbr>placement_new.h"<br>
+<br>
+namespace __hwasan {<br>
+<br>
+static uptr RingBufferSize() {<br>
+  uptr desired_bytes = flags()->stack_history_size * sizeof(uptr);<br>
+  // FIXME: increase the limit to 8 once this bug is fixed:<br>
+  // <a href="https://bugs.llvm.org/show_bug.cgi?id=39030" rel="noreferrer" target="_blank">https://bugs.llvm.org/show_<wbr>bug.cgi?id=39030</a><br>
+  for (int shift = 1; shift < 7; ++shift) {<br>
+    uptr size = 4096 * (1ULL << shift);<br>
+    if (size >= desired_bytes)<br>
+      return size;<br>
+  }<br>
+  Printf("stack history size too large: %d\n", flags()->stack_history_size);<br>
+  CHECK(0);<br>
+  return 0;<br>
+}<br>
+<br>
+struct ThreadListHead {<br>
+  Thread *list_;<br>
+<br>
+  ThreadListHead() : list_(nullptr) {}<br>
+<br>
+  void Push(Thread *t) {<br>
+    t->next_ = list_;<br>
+    list_ = t;<br>
+  }<br>
+<br>
+  Thread *Pop() {<br>
+    Thread *t = list_;<br>
+    if (t)<br>
+      list_ = t->next_;<br>
+    return t;<br>
+  }<br>
+<br>
+  void Remove(Thread *t) {<br>
+    Thread **cur = &list_;<br>
+    while (*cur != t) cur = &(*cur)->next_;<br>
+    CHECK(*cur && "thread not found");<br>
+    *cur = (*cur)->next_;<br>
+  }<br>
+<br>
+  template <class CB><br>
+  void ForEach(CB cb) {<br>
+    Thread *t = list_;<br>
+    while (t) {<br>
+      cb(t);<br>
+      t = t->next_;<br>
+    }<br>
+  }<br>
+};<br>
+<br>
+struct ThreadStats {<br>
+  uptr n_live_threads;<br>
+  uptr total_stack_size;<br>
+};<br>
+<br>
+class HwasanThreadList {<br>
+ public:<br>
+  HwasanThreadList(uptr storage, uptr size)<br>
+      : free_space_(storage),<br>
+        free_space_end_(storage + size),<br>
+        ring_buffer_size_(<wbr>RingBufferSize()) {}<br>
+<br>
+  Thread *CreateCurrentThread() {<br>
+    Thread *t;<br>
+    {<br>
+      SpinMutexLock l(&list_mutex_);<br>
+      t = free_list_.Pop();<br>
+      if (t)<br>
+        internal_memset((void *)t, 0, sizeof(Thread) + ring_buffer_size_);<br>
+      else<br>
+        t = AllocThread();<br>
+      live_list_.Push(t);<br>
+    }<br>
+    t->Init((uptr)(t + 1), ring_buffer_size_);<br>
+    AddThreadStats(t);<br>
+    return t;<br>
+  }<br>
+<br>
+  void ReleaseThread(Thread *t) {<br>
+    // FIXME: madvise away the ring buffer?<br>
+    RemoveThreadStats(t);<br>
+    t->Destroy();<br>
+    SpinMutexLock l(&list_mutex_);<br>
+    live_list_.Remove(t);<br>
+    free_list_.Push(t);<br>
+  }<br>
+<br>
+  Thread *GetThreadByBufferAddress(uptr p) {<br>
+    uptr align = ring_buffer_size_ * 2;<br>
+    return (Thread *)(RoundDownTo(p, align) - sizeof(Thread));<br>
+  }<br>
+<br>
+  uptr MemoryUsedPerThread() {<br>
+    uptr res = sizeof(Thread) + ring_buffer_size_;<br>
+    if (auto sz = flags()->heap_history_size)<br>
+      res += HeapAllocationsRingBuffer::<wbr>SizeInBytes(sz);<br>
+    return res;<br>
+  }<br>
+<br>
+  template <class CB><br>
+  void VisitAllLiveThreads(CB cb) {<br>
+    SpinMutexLock l(&list_mutex_);<br>
+    live_list_.ForEach(cb);<br>
+  }<br>
+<br>
+  void AddThreadStats(Thread *t) {<br>
+    SpinMutexLock l(&stats_mutex_);<br>
+    stats_.n_live_threads++;<br>
+    stats_.total_stack_size += t->stack_size();<br>
+  }<br>
+<br>
+  void RemoveThreadStats(Thread *t) {<br>
+    SpinMutexLock l(&stats_mutex_);<br>
+    stats_.n_live_threads--;<br>
+    stats_.total_stack_size -= t->stack_size();<br>
+  }<br>
+<br>
+  ThreadStats GetThreadStats() {<br>
+    SpinMutexLock l(&stats_mutex_);<br>
+    return stats_;<br>
+  }<br>
+<br>
+ private:<br>
+  Thread *AllocThread() {<br>
+    uptr align = ring_buffer_size_ * 2;<br>
+    uptr ring_buffer_start = RoundUpTo(free_space_ + sizeof(Thread), align);<br>
+    free_space_ = ring_buffer_start + ring_buffer_size_;<br>
+    CHECK(free_space_ <= free_space_end_ && "out of thread memory");<br>
+    return (Thread *)(ring_buffer_start - sizeof(Thread));<br>
+  }<br>
+<br>
+  uptr free_space_;<br>
+  uptr free_space_end_;<br>
+  uptr ring_buffer_size_;<br>
+<br>
+  ThreadListHead free_list_;<br>
+  ThreadListHead live_list_;<br>
+  SpinMutex list_mutex_;<br>
+<br>
+  ThreadStats stats_;<br>
+  SpinMutex stats_mutex_;<br>
+};<br>
+<br>
+void InitThreadList(uptr storage, uptr size);<br>
+HwasanThreadList &hwasanThreadList();<br>
+<br>
+} // namespace<br>
<br>
Modified: compiler-rt/trunk/lib/<wbr>sanitizer_common/sanitizer_<wbr>ring_buffer.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_ring_buffer.h?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>sanitizer_common/sanitizer_<wbr>ring_buffer.h?rev=342921&r1=<wbr>342920&r2=342921&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/<wbr>sanitizer_common/sanitizer_<wbr>ring_buffer.h (original)<br>
+++ compiler-rt/trunk/lib/<wbr>sanitizer_common/sanitizer_<wbr>ring_buffer.h Mon Sep 24 14:38:42 2018<br>
@@ -72,12 +72,91 @@ class RingBuffer {<br>
   // L: last_, always points to the last data element.<br>
   // N: next_, initially equals to last_, is decremented on every push,<br>
   //    wraps around if it's less or equal than its own address.<br>
-<br>
   T *last_;<br>
   T *next_;<br>
   T data_[1];  // flexible array.<br>
 };<br>
<br>
+// A ring buffer with externally provided storage that encodes its state in 8<br>
+// bytes. Has significant constraints on size and alignment of storage.<br>
+// See a comment in hwasan/hwasan_thread_list.h for the motivation behind this.<br>
+#if SANITIZER_WORDSIZE == 64<br>
+template <class T><br>
+class CompactRingBuffer {<br>
+  // Top byte of long_ stores the buffer size in pages.<br>
+  // Lower bytes store the address of the next buffer element.<br>
+  static constexpr int kPageSizeBits = 12;<br>
+  static constexpr int kSizeShift = 56;<br>
+  static constexpr uptr kNextMask = (1ULL << kSizeShift) - 1;<br>
+<br>
+  uptr GetStorageSize() const { return (long_ >> kSizeShift) << kPageSizeBits; }<br>
+<br>
+  void Init(void *storage, uptr size) {<br>
+    CHECK_EQ(sizeof(<wbr>CompactRingBuffer<T>), sizeof(void *));<br>
+    CHECK(IsPowerOfTwo(size));<br>
+    CHECK_GE(size, 1 << kPageSizeBits);<br>
+    CHECK_LE(size, 128 << kPageSizeBits);<br>
+    CHECK_EQ(size % 4096, 0);<br>
+    CHECK_EQ(size % sizeof(T), 0);<br>
+    CHECK_EQ((uptr)storage % (size * 2), 0);<br>
+    long_ = (uptr)storage | ((size >> kPageSizeBits) << kSizeShift);<br>
+  }<br>
+<br>
+  void SetNext(const T *next) {<br>
+    long_ = (long_ & ~kNextMask) | (uptr)next;<br>
+  }<br>
+<br>
+ public:<br>
+  CompactRingBuffer(void *storage, uptr size) {<br>
+    Init(storage, size);<br>
+  }<br>
+<br>
+  // A copy constructor of sorts.<br>
+  CompactRingBuffer(const CompactRingBuffer &other, void *storage) {<br>
+    uptr size = other.GetStorageSize();<br>
+    internal_memcpy(storage, other.StartOfStorage(), size);<br>
+    Init(storage, size);<br>
+    uptr Idx = other.Next() - (const T *)other.StartOfStorage();<br>
+    SetNext((const T *)storage + Idx);<br>
+  }<br>
+<br>
+  T *Next() const { return (T *)(long_ & kNextMask); }<br>
+<br>
+  void *StartOfStorage() const {<br>
+    return (void *)((uptr)Next() & ~(GetStorageSize() - 1));<br>
+  }<br>
+<br>
+  void *EndOfStorage() const {<br>
+    return (void *)((uptr)StartOfStorage() + GetStorageSize());<br>
+  }<br>
+<br>
+  uptr size() const { return GetStorageSize() / sizeof(T); }<br>
+<br>
+  void push(T t) {<br>
+    T *next = Next();<br>
+    *next = t;<br>
+    next++;<br>
+    next = (T *)((uptr)next & ~GetStorageSize());<br>
+    SetNext(next);<br>
+  }<br>
+<br>
+  T operator[](uptr Idx) const {<br>
+    CHECK_LT(Idx, size());<br>
+    const T *Begin = (const T *)StartOfStorage();<br>
+    sptr StorageIdx = Next() - Begin;<br>
+    StorageIdx -= (sptr)(Idx + 1);<br>
+    if (StorageIdx < 0)<br>
+      StorageIdx += size();<br>
+    return Begin[StorageIdx];<br>
+  }<br>
+<br>
+ public:<br>
+  ~CompactRingBuffer() {}<br>
+  CompactRingBuffer(const CompactRingBuffer &) = delete;<br>
+<br>
+  uptr long_;<br>
+};<br>
+#endif<br>
 }  // namespace __sanitizer<br>
<br>
 #endif  // SANITIZER_RING_BUFFER_H<br>
<br>
Modified: compiler-rt/trunk/lib/<wbr>sanitizer_common/tests/<wbr>sanitizer_ring_buffer_test.cc<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/tests/sanitizer_ring_buffer_test.cc?rev=342921&r1=342920&r2=342921&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/lib/<wbr>sanitizer_common/tests/<wbr>sanitizer_ring_buffer_test.cc?<wbr>rev=342921&r1=342920&r2=<wbr>342921&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/lib/<wbr>sanitizer_common/tests/<wbr>sanitizer_ring_buffer_test.cc (original)<br>
+++ compiler-rt/trunk/lib/<wbr>sanitizer_common/tests/<wbr>sanitizer_ring_buffer_test.cc Mon Sep 24 14:38:42 2018<br>
@@ -66,6 +66,7 @@ template <class T> void TestRB() {<br>
 #undef EXPECT_RING_BUFFER<br>
 }<br>
<br>
+#if SANITIZER_WORDSIZE == 64<br>
 TEST(RingBuffer, int64) {<br>
   TestRB<int64_t>();<br>
 }<br>
@@ -74,4 +75,25 @@ TEST(RingBuffer, LargeStruct) {<br>
   TestRB<LargeStruct>();<br>
 }<br>
<br>
+template<typename T><br>
+CompactRingBuffer<T> *AllocCompactRingBuffer(size_t count) {<br>
+  size_t sz = sizeof(T) * count;<br>
+  EXPECT_EQ(0ULL, sz % 4096);<br>
+  void *p = MmapAlignedOrDieOnFatalError(<wbr>sz, sz * 2, "CompactRingBuffer");<br>
+  return new CompactRingBuffer<T>(p, sz);<br>
+}<br>
+<br>
+TEST(CompactRingBuffer, int64) {<br>
+  const size_t page_sizes[] = {1, 2, 4, 128};<br>
+<br>
+  for (size_t pages : page_sizes) {<br>
+    size_t count = 4096 * pages / sizeof(int64_t);<br>
+    auto R = AllocCompactRingBuffer<int64_<wbr>t>(count);<br>
+    int64_t top = count * 3 + 13;<br>
+    for (int64_t i = 0; i < top; ++i) R->push(i);<br>
+    for (int64_t i = 0; i < (int64_t)count; ++i)<br>
+      EXPECT_EQ(top - i - 1, (*R)[i]);<br>
+  }<br>
+}<br>
+#endif<br>
 }  // namespace __sanitizer<br>
<br>
Added: compiler-rt/trunk/test/hwasan/<wbr>TestCases/deep-recursion.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/deep-recursion.c?rev=342921&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/<wbr>test/hwasan/TestCases/deep-<wbr>recursion.c?rev=342921&view=<wbr>auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/test/hwasan/<wbr>TestCases/deep-recursion.c (added)<br>
+++ compiler-rt/trunk/test/hwasan/<wbr>TestCases/deep-recursion.c Mon Sep 24 14:38:42 2018<br>
@@ -0,0 +1,73 @@<br>
+// RUN: %clang_hwasan -O1 %s -o %t<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=1 not %run %t 2>&1 | FileCheck %s --check-prefix=D1<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=D2<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=3 not %run %t 2>&1 | FileCheck %s --check-prefix=D3<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=5 not %run %t 2>&1 | FileCheck %s --check-prefix=D5<br>
+// RUN:                                       not %run %t 2>&1 | FileCheck %s --check-prefix=DEFAULT<br>
+<br>
+// REQUIRES: stable-runtime<br>
+<br>
+#include <stdlib.h><br>
+// At least -O1 is needed for this function to not have a stack frame on<br>
+// AArch64.<br>
+void USE(void *x) { // pretend_to_do_something(void *x)<br>
+  __asm__ __volatile__("" : : "r" (x) : "memory");<br>
+}<br>
+<br>
+volatile int four = 4;<br>
+<br>
+__attribute__((noinline)) void OOB() { int x[4]; x[four] = 0; USE(&x[0]); }<br>
+__attribute__((noinline)) void FUNC1() { int x; USE(&x); OOB(); }<br>
+__attribute__((noinline)) void FUNC2() { int x; USE(&x); FUNC1(); }<br>
+__attribute__((noinline)) void FUNC3() { int x; USE(&x); FUNC2(); }<br>
+__attribute__((noinline)) void FUNC4() { int x; USE(&x); FUNC3(); }<br>
+__attribute__((noinline)) void FUNC5() { int x; USE(&x); FUNC4(); }<br>
+__attribute__((noinline)) void FUNC6() { int x; USE(&x); FUNC5(); }<br>
+__attribute__((noinline)) void FUNC7() { int x; USE(&x); FUNC6(); }<br>
+__attribute__((noinline)) void FUNC8() { int x; USE(&x); FUNC7(); }<br>
+__attribute__((noinline)) void FUNC9() { int x; USE(&x); FUNC8(); }<br>
+__attribute__((noinline)) void FUNC10() { int x; USE(&x); FUNC9(); }<br>
+<br>
+int main() { FUNC10(); }<br>
+<br>
+// D1: Previosly allocated frames<br>
+// D1: in OOB<br>
+// D1-NOT: in FUNC<br>
+// D1: Memory tags around the buggy address<br>
+<br>
+// D2: Previosly allocated frames<br>
+// D2: in OOB<br>
+// D2: in FUNC1<br>
+// D2-NOT: in FUNC<br>
+// D2: Memory tags around the buggy address<br>
+<br>
+// D3: Previosly allocated frames<br>
+// D3: in OOB<br>
+// D3: in FUNC1<br>
+// D3: in FUNC2<br>
+// D3-NOT: in FUNC<br>
+// D3: Memory tags around the buggy address<br>
+<br>
+// D5: Previosly allocated frames<br>
+// D5: in OOB<br>
+// D5: in FUNC1<br>
+// D5: in FUNC2<br>
+// D5: in FUNC3<br>
+// D5: in FUNC4<br>
+// D5-NOT: in FUNC<br>
+// D5: Memory tags around the buggy address<br>
+<br>
+// DEFAULT: Previosly allocated frames<br>
+// DEFAULT: in OOB<br>
+// DEFAULT: in FUNC1<br>
+// DEFAULT: in FUNC2<br>
+// DEFAULT: in FUNC3<br>
+// DEFAULT: in FUNC4<br>
+// DEFAULT: in FUNC5<br>
+// DEFAULT: in FUNC6<br>
+// DEFAULT: in FUNC7<br>
+// DEFAULT: in FUNC8<br>
+// DEFAULT: in FUNC9<br>
+// DEFAULT: in FUNC10<br>
+// DEFAULT-NOT: in FUNC<br>
+// DEFAULT: Memory tags around the buggy address<br>
<br>
Added: compiler-rt/trunk/test/hwasan/<wbr>TestCases/rich-stack.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/rich-stack.c?rev=342921&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/<wbr>test/hwasan/TestCases/rich-<wbr>stack.c?rev=342921&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/test/hwasan/<wbr>TestCases/rich-stack.c (added)<br>
+++ compiler-rt/trunk/test/hwasan/<wbr>TestCases/rich-stack.c Mon Sep 24 14:38:42 2018<br>
@@ -0,0 +1,66 @@<br>
+// Test how stack frames are reported (not fully implemented yet).<br>
+// RUN: %clang_hwasan %s -o %t<br>
+// RUN: not %run %t 3 2 -1 2>&1 | FileCheck %s --check-prefix=R321<br>
+// REQUIRES: stable-runtime<br>
+#include <stdint.h><br>
+#include <stdlib.h><br>
+void USE(void *x) { // pretend_to_do_something(void *x)<br>
+  __asm__ __volatile__("" : : "r" (x) : "memory");<br>
+}<br>
+void USE2(void *a, void *b) { USE(a); USE(b); }<br>
+void USE4(void *a, void *b, void *c, void *d) { USE2(a, b); USE2(c, d); }<br>
+<br>
+void BAR(int depth, int err_depth, int offset);<br>
+<br>
+uint64_t *leaked_ptr;<br>
+<br>
+void FOO(int depth, int err_depth, int offset) {<br>
+  uint8_t v1;<br>
+  uint16_t v2;<br>
+  uint32_t v4;<br>
+  uint64_t v8;<br>
+  uint64_t v16[2];<br>
+  uint64_t v32[4];<br>
+  uint64_t v48[3];<br>
+  USE4(&v1, &v2, &v4, &v8);  USE4(&v16, &v32, &v48, 0);<br>
+  leaked_ptr = &v16[0];<br>
+  if (depth)<br>
+    BAR(depth - 1, err_depth, offset);<br>
+<br>
+  if (err_depth == depth)<br>
+    v16[offset] = 0;  // maybe OOB.<br>
+  if (err_depth == -depth)<br>
+    leaked_ptr[offset] = 0; // maybe UAR.<br>
+  USE(&v16);<br>
+}<br>
+<br>
+void BAR(int depth, int err_depth, int offset) {<br>
+  uint64_t x16[2];<br>
+  uint64_t x32[4];<br>
+  USE2(&x16, &x32);<br>
+  leaked_ptr = &x16[0];<br>
+  if (depth)<br>
+    FOO(depth - 1, err_depth, offset);<br>
+  if (err_depth == depth)<br>
+    x16[offset] = 0;  // maybe OOB<br>
+  if (err_depth == -depth)<br>
+    leaked_ptr[offset] = 0;  // maybe UAR<br>
+  USE(&x16);<br>
+}<br>
+<br>
+<br>
+int main(int argc, char **argv) {<br>
+  if (argc != 4) return -1;<br>
+  int depth = atoi(argv[1]);<br>
+  int err_depth = atoi(argv[2]);<br>
+  int offset = atoi(argv[3]);<br>
+  FOO(depth, err_depth, offset);<br>
+  return 0;<br>
+}<br>
+<br>
+// R321: HWAddressSanitizer: tag-mismatch<br>
+// R321-NEXT: WRITE of size 8<br>
+// R321-NEXT: in BAR<br>
+// R321-NEXT: in FOO<br>
+// R321-NEXT: in main<br>
+// R321: is located in stack of thread T0<br>
<br>
Added: compiler-rt/trunk/test/hwasan/<wbr>TestCases/stack-history-<wbr>length.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/stack-history-length.c?rev=342921&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/compiler-rt/trunk/<wbr>test/hwasan/TestCases/stack-<wbr>history-length.c?rev=342921&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- compiler-rt/trunk/test/hwasan/<wbr>TestCases/stack-history-<wbr>length.c (added)<br>
+++ compiler-rt/trunk/test/hwasan/<wbr>TestCases/stack-history-<wbr>length.c Mon Sep 24 14:38:42 2018<br>
@@ -0,0 +1,36 @@<br>
+// RUN: %clang_hwasan -O1 -DX=2046 %s -o %t.2046<br>
+// RUN: %clang_hwasan -O1 -DX=2047 %s -o %t.2047<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=2048 not %run %t.2046 2>&1 | FileCheck %s --check-prefix=YES<br>
+// RUN: %env_hwasan_opts=stack_<wbr>history_size=2048 not %run %t.2047 2>&1 | FileCheck %s --check-prefix=NO<br>
+<br>
+// REQUIRES: stable-runtime<br>
+<br>
+#include <stdlib.h><br>
+<br>
+void USE(void *x) { // pretend_to_do_something(void *x)<br>
+  __asm__ __volatile__("" : : "r" (x) : "memory");<br>
+}<br>
+<br>
+volatile int four = 4;<br>
+__attribute__((noinline)) void FUNC0() { int x[4]; USE(&x[0]); }<br>
+__attribute__((noinline)) void FUNC() { int x[4]; USE(&x[0]); }<br>
+__attribute__((noinline)) void OOB() { int x[4]; x[four] = 0; USE(&x[0]); }<br>
+<br>
+int main() {<br>
+  // FUNC0 is X+2's element of the ring buffer.<br>
+  // If runtime buffer size is less than it, FUNC0 record will be lost.<br>
+  FUNC0();<br>
+  for (int i = 0; i < X; ++i)<br>
+    FUNC();<br>
+  OOB();<br>
+}<br>
+<br>
+// YES: Previosly allocated frames<br>
+// YES: OOB<br>
+// YES: FUNC<br>
+// YES: FUNC0<br>
+<br>
+// NO: Previosly allocated frames<br>
+// NO: OOB<br>
+// NO: FUNC<br>
+// NO-NOT: FUNC0<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>