Skip to content

Commit 0f7e949

Browse files
committed
tsan: rely on AnnotateRWLockCreateStatic to detect linker-initialized mutexes
The new annotation was added a while ago, but was not actually used. Use the annotation to detect linker-initialized mutexes instead of the broken IsGlobalVar which has both false positives and false negatives. Remove IsGlobalVar mess. llvm-svn: 271663
1 parent a4a99ad commit 0f7e949

File tree

6 files changed

+89
-70
lines changed

6 files changed

+89
-70
lines changed

compiler-rt/lib/tsan/rtl/tsan_platform.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -757,10 +757,6 @@ void CheckAndProtect();
757757
void InitializeShadowMemoryPlatform();
758758
void FlushShadowMemory();
759759
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
760-
761-
// Says whether the addr relates to a global var.
762-
// Guesses with high probability, may yield both false positives and negatives.
763-
bool IsGlobalVar(uptr addr);
764760
int ExtractResolvFDs(void *state, int *fds, int nfd);
765761
int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
766762

compiler-rt/lib/tsan/rtl/tsan_platform_linux.cc

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ void *__libc_stack_end = 0;
6969

7070
namespace __tsan {
7171

72-
static uptr g_data_start;
73-
static uptr g_data_end;
74-
7572
#ifdef TSAN_RUNTIME_VMA
7673
// Runtime detected VMA size.
7774
uptr vmaSize;
@@ -204,46 +201,6 @@ void InitializeShadowMemoryPlatform() {
204201
MapRodata();
205202
}
206203

207-
static void InitDataSeg() {
208-
MemoryMappingLayout proc_maps(true);
209-
uptr start, end, offset;
210-
char name[128];
211-
#if SANITIZER_FREEBSD
212-
// On FreeBSD BSS is usually the last block allocated within the
213-
// low range and heap is the last block allocated within the range
214-
// 0x800000000-0x8ffffffff.
215-
while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
216-
/*protection*/ 0)) {
217-
DPrintf("%p-%p %p %s\n", start, end, offset, name);
218-
if ((start & 0xffff00000000ULL) == 0 && (end & 0xffff00000000ULL) == 0 &&
219-
name[0] == '\0') {
220-
g_data_start = start;
221-
g_data_end = end;
222-
}
223-
}
224-
#else
225-
bool prev_is_data = false;
226-
while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
227-
/*protection*/ 0)) {
228-
DPrintf("%p-%p %p %s\n", start, end, offset, name);
229-
bool is_data = offset != 0 && name[0] != 0;
230-
// BSS may get merged with [heap] in /proc/self/maps. This is not very
231-
// reliable.
232-
bool is_bss = offset == 0 &&
233-
(name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
234-
if (g_data_start == 0 && is_data)
235-
g_data_start = start;
236-
if (is_bss)
237-
g_data_end = end;
238-
prev_is_data = is_data;
239-
}
240-
#endif
241-
DPrintf("guessed data_start=%p data_end=%p\n", g_data_start, g_data_end);
242-
CHECK_LT(g_data_start, g_data_end);
243-
CHECK_GE((uptr)&g_data_start, g_data_start);
244-
CHECK_LT((uptr)&g_data_start, g_data_end);
245-
}
246-
247204
#endif // #ifndef SANITIZER_GO
248205

249206
void InitializePlatformEarly() {
@@ -315,14 +272,9 @@ void InitializePlatform() {
315272
#ifndef SANITIZER_GO
316273
CheckAndProtect();
317274
InitTlsSize();
318-
InitDataSeg();
319275
#endif
320276
}
321277

322-
bool IsGlobalVar(uptr addr) {
323-
return g_data_start && addr >= g_data_start && addr < g_data_end;
324-
}
325-
326278
#ifndef SANITIZER_GO
327279
// Extract file descriptors passed to glibc internal __res_iclose function.
328280
// This is required to properly "close" the fds, because we do not see internal

compiler-rt/lib/tsan/rtl/tsan_platform_mac.cc

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,6 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
189189
}
190190
#endif
191191

192-
bool IsGlobalVar(uptr addr) {
193-
return false;
194-
}
195-
196192
} // namespace __tsan
197193

198194
#endif // SANITIZER_MAC

compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,14 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
8484
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
8585
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
8686
StatInc(thr, StatMutexDestroy);
87-
#ifndef SANITIZER_GO
88-
// Global mutexes not marked as LINKER_INITIALIZED
89-
// cause tons of not interesting reports, so just ignore it.
90-
if (IsGlobalVar(addr))
91-
return;
92-
#endif
93-
if (IsAppMem(addr)) {
94-
CHECK(!thr->is_freeing);
95-
thr->is_freeing = true;
96-
MemoryWrite(thr, pc, addr, kSizeLog1);
97-
thr->is_freeing = false;
98-
}
9987
SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
10088
if (s == 0)
10189
return;
90+
if (s->is_linker_init) {
91+
// Destroy is no-op for linker-initialized mutexes.
92+
s->mtx.Unlock();
93+
return;
94+
}
10295
if (common_flags()->detect_deadlocks) {
10396
Callback cb(thr, pc);
10497
ctx->dd->MutexDestroy(&cb, &s->dd);
@@ -128,15 +121,23 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
128121
rep.AddStack(trace, true);
129122
rep.AddLocation(addr, 1);
130123
OutputReport(thr, rep);
131-
}
132-
if (unlock_locked) {
124+
133125
SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr);
134126
if (s != 0) {
135127
s->Reset(thr->proc());
136128
s->mtx.Unlock();
137129
}
138130
}
139131
thr->mset.Remove(mid);
132+
// Imitate a memory write to catch unlock-destroy races.
133+
// Do this outside of sync mutex, because it can report a race which locks
134+
// sync mutexes.
135+
if (IsAppMem(addr)) {
136+
CHECK(!thr->is_freeing);
137+
thr->is_freeing = true;
138+
MemoryWrite(thr, pc, addr, kSizeLog1);
139+
thr->is_freeing = false;
140+
}
140141
// s will be destroyed and freed in MetaMap::FreeBlock.
141142
}
142143

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2+
#include "test.h"
3+
4+
// Test that a linker-initialized mutex can be created/destroyed while in use.
5+
6+
// Stub for testing, just invokes annotations.
7+
// Meant to be synchronized externally with test barrier.
8+
class Mutex {
9+
public:
10+
void Create(bool linker_initialized = false) {
11+
if (linker_initialized)
12+
ANNOTATE_RWLOCK_CREATE_STATIC(&state_);
13+
else
14+
ANNOTATE_RWLOCK_CREATE(&state_);
15+
}
16+
17+
void Destroy() {
18+
ANNOTATE_RWLOCK_DESTROY(&state_);
19+
}
20+
21+
void Lock() {
22+
ANNOTATE_RWLOCK_ACQUIRED(&state_, true);
23+
}
24+
25+
void Unlock() {
26+
ANNOTATE_RWLOCK_RELEASED(&state_, true);
27+
}
28+
29+
private:
30+
long long state_;
31+
};
32+
33+
int main() {
34+
Mutex m;
35+
36+
m.Lock();
37+
m.Create(true);
38+
m.Unlock();
39+
40+
m.Lock();
41+
m.Destroy();
42+
m.Unlock();
43+
44+
fprintf(stderr, "DONE\n");
45+
return 0;
46+
}
47+
48+
// CHECK-NOT: WARNING: ThreadSanitizer:
49+
// CHECK: DONE

compiler-rt/test/tsan/test.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,28 @@ const int kPCInc = 8;
7777
#else
7878
const int kPCInc = 1;
7979
#endif
80+
81+
#ifdef __cplusplus
82+
extern "C" {
83+
#endif
84+
85+
void AnnotateRWLockCreate(const char *f, int l, void *m);
86+
void AnnotateRWLockCreateStatic(const char *f, int l, void *m);
87+
void AnnotateRWLockDestroy(const char *f, int l, void *m);
88+
void AnnotateRWLockAcquired(const char *f, int l, void *m, long is_w);
89+
void AnnotateRWLockReleased(const char *f, int l, void *m, long is_w);
90+
91+
#ifdef __cplusplus
92+
}
93+
#endif
94+
95+
#define ANNOTATE_RWLOCK_CREATE(m) \
96+
AnnotateRWLockCreate(__FILE__, __LINE__, m)
97+
#define ANNOTATE_RWLOCK_CREATE_STATIC(m) \
98+
AnnotateRWLockCreateStatic(__FILE__, __LINE__, m)
99+
#define ANNOTATE_RWLOCK_DESTROY(m) \
100+
AnnotateRWLockDestroy(__FILE__, __LINE__, m)
101+
#define ANNOTATE_RWLOCK_ACQUIRED(m, is_w) \
102+
AnnotateRWLockAcquired(__FILE__, __LINE__, m, is_w)
103+
#define ANNOTATE_RWLOCK_RELEASED(m, is_w) \
104+
AnnotateRWLockReleased(__FILE__, __LINE__, m, is_w)

0 commit comments

Comments
 (0)