[tsan] Replace mem intrinsics with calls to interceptors
authorVitaly Buka <vitalybuka@google.com>
Sun, 4 Sep 2022 05:24:33 +0000 (22:24 -0700)
committerVitaly Buka <vitalybuka@google.com>
Tue, 6 Sep 2022 20:09:31 +0000 (13:09 -0700)
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

compiler-rt/lib/tsan/rtl/tsan.syms.extra
compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
compiler-rt/lib/tsan/rtl/tsan_interface.h
compiler-rt/test/tsan/Linux/double_race.cpp
compiler-rt/test/tsan/inlined_memcpy_race.cpp
compiler-rt/test/tsan/inlined_memcpy_race2.cpp
compiler-rt/test/tsan/memcmp_race.cpp
compiler-rt/test/tsan/memcpy_race.cpp
llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
llvm/test/Instrumentation/ThreadSanitizer/tsan_basic.ll

index 4838bb0..a5bd171 100644 (file)
@@ -9,6 +9,9 @@ __tsan_java*
 __tsan_unaligned*
 __tsan_release
 __tsan_acquire
+__tsan_memcpy
+__tsan_memmove
+__tsan_memset
 __tsan_mutex_create
 __tsan_mutex_destroy
 __tsan_mutex_pre_lock
index 17f6b1f..f2eaaf4 100644 (file)
@@ -3029,7 +3029,9 @@ void InitializeInterceptors() {
 constexpr u32 kBarrierThreadBits = 10;
 constexpr u32 kBarrierThreads = 1 << kBarrierThreadBits;
 
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_init(
+extern "C" {
+
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_init(
     atomic_uint32_t *barrier, u32 num_threads) {
   if (num_threads >= kBarrierThreads) {
     Printf("barrier_init: count is too large (%d)\n", num_threads);
@@ -3044,7 +3046,7 @@ static u32 barrier_epoch(u32 value) {
   return (value >> kBarrierThreadBits) / (value & (kBarrierThreads - 1));
 }
 
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
     atomic_uint32_t *barrier) {
   u32 old = atomic_fetch_add(barrier, kBarrierThreads, memory_order_relaxed);
   u32 old_epoch = barrier_epoch(old);
@@ -3059,3 +3061,23 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
     FutexWait(barrier, cur);
   }
 }
+
+void *__tsan_memcpy(void *dst, const void *src, uptr size) {
+  void *ctx;
+#if PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE
+  COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size);
+#else
+  COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
+#endif
+}
+
+void *__tsan_memset(void *dst, int c, uptr size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, c, size);
+}
+
+void *__tsan_memmove(void *dst, const void *src, uptr size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
+}
+}
index 711f064..5b9d664 100644 (file)
@@ -72,6 +72,13 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_vptr_read(void **vptr_p);
 SANITIZER_INTERFACE_ATTRIBUTE
 void __tsan_vptr_update(void **vptr_p, void *new_val);
 
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_memcpy(void *dest, const void *src, uptr count);
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_memset(void *dest, int ch, uptr count);
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_memmove(void *dest, const void *src, uptr count);
+
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc);
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
 
index 81d4ca0..f02c3c2 100644 (file)
@@ -44,7 +44,7 @@ int main() {
 
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK:   Write of size 8 at {{.*}} by thread T1:
-// CHECK:     #0 memset
+// CHECK:     #0 {{.*}}memset
 // CHECK:     #{{[12]}} Thread
 // CHECK-NOT: bad PC passed to __tsan_symbolize_external
 // CHECK-NOT: __sanitizer_report_error_summary
index eb252e5..5f17cfb 100644 (file)
@@ -29,8 +29,8 @@ int main() {
 }
 
 // CHECK: WARNING: ThreadSanitizer: data race
-// CHECK:   #0 memset
+// CHECK:   #0 {{.*}}memset
 // CHECK:   #{{[12]}} MemSetThread
 // CHECK:  Previous write
-// CHECK:   #0 {{(memcpy|memmove)}}
+// CHECK:   #0 {{.*mem(cpy|move)}}
 // CHECK:   #{{[12]}} MemCpyThread
index 75b92ef..cd4bb58 100644 (file)
@@ -30,8 +30,8 @@ int main() {
 }
 
 // CHECK: WARNING: ThreadSanitizer: data race
-// CHECK:   #0 memset
+// CHECK:   #0 {{.*}}memset
 // CHECK:   #{{[12]}} MemSetThread
 // CHECK:  Previous write
-// CHECK:   #0 {{(memcpy|memmove)}}
+// CHECK:   #0 {{.*mem(cpy|move)}}
 // CHECK:   #{{[12]}} MemMoveThread
index 911c335..4c9ee4a 100644 (file)
@@ -35,8 +35,8 @@ int main() {
 // CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK:   Write of size 3 at [[ADDR]] by thread T2:
-// CHECK:     #0 {{(memcpy|memmove)}}
+// CHECK:     #0 {{.*mem(cpy|move)}}
 // CHECK:     #{{[12]}} Thread2
 // CHECK:   Previous read of size 1 at [[ADDR]] by thread T1:
-// CHECK:     #0 memcmp
+// CHECK:     #0 {{.*}}memcmp
 // CHECK:     #{{[12]}} Thread1
index cfdec7c..aed047a 100644 (file)
@@ -36,8 +36,8 @@ int main() {
 // CHECK: addr2=[[ADDR2:0x[0-9,a-f]+]]
 // CHECK: WARNING: ThreadSanitizer: data race
 // CHECK:   Write of size 4 at [[ADDR1]] by thread T2:
-// CHECK:     #0 {{(memcpy|memmove)}}
+// CHECK:     #0 {{.*mem(cpy|move)}}
 // CHECK:     #{{[12]}} Thread2
 // CHECK:   Previous write of size 1 at [[ADDR2]] by thread T1:
-// CHECK:     #0 {{(memcpy|memmove)}}
+// CHECK:     #0 {{.*mem(cpy|move)}}
 // CHECK:     #{{[12]}} Thread1
index 863b085..0cda196 100644 (file)
@@ -341,13 +341,13 @@ void ThreadSanitizer::initialize(Module &M) {
   }
 
   MemmoveFn =
-      M.getOrInsertFunction("memmove", Attr, IRB.getInt8PtrTy(),
+      M.getOrInsertFunction("__tsan_memmove", Attr, IRB.getInt8PtrTy(),
                             IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy);
   MemcpyFn =
-      M.getOrInsertFunction("memcpy", Attr, IRB.getInt8PtrTy(),
+      M.getOrInsertFunction("__tsan_memcpy", Attr, IRB.getInt8PtrTy(),
                             IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy);
   MemsetFn =
-      M.getOrInsertFunction("memset", Attr, IRB.getInt8PtrTy(),
+      M.getOrInsertFunction("__tsan_memset", Attr, IRB.getInt8PtrTy(),
                             IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy);
 }
 
index 9a1ef9e..d59efd9 100644 (file)
@@ -35,7 +35,7 @@ entry:
     tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
     ret void
 ; CHECK: define void @MemCpyTest
-; CHECK: call i8* @memcpy
+; CHECK: call i8* @__tsan_memcpy
 ; CHECK: ret void
 }
 
@@ -44,7 +44,7 @@ entry:
     tail call void @llvm.memcpy.inline.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
     ret void
 ; CHECK: define void @MemCpyInlineTest
-; CHECK: call i8* @memcpy
+; CHECK: call i8* @__tsan_memcpy
 ; CHECK: ret void
 }
 
@@ -53,7 +53,7 @@ entry:
     tail call void @llvm.memmove.p0i8.p0i8.i64(i8* align 4 %x, i8* align 4 %y, i64 16, i1 false)
     ret void
 ; CHECK: define void @MemMoveTest
-; CHECK: call i8* @memmove
+; CHECK: call i8* @__tsan_memmove
 ; CHECK: ret void
 }
 
@@ -62,7 +62,7 @@ entry:
     tail call void @llvm.memset.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
     ret void
 ; CHECK: define void @MemSetTest
-; CHECK: call i8* @memset
+; CHECK: call i8* @__tsan_memset
 ; CHECK: ret void
 }
 
@@ -71,7 +71,7 @@ entry:
     tail call void @llvm.memset.inline.p0i8.i64(i8* align 4 %x, i8 77, i64 16, i1 false)
     ret void
 ; CHECK: define void @MemSetInlineTest
-; CHECK: call i8* @memset
+; CHECK: call i8* @__tsan_memset
 ; CHECK: ret void
 }