[prev in list] [next in list] [prev in thread] [next in thread] 

List:       llvm-commits
Subject:    [PATCH] D32382: [tsan] Track external tags in thread traces
From:       Phabricator via Phabricator via llvm-commits <llvm-commits () lists ! llvm ! org>
Date:       2017-04-30 20:48:31
Message-ID: 6efe4f8bd6748cf1619de23d5cf98bd8 () localhost ! localdomain
[Download RAW message or body]

This revision was automatically updated to reflect the committed changes.
Closed by commit rL301777: [tsan] Track external tags in thread traces (authored by kuba.brecka).

Changed prior to commit:
  https://reviews.llvm.org/D32382?vs=96627&id=97242#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D32382

Files:
  compiler-rt/trunk/lib/tsan/go/buildgo.sh
  compiler-rt/trunk/lib/tsan/rtl/tsan_external.cc
  compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
  compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
  compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc


["D32382.97242.patch" (text/x-patch)]

Index: compiler-rt/trunk/lib/tsan/go/buildgo.sh
===================================================================
--- compiler-rt/trunk/lib/tsan/go/buildgo.sh
+++ compiler-rt/trunk/lib/tsan/go/buildgo.sh
@@ -5,6 +5,7 @@
 SRCS="
 	tsan_go.cc
 	../rtl/tsan_clock.cc
+	../rtl/tsan_external.cc
 	../rtl/tsan_flags.cc
 	../rtl/tsan_interface_atomic.cc
 	../rtl/tsan_md5.cc
Index: compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
===================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_report.cc
@@ -164,7 +164,7 @@
   char thrbuf[kThreadBufSize];
   Printf("%s", d.Access());
   const char *object_type = GetObjectTypeFromTag(mop->external_tag);
-  if (!object_type) {
+  if (mop->external_tag == kExternalTagNone || !object_type) {
     Printf("  %s of size %d at %p by %s",
            MopDesc(first, mop->write, mop->atomic), mop->size,
            (void *)mop->addr, thread_name(thrbuf, mop->tid));
Index: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
===================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
@@ -411,7 +411,6 @@
   bool is_dead;
   bool is_freeing;
   bool is_vptr_access;
-  uptr external_tag;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -565,6 +564,16 @@
   }
 };
 
+enum ExternalTag : uptr {
+  kExternalTagNone = 0,
+  kExternalTagFirstUserAvailable = 1,
+  kExternalTagMax = 1024,
+  // Don't set kExternalTagMax over 65,536, since MBlock only stores tags
+  // as 16-bit values, see tsan_defs.h.
+};
+const char *GetObjectTypeFromTag(uptr tag);
+uptr TagFromShadowStackFrame(uptr pc);
+
 class ScopedReport {
  public:
   explicit ScopedReport(ReportType typ);
@@ -598,17 +607,34 @@
 
 ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
 void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
-                  MutexSet *mset);
+                  MutexSet *mset, uptr *tag = nullptr);
+
+// The stack could look like:
+//   <start> | <main> | <foo> | tag | <bar>
+// This will extract the tag and keep:
+//   <start> | <main> | <foo> | <bar>
+template<typename StackTraceTy>
+void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) {
+  if (stack->size < 2) return;
+  uptr possible_tag_pc = stack->trace[stack->size - 2];
+  uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc);
+  if (possible_tag == kExternalTagNone) return;
+  stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1];
+  stack->size -= 1;
+  if (tag) *tag = possible_tag;
+}
 
 template<typename StackTraceTy>
-void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,
+                        uptr *tag = nullptr) {
   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);
+  ExtractTagFromStack(stack, tag);
 }
 
 
@@ -646,8 +672,6 @@
 bool IsExpectedReport(uptr addr, uptr size);
 void PrintMatchedBenignRaces();
 
-const char *GetObjectTypeFromTag(uptr tag);
-
 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
 # define DPrintf Printf
 #else
Index: compiler-rt/trunk/lib/tsan/rtl/tsan_external.cc
===================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_external.cc
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_external.cc
@@ -17,38 +17,49 @@
 
 #define CALLERPC ((uptr)__builtin_return_address(0))
 
-const uptr kMaxTag = 128;  // Limited to 65,536, since MBlock only stores tags
-                           // as 16-bit values, see tsan_defs.h.
-
-const char *registered_tags[kMaxTag];
-static atomic_uint32_t used_tags{1};  // Tag 0 means "no tag". NOLINT
+const char *registered_tags[kExternalTagMax];
+static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable};  // NOLINT.
 
 const char *GetObjectTypeFromTag(uptr tag) {
   if (tag == 0) return nullptr;
   // Invalid/corrupted tag?  Better return NULL and let the caller deal with it.
   if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr;
   return registered_tags[tag];
 }
 
+void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) {
+  FuncEntry(thr, (uptr)&registered_tags[tag]);
+}
+
+uptr TagFromShadowStackFrame(uptr pc) {
+  uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
+  void *pc_ptr = (void *)pc;
+  if (pc_ptr < &registered_tags[0] || pc_ptr >= &registered_tags[tag_count])
+    return 0;
+  return (const char **)pc_ptr - &registered_tags[0];
+}
+
+#if !SANITIZER_GO
+
 typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int);
 void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) {
   CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
   ThreadState *thr = cur_thread();
-  thr->external_tag = (uptr)tag;
   if (caller_pc) FuncEntry(thr, (uptr)caller_pc);
+  InsertShadowStackFrameForTag(thr, (uptr)tag);
   bool in_ignored_lib;
   if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) {
     access(thr, CALLERPC, (uptr)addr, kSizeLog1);
   }
+  FuncExit(thr);
   if (caller_pc) FuncExit(thr);
-  thr->external_tag = 0;
 }
 
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void *__tsan_external_register_tag(const char *object_type) {
   uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed);
-  CHECK_LT(new_tag, kMaxTag);
+  CHECK_LT(new_tag, kExternalTagMax);
   registered_tags[new_tag] = internal_strdup(object_type);
   return (void *)new_tag;
 }
@@ -78,4 +89,6 @@
 }
 }  // extern "C"
 
+#endif  // !SANITIZER_GO
+
 }  // namespace __tsan
Index: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
===================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_report.cc
@@ -377,7 +377,7 @@
 }
 
 void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
-                  MutexSet *mset) {
+                  MutexSet *mset, uptr *tag) {
   // 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.
@@ -436,6 +436,7 @@
     return;
   pos++;
   stk->Init(&stack[0], pos);
+  ExtractTagFromStack(stk, tag);
 }
 
 static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
@@ -625,16 +626,15 @@
     typ = ReportTypeVptrRace;
   else if (freed)
     typ = ReportTypeUseAfterFree;
-  else if (thr->external_tag > 0)
-    typ = ReportTypeExternalRace;
 
   if (IsFiredSuppression(ctx, typ, addr))
     return;
 
   const uptr kMop = 2;
   VarSizeStackTrace traces[kMop];
+  uptr tags[kMop] = {kExternalTagNone};
   const uptr toppc = TraceTopPC(thr);
-  ObtainCurrentStack(thr, toppc, &traces[0]);
+  ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]);
   if (IsFiredSuppression(ctx, typ, traces[0]))
     return;
 
@@ -644,18 +644,22 @@
   MutexSet *mset2 = new(&mset_buffer[0]) MutexSet();
 
   Shadow s2(thr->racy_state[1]);
-  RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2);
+  RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2, &tags[1]);
   if (IsFiredSuppression(ctx, typ, traces[1]))
     return;
 
   if (HandleRacyStacks(thr, traces, addr_min, addr_max))
     return;
 
+  // If any of the two accesses has a tag, treat this as an "external" race.
+  if (tags[0] != kExternalTagNone || tags[1] != kExternalTagNone)
+    typ = ReportTypeExternalRace;
+
   ThreadRegistryLock l0(ctx->thread_registry);
   ScopedReport rep(typ);
   for (uptr i = 0; i < kMop; i++) {
     Shadow s(thr->racy_state[i]);
-    rep.AddMemoryAccess(addr, thr->external_tag, s, traces[i],
+    rep.AddMemoryAccess(addr, tags[i], s, traces[i],
                         i == 0 ? &thr->mset : mset2);
   }
 

[Attachment #4 (text/plain)]

_______________________________________________
llvm-commits mailing list
llvm-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic