summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler-rt/lib/tsan/go/buildgo.sh1
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_external.cc29
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_report.cc2
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl.h34
-rw-r--r--compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc16
5 files changed, 62 insertions, 20 deletions
diff --git a/compiler-rt/lib/tsan/go/buildgo.sh b/compiler-rt/lib/tsan/go/buildgo.sh
index 42d479064c4..59176809eae 100755
--- a/compiler-rt/lib/tsan/go/buildgo.sh
+++ b/compiler-rt/lib/tsan/go/buildgo.sh
@@ -5,6 +5,7 @@ set -e
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
diff --git a/compiler-rt/lib/tsan/rtl/tsan_external.cc b/compiler-rt/lib/tsan/rtl/tsan_external.cc
index 88468e40665..2d32b6dac75 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_external.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_external.cc
@@ -17,11 +17,8 @@ namespace __tsan {
#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;
@@ -30,25 +27,39 @@ const char *GetObjectTypeFromTag(uptr tag) {
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 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
}
} // extern "C"
+#endif // !SANITIZER_GO
+
} // namespace __tsan
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc
index af5fe61761d..b188af2a0d4 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_report.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc
@@ -164,7 +164,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
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));
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 09c97a3a4f3..cc60eb6db96 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -411,7 +411,6 @@ struct ThreadState {
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 @@ struct ScopedIgnoreInterceptors {
}
};
+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,10 +607,26 @@ class ScopedReport {
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) {
@@ -609,6 +634,7 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
size = kStackTraceMax - !!toppc;
}
stack->Init(&thr->shadow_stack[start], size, toppc);
+ ExtractTagFromStack(stack, tag);
}
@@ -646,8 +672,6 @@ bool IsFiredSuppression(Context *ctx, ReportType type, StackTrace trace);
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
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
index 5cd93a184ce..055029b91f5 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
@@ -377,7 +377,7 @@ const ReportDesc *ScopedReport::GetReport() const {
}
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 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
return;
pos++;
stk->Init(&stack[0], pos);
+ ExtractTagFromStack(stk, tag);
}
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
@@ -625,16 +626,15 @@ void ReportRace(ThreadState *thr) {
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 @@ void ReportRace(ThreadState *thr) {
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);
}
OpenPOWER on IntegriCloud