[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)®istered_tags[tag]);
+}
+
+uptr TagFromShadowStackFrame(uptr pc) {
+ uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
+ void *pc_ptr = (void *)pc;
+ if (pc_ptr < ®istered_tags[0] || pc_ptr >= ®istered_tags[tag_count])
+ return 0;
+ return (const char **)pc_ptr - ®istered_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