Skip to content

Commit b4257d3

Browse files
committed
[tsan] Replace mem intrinsics with calls to interceptors
After https://reviews.llvm.org/rG463aa814182a23 tsan replaces llvm intrinsics with calls to glibc functions. However this approach is fragile, as slight changes in pipeline can return llvm intrinsics back. In particular InstCombine can do that. Msan/Asan already declare own version of these memory functions for the similar purpose. KCSAN, or anything that uses something else than compiler-rt, needs to implement this callbacks. Reviewed By: melver Differential Revision: https://reviews.llvm.org/D133268
1 parent 4a0b18c commit b4257d3

File tree

10 files changed

+51
-19
lines changed

10 files changed

+51
-19
lines changed

compiler-rt/lib/tsan/rtl/tsan.syms.extra

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ __tsan_java*
99
__tsan_unaligned*
1010
__tsan_release
1111
__tsan_acquire
12+
__tsan_memcpy
13+
__tsan_memmove
14+
__tsan_memset
1215
__tsan_mutex_create
1316
__tsan_mutex_destroy
1417
__tsan_mutex_pre_lock

compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,7 +3029,9 @@ void InitializeInterceptors() {
30293029
constexpr u32 kBarrierThreadBits = 10;
30303030
constexpr u32 kBarrierThreads = 1 << kBarrierThreadBits;
30313031

3032-
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_init(
3032+
extern "C" {
3033+
3034+
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_init(
30333035
atomic_uint32_t *barrier, u32 num_threads) {
30343036
if (num_threads >= kBarrierThreads) {
30353037
Printf("barrier_init: count is too large (%d)\n", num_threads);
@@ -3044,7 +3046,7 @@ static u32 barrier_epoch(u32 value) {
30443046
return (value >> kBarrierThreadBits) / (value & (kBarrierThreads - 1));
30453047
}
30463048

3047-
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
3049+
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
30483050
atomic_uint32_t *barrier) {
30493051
u32 old = atomic_fetch_add(barrier, kBarrierThreads, memory_order_relaxed);
30503052
u32 old_epoch = barrier_epoch(old);
@@ -3059,3 +3061,23 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
30593061
FutexWait(barrier, cur);
30603062
}
30613063
}
3064+
3065+
void *__tsan_memcpy(void *dst, const void *src, uptr size) {
3066+
void *ctx;
3067+
#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
3068+
COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size);
3069+
#else
3070+
COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
3071+
#endif
3072+
}
3073+
3074+
void *__tsan_memset(void *dst, int c, uptr size) {
3075+
void *ctx;
3076+
COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, c, size);
3077+
}
3078+
3079+
void *__tsan_memmove(void *dst, const void *src, uptr size) {
3080+
void *ctx;
3081+
COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
3082+
}
3083+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_vptr_read(void **vptr_p);
7272
SANITIZER_INTERFACE_ATTRIBUTE
7373
void __tsan_vptr_update(void **vptr_p, void *new_val);
7474

75+
SANITIZER_INTERFACE_ATTRIBUTE
76+
void *__tsan_memcpy(void *dest, const void *src, uptr count);
77+
SANITIZER_INTERFACE_ATTRIBUTE
78+
void *__tsan_memset(void *dest, int ch, uptr count);
79+
SANITIZER_INTERFACE_ATTRIBUTE
80+
void *__tsan_memmove(void *dest, const void *src, uptr count);
81+
7582
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc);
7683
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
7784

compiler-rt/test/tsan/Linux/double_race.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ int main() {
4444

4545
// CHECK: WARNING: ThreadSanitizer: data race
4646
// CHECK: Write of size 8 at {{.*}} by thread T1:
47-
// CHECK: #0 memset
47+
// CHECK: #0 {{.*}}memset
4848
// CHECK: #{{[12]}} Thread
4949
// CHECK-NOT: bad PC passed to __tsan_symbolize_external
5050
// CHECK-NOT: __sanitizer_report_error_summary

compiler-rt/test/tsan/inlined_memcpy_race.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ int main() {
2929
}
3030

3131
// CHECK: WARNING: ThreadSanitizer: data race
32-
// CHECK: #0 memset
32+
// CHECK: #0 {{.*}}memset
3333
// CHECK: #{{[12]}} MemSetThread
3434
// CHECK: Previous write
35-
// CHECK: #0 {{(memcpy|memmove)}}
35+
// CHECK: #0 {{.*mem(cpy|move)}}
3636
// CHECK: #{{[12]}} MemCpyThread

compiler-rt/test/tsan/inlined_memcpy_race2.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ int main() {
3030
}
3131

3232
// CHECK: WARNING: ThreadSanitizer: data race
33-
// CHECK: #0 memset
33+
// CHECK: #0 {{.*}}memset
3434
// CHECK: #{{[12]}} MemSetThread
3535
// CHECK: Previous write
36-
// CHECK: #0 {{(memcpy|memmove)}}
36+
// CHECK: #0 {{.*mem(cpy|move)}}
3737
// CHECK: #{{[12]}} MemMoveThread

compiler-rt/test/tsan/memcmp_race.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ int main() {
3535
// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
3636
// CHECK: WARNING: ThreadSanitizer: data race
3737
// CHECK: Write of size 3 at [[ADDR]] by thread T2:
38-
// CHECK: #0 {{(memcpy|memmove)}}
38+
// CHECK: #0 {{.*mem(cpy|move)}}
3939
// CHECK: #{{[12]}} Thread2
4040
// CHECK: Previous read of size 1 at [[ADDR]] by thread T1:
41-
// CHECK: #0 memcmp
41+
// CHECK: #0 {{.*}}memcmp
4242
// CHECK: #{{[12]}} Thread1

compiler-rt/test/tsan/memcpy_race.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ int main() {
3636
// CHECK: addr2=[[ADDR2:0x[0-9,a-f]+]]
3737
// CHECK: WARNING: ThreadSanitizer: data race
3838
// CHECK: Write of size 4 at [[ADDR1]] by thread T2:
39-
// CHECK: #0 {{(memcpy|memmove)}}
39+
// CHECK: #0 {{.*mem(cpy|move)}}
4040
// CHECK: #{{[12]}} Thread2
4141
// CHECK: Previous write of size 1 at [[ADDR2]] by thread T1:
42-
// CHECK: #0 {{(memcpy|memmove)}}
42+
// CHECK: #0 {{.*mem(cpy|move)}}
4343
// CHECK: #{{[12]}} Thread1

llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,13 +341,13 @@ void ThreadSanitizer::initialize(Module &M) {
341341
}
342342

343343
MemmoveFn =
344-
M.getOrInsertFunction("memmove", Attr, IRB.getInt8PtrTy(),
344+
M.getOrInsertFunction("__tsan_memmove", Attr, IRB.getInt8PtrTy(),
345345
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy);
346346
MemcpyFn =
347-
M.getOrInsertFunction("memcpy", Attr, IRB.getInt8PtrTy(),
347+
M.getOrInsertFunction("__tsan_memcpy", Attr, IRB.getInt8PtrTy(),
348348
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy);
349349
MemsetFn =
350-
M.getOrInsertFunction("memset", Attr, IRB.getInt8PtrTy(),
350+
M.getOrInsertFunction("__tsan_memset", Attr, IRB.getInt8PtrTy(),
351351
IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy);
352352
}
353353

llvm/test/Instrumentation/ThreadSanitizer/tsan_basic.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ entry:
3535
tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
3636
ret void
3737
; CHECK: define void @MemCpyTest
38-
; CHECK: call i8* @memcpy
38+
; CHECK: call i8* @__tsan_memcpy
3939
; CHECK: ret void
4040
}
4141

@@ -44,7 +44,7 @@ entry:
4444
tail call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
4545
ret void
4646
; CHECK: define void @MemCpyInlineTest
47-
; CHECK: call i8* @memcpy
47+
; CHECK: call i8* @__tsan_memcpy
4848
; CHECK: ret void
4949
}
5050

@@ -53,7 +53,7 @@ entry:
5353
tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
5454
ret void
5555
; CHECK: define void @MemMoveTest
56-
; CHECK: call i8* @memmove
56+
; CHECK: call i8* @__tsan_memmove
5757
; CHECK: ret void
5858
}
5959

@@ -62,7 +62,7 @@ entry:
6262
tail call void @llvm.memset.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
6363
ret void
6464
; CHECK: define void @MemSetTest
65-
; CHECK: call i8* @memset
65+
; CHECK: call i8* @__tsan_memset
6666
; CHECK: ret void
6767
}
6868

@@ -71,7 +71,7 @@ entry:
7171
tail call void @llvm.memset.inline.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
7272
ret void
7373
; CHECK: define void @MemSetInlineTest
74-
; CHECK: call i8* @memset
74+
; CHECK: call i8* @__tsan_memset
7575
; CHECK: ret void
7676
}
7777

0 commit comments

Comments
 (0)