llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Naveen Seth Hanig (naveen-seth)

<details>
<summary>Changes</summary>

This introduces a lightweight ThreadSanitizer submode that focuses exclusively 
on lock correctness validation, enabled by `-fsanitize=thread-deadlock`.

The motivation behind this is to allow lock-order inversion and mutex misuse 
detection without enabling data-race detection.
This is useful for:
- Programs that exceed regular TSan's shadow memory address space constraints
- Combining with other sanitizers incompatible with TSan because of the shadow 
memory mappings. (This works with MSan.)
- Platforms where regular TSan is not supported
- Users who are only interested in lock-correctness but not in data-races.

This is implemented as a separate standalone runtime, as the regular TSan 
runtime intertwines its lock tracking with SyncVar objects in shadow memory.
A follow up patch will remove the old tsan/dd, which was never wired to the 
compiler and is effectively unmaintained/dead code.

This follows the RFC:
https://discourse.llvm.org/t/rfc-add-update-tsan-submode-for-lock-correctness-validation-only/91319?u=naveen-seth

---

Patch is 55.39 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/212748.diff


25 Files Affected:

- (modified) clang/include/clang/Basic/Sanitizers.def (+3) 
- (modified) clang/include/clang/Driver/SanitizerArgs.h (+3) 
- (modified) clang/lib/CodeGen/BackendUtil.cpp (+9) 
- (modified) clang/lib/Driver/SanitizerArgs.cpp (+3-1) 
- (modified) clang/lib/Driver/ToolChains/CommonArgs.cpp (+4) 
- (modified) clang/lib/Driver/ToolChains/Linux.cpp (+1) 
- (modified) compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake (+1) 
- (modified) compiler-rt/cmake/config-ix.cmake (+9-1) 
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h (+3) 
- (added) compiler-rt/lib/tsan_deadlock/CMakeLists.txt (+76) 
- (added) compiler-rt/lib/tsan_deadlock/tsan_deadlock_interceptors.cpp (+398) 
- (added) compiler-rt/lib/tsan_deadlock/tsan_deadlock_interface.cpp (+36) 
- (added) compiler-rt/lib/tsan_deadlock/tsan_deadlock_rtl.cpp (+339) 
- (added) compiler-rt/lib/tsan_deadlock/tsan_deadlock_rtl.h (+102) 
- (added) compiler-rt/test/tsan_deadlock/CMakeLists.txt (+29) 
- (added) compiler-rt/test/tsan_deadlock/lit.cfg.py (+47) 
- (added) compiler-rt/test/tsan_deadlock/lit.site.cfg.py.in (+12) 
- (added) compiler-rt/test/tsan_deadlock/mutex_bad_unlock.cpp (+26) 
- (added) compiler-rt/test/tsan_deadlock/mutex_cycle2.cpp (+31) 
- (added) compiler-rt/test/tsan_deadlock/mutex_cycle_long.c (+44) 
- (added) compiler-rt/test/tsan_deadlock/mutex_destroy_locked.cpp (+20) 
- (added) compiler-rt/test/tsan_deadlock/mutex_destroy_locked2.cpp (+27) 
- (added) compiler-rt/test/tsan_deadlock/mutex_double_lock.cpp (+17) 
- (modified) llvm/include/llvm/Transforms/Instrumentation/ThreadSanitizer.h 
(+15-1) 
- (modified) llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp (+12-7) 


``````````diff
diff --git a/clang/include/clang/Basic/Sanitizers.def 
b/clang/include/clang/Basic/Sanitizers.def
index da85431625026..fcb43dc31fcdc 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -79,6 +79,9 @@ SANITIZER("type", Type)
 // ThreadSanitizer
 SANITIZER("thread", Thread)
 
+// DeadlockSanitizer (ThreadSanitizer, with only the deadlock detection.)
+SANITIZER("thread-deadlock", ThreadDeadlock)
+
 // Numerical stability sanitizer.
 SANITIZER("numerical", NumericalStability)
 
diff --git a/clang/include/clang/Driver/SanitizerArgs.h 
b/clang/include/clang/Driver/SanitizerArgs.h
index 6a01b3e36d44c..7b7f738d91131 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -104,6 +104,9 @@ class SanitizerArgs {
   }
   bool needsTysanRt() const { return Sanitizers.has(SanitizerKind::Type); }
   bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
+  bool needsDeadlockRt() const {
+    return Sanitizers.has(SanitizerKind::ThreadDeadlock);
+  }
   bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
   bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
   bool needsLsanRt() const {
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index 2b755fa916e55..ce9740554a348 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -741,6 +741,15 @@ static void addSanitizers(const Triple &TargetTriple,
       MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
     }
 
+    if (LangOpts.Sanitize.has(SanitizerKind::ThreadDeadlock)) {
+      MPM.addPass(ModuleThreadSanitizerPass());
+      MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass(
+          ThreadSanitizerOptions{/*InstrumentMemoryAccesses=*/false,
+                                 /*InstrumentAtomics=*/false,
+                                 /*InstrumentMemIntrinsics=*/false,
+                                 /*AlwaysInstrumentFuncEntryExit=*/true})));
+    }
+
     if (LangOpts.Sanitize.has(SanitizerKind::Type))
       MPM.addPass(TypeSanitizerPass());
 
diff --git a/clang/lib/Driver/SanitizerArgs.cpp 
b/clang/lib/Driver/SanitizerArgs.cpp
index c77ba78122a81..3c3bc84eacd3f 100644
--- a/clang/lib/Driver/SanitizerArgs.cpp
+++ b/clang/lib/Driver/SanitizerArgs.cpp
@@ -40,7 +40,8 @@ static const SanitizerMask NotAllowedWithExecuteOnly =
     SanitizerKind::Function | SanitizerKind::KCFI;
 static const SanitizerMask NeedsUnwindTables =
     SanitizerKind::Address | SanitizerKind::HWAddress | SanitizerKind::Type |
-    SanitizerKind::Thread | SanitizerKind::Memory | SanitizerKind::DataFlow |
+    SanitizerKind::Thread | SanitizerKind::ThreadDeadlock |
+    SanitizerKind::Memory | SanitizerKind::DataFlow |
     SanitizerKind::NumericalStability;
 static const SanitizerMask SupportsCoverage =
     SanitizerKind::Address | SanitizerKind::HWAddress |
@@ -707,6 +708,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
                          SanitizerKind::Memory | SanitizerKind::Leak |
                          SanitizerKind::Thread),
       std::make_pair(SanitizerKind::Thread, SanitizerKind::Memory),
+      std::make_pair(SanitizerKind::Thread, SanitizerKind::ThreadDeadlock),
       std::make_pair(SanitizerKind::Leak,
                      SanitizerKind::Thread | SanitizerKind::Memory),
       std::make_pair(SanitizerKind::KernelAddress,
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 08c06951cf220..d7acfacd17b05 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1655,6 +1655,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const 
ArgList &Args,
     }
     if (SanArgs.needsTsanRt())
       SharedRuntimes.push_back("tsan");
+    if (SanArgs.needsDeadlockRt())
+      SharedRuntimes.push_back("tsan_deadlock");
     if (SanArgs.needsTysanRt())
       SharedRuntimes.push_back("tysan");
     if (SanArgs.needsHwasanRt()) {
@@ -1729,6 +1731,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const 
ArgList &Args,
     if (SanArgs.linkCXXRuntimes())
       StaticRuntimes.push_back("tsan_cxx");
   }
+  if (!SanArgs.needsSharedRt() && SanArgs.needsDeadlockRt())
+    StaticRuntimes.push_back("tsan_deadlock");
   if (!SanArgs.needsSharedRt() && SanArgs.needsTysanRt())
     StaticRuntimes.push_back("tysan");
   if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp 
b/clang/lib/Driver/ToolChains/Linux.cpp
index 6dca14d8bf0a8..ab9257362cea1 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -1001,6 +1001,7 @@ Linux::getSupportedSanitizers(BoundArch BA,
   if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ ||
       IsLoongArch64 || IsRISCV64)
     Res |= SanitizerKind::Thread;
+  Res |= SanitizerKind::ThreadDeadlock;
   if (IsX86_64 || IsAArch64 || IsSystemZ || IsHexagon)
     Res |= SanitizerKind::Type;
   if (IsX86_64 || IsSystemZ || IsPowerPC64)
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake 
b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 9c9874d94a1f2..5eebb98cda68a 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -52,6 +52,7 @@ set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} 
${ARM64_32})
 set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64}
     ${S390X})
 set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${HEXAGON})
+set(ALL_TSAN_DEADLOCK_SUPPORTED_ARCH ${ALL_SANITIZER_COMMON_SUPPORTED_ARCH})
 
 if(ANDROID)
   set(OS_NAME "Android")
diff --git a/compiler-rt/cmake/config-ix.cmake 
b/compiler-rt/cmake/config-ix.cmake
index 083f1c98d0f16..d0ef92ed6d446 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -476,6 +476,7 @@ if(APPLE)
   set(SANITIZER_COMMON_SUPPORTED_OS osx)
   set(PROFILE_SUPPORTED_OS osx)
   set(TSAN_SUPPORTED_OS osx)
+  set(TSAN_DEADLOCK_SUPPORTED_OS osx)
   set(TYSAN_SUPPORTED_OS osx)
   set(XRAY_SUPPORTED_OS osx)
   set(FUZZER_SUPPORTED_OS osx)
@@ -575,6 +576,7 @@ if(APPLE)
           list(APPEND SANITIZER_COMMON_SUPPORTED_OS ${platform}sim)
           list(APPEND PROFILE_SUPPORTED_OS ${platform}sim)
           list(APPEND TSAN_SUPPORTED_OS ${platform}sim)
+          list(APPEND TSAN_DEADLOCK_SUPPORTED_OS ${platform}sim)
           list(APPEND FUZZER_SUPPORTED_OS ${platform}sim)
           list(APPEND ORC_SUPPORTED_OS ${platform}sim)
           list(APPEND UBSAN_SUPPORTED_OS ${platform}sim)
@@ -608,6 +610,7 @@ if(APPLE)
           list_intersect(DARWIN_${platform}_TSAN_ARCHS 
DARWIN_${platform}_ARCHS ALL_TSAN_SUPPORTED_ARCH)
           if(DARWIN_${platform}_TSAN_ARCHS)
             list(APPEND TSAN_SUPPORTED_OS ${platform})
+            list(APPEND TSAN_DEADLOCK_SUPPORTED_OS ${platform})
           endif()
           list(APPEND FUZZER_SUPPORTED_OS ${platform})
           list(APPEND ORC_SUPPORTED_OS ${platform})
@@ -677,6 +680,9 @@ if(APPLE)
   list_intersect(TSAN_SUPPORTED_ARCH
     ALL_TSAN_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
+  list_intersect(TSAN_DEADLOCK_SUPPORTED_ARCH
+    ALL_TSAN_DEADLOCK_SUPPORTED_ARCH
+    SANITIZER_COMMON_SUPPORTED_ARCH)
   list_intersect(UBSAN_SUPPORTED_ARCH
     ALL_UBSAN_SUPPORTED_ARCH
     SANITIZER_COMMON_SUPPORTED_ARCH)
@@ -726,6 +732,7 @@ else()
   filter_available_targets(PROFILE_SUPPORTED_ARCH 
${ALL_PROFILE_SUPPORTED_ARCH})
   filter_available_targets(CTX_PROFILE_SUPPORTED_ARCH 
${ALL_CTX_PROFILE_SUPPORTED_ARCH})
   filter_available_targets(TSAN_SUPPORTED_ARCH ${ALL_TSAN_SUPPORTED_ARCH})
+  filter_available_targets(TSAN_DEADLOCK_SUPPORTED_ARCH 
${ALL_TSAN_DEADLOCK_SUPPORTED_ARCH})
   filter_available_targets(TYSAN_SUPPORTED_ARCH ${ALL_TYSAN_SUPPORTED_ARCH})
   filter_available_targets(UBSAN_SUPPORTED_ARCH ${ALL_UBSAN_SUPPORTED_ARCH})
   filter_available_targets(SAFESTACK_SUPPORTED_ARCH
@@ -765,7 +772,7 @@ if(COMPILER_RT_SUPPORTED_ARCH)
 endif()
 message(STATUS "Compiler-RT supported architectures: 
${COMPILER_RT_SUPPORTED_ARCH}")
 
-set(ALL_SANITIZERS 
asan;rtsan;dfsan;msan;hwasan;tsan;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
+set(ALL_SANITIZERS 
asan;rtsan;dfsan;msan;hwasan;tsan;tsan_deadlock;tysan;safestack;cfi;scudo_standalone;ubsan_minimal;gwp_asan;nsan;asan_abi)
 set(COMPILER_RT_SANITIZERS_TO_BUILD all CACHE STRING
     "sanitizers to build if supported on the target (all;${ALL_SANITIZERS})")
 list_replace(COMPILER_RT_SANITIZERS_TO_BUILD all "${ALL_SANITIZERS}")
@@ -879,6 +886,7 @@ if (COMPILER_RT_HAS_SANITIZER_COMMON AND 
TSAN_SUPPORTED_ARCH)
 else()
   set(COMPILER_RT_HAS_TSAN FALSE)
 endif()
+set(COMPILER_RT_HAS_TSAN_DEADLOCK ${COMPILER_RT_HAS_TSAN})
 
 if (OS_NAME MATCHES "Linux|FreeBSD|Windows|NetBSD|SunOS")
   set(COMPILER_RT_TSAN_HAS_STATIC_RUNTIME TRUE)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h 
b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
index c694897b6556b..8d30a4e2f044c 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -500,5 +500,8 @@ using namespace __sanitizer;
 namespace __memprof {
 using namespace __sanitizer;
 }
+namespace __tsan_deadlock {
+using namespace __sanitizer;
+}
 
 #endif  // SANITIZER_DEFS_H
diff --git a/compiler-rt/lib/tsan_deadlock/CMakeLists.txt 
b/compiler-rt/lib/tsan_deadlock/CMakeLists.txt
new file mode 100644
index 0000000000000..74fc0f8bdb1cb
--- /dev/null
+++ b/compiler-rt/lib/tsan_deadlock/CMakeLists.txt
@@ -0,0 +1,76 @@
+# Build for the DeadlockSanitizer runtime support library.
+
+include_directories(..)
+
+set(TSAN_DEADLOCK_SOURCES
+  tsan_deadlock_rtl.cpp
+  tsan_deadlock_interceptors.cpp
+  tsan_deadlock_interface.cpp)
+
+set(TSAN_DEADLOCK_HEADERS
+  tsan_deadlock_rtl.h)
+
+set(TSAN_DEADLOCK_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+append_rtti_flag(OFF TSAN_DEADLOCK_CFLAGS)
+
+set(TSAN_DEADLOCK_DYNAMIC_LINK_LIBS
+  ${COMPILER_RT_UNWINDER_LINK_LIBS}
+  ${SANITIZER_CXX_ABI_LIBRARIES}
+  ${SANITIZER_COMMON_LINK_LIBS})
+
+append_list_if(COMPILER_RT_HAS_LIBDL dl TSAN_DEADLOCK_DYNAMIC_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBM m TSAN_DEADLOCK_DYNAMIC_LINK_LIBS)
+append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread 
TSAN_DEADLOCK_DYNAMIC_LINK_LIBS)
+
+add_compiler_rt_component(tsan_deadlock)
+
+if(APPLE)
+  add_weak_symbols("sanitizer_common" WEAK_SYMBOL_LINK_FLAGS)
+
+  add_compiler_rt_runtime(clang_rt.tsan_deadlock
+    SHARED
+    OS ${TSAN_DEADLOCK_SUPPORTED_OS}
+    ARCHS ${TSAN_DEADLOCK_SUPPORTED_ARCH}
+    SOURCES ${TSAN_DEADLOCK_SOURCES}
+    ADDITIONAL_HEADERS ${TSAN_DEADLOCK_HEADERS}
+    OBJECT_LIBS RTInterception
+                RTSanitizerCommon
+                RTSanitizerCommonLibc
+                RTSanitizerCommonCoverage
+                RTSanitizerCommonSymbolizer
+    CFLAGS ${TSAN_DEADLOCK_CFLAGS}
+    LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS} ${WEAK_SYMBOL_LINK_FLAGS}
+    LINK_LIBS ${SANITIZER_COMMON_LINK_LIBS}
+    PARENT_TARGET tsan_deadlock)
+else()
+  foreach(arch ${TSAN_DEADLOCK_SUPPORTED_ARCH})
+    add_compiler_rt_runtime(clang_rt.tsan_deadlock
+      STATIC
+      ARCHS ${arch}
+      SOURCES ${TSAN_DEADLOCK_SOURCES}
+              $<TARGET_OBJECTS:RTInterception.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>
+      ADDITIONAL_HEADERS ${TSAN_DEADLOCK_HEADERS}
+      CFLAGS ${TSAN_DEADLOCK_CFLAGS}
+      PARENT_TARGET tsan_deadlock)
+    add_compiler_rt_runtime(clang_rt.tsan_deadlock
+      SHARED
+      ARCHS ${arch}
+      SOURCES ${TSAN_DEADLOCK_SOURCES}
+              $<TARGET_OBJECTS:RTInterception.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonCoverage.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>
+              $<TARGET_OBJECTS:RTSanitizerCommonSymbolizerInternal.${arch}>
+      ADDITIONAL_HEADERS ${TSAN_DEADLOCK_HEADERS}
+      CFLAGS ${TSAN_DEADLOCK_CFLAGS}
+      LINK_LIBS ${TSAN_DEADLOCK_DYNAMIC_LINK_LIBS}
+      LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}
+      PARENT_TARGET tsan_deadlock)
+  endforeach()
+endif()
diff --git a/compiler-rt/lib/tsan_deadlock/tsan_deadlock_interceptors.cpp 
b/compiler-rt/lib/tsan_deadlock/tsan_deadlock_interceptors.cpp
new file mode 100644
index 0000000000000..51ed3a22e2d9d
--- /dev/null
+++ b/compiler-rt/lib/tsan_deadlock/tsan_deadlock_interceptors.cpp
@@ -0,0 +1,398 @@
+//===-- tsan_deadlock_interceptors.cpp 
------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of DeadlockSanitizer.
+//
+//===----------------------------------------------------------------------===//
+
+#include <pthread.h>
+
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_errno.h"
+#include "sanitizer_common/sanitizer_glibc_version.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_deadlock_rtl.h"
+
+using namespace __tsan_deadlock;
+
+__attribute__((tls_model("initial-exec"))) static __thread volatile int 
initing;
+static bool inited;
+
+static bool InitThread() {
+  if (initing)
+    return false;
+  if (cur_thread())
+    return true;
+  initing = true;
+  if (!inited) {
+    inited = true;
+    Initialize();
+  }
+  ThreadInit(&thr_tls);
+  initing = false;
+  return true;
+}
+
+struct ThreadArg {
+  void *(*fn)(void *);
+  void *arg;
+};
+
+static void *ThreadTrampoline(void *arg) {
+  ThreadArg *targ = static_cast<ThreadArg *>(arg);
+  void *(*fn)(void *) = targ->fn;
+  void *fn_arg = targ->arg;
+  InternalFree(targ);
+  ThreadInit(&thr_tls);
+  void *retval = fn(fn_arg);
+  // Also called from the pthread_exit interceptor; guard with is_inited to
+  // stay idempotent.
+  if (thr_tls.is_inited)
+    ThreadDestroy(&thr_tls);
+  return retval;
+}
+
+INTERCEPTOR(int, pthread_create, pthread_t *th, const pthread_attr_t *attr,
+            void *(*fn)(void *), void *arg) {
+  InitThread();
+  ThreadArg *targ = static_cast<ThreadArg *>(InternalAlloc(sizeof(ThreadArg)));
+  targ->fn = fn;
+  targ->arg = arg;
+  return REAL(pthread_create)(th, attr, ThreadTrampoline, targ);
+}
+
+INTERCEPTOR(int, pthread_join, pthread_t t, void **retval) {
+  InitThread();
+  return REAL(pthread_join)(t, retval);
+}
+
+INTERCEPTOR(void, pthread_exit, void *retval) {
+  if (thr_tls.is_inited)
+    ThreadDestroy(&thr_tls);
+  REAL(pthread_exit)(retval);
+}
+
+INTERCEPTOR(int, pthread_mutex_init, pthread_mutex_t *m,
+            const pthread_mutexattr_t *attr) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_mutex_init)(m, attr);
+  if (res == 0) {
+    bool reentrant = false;
+    if (attr) {
+      int type = 0;
+      if (pthread_mutexattr_gettype(attr, &type) == 0)
+        reentrant = (type == PTHREAD_MUTEX_RECURSIVE);
+    }
+    MutexInit(cur_thread(), (uptr)m, reentrant, pc);
+  }
+  return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_mutex_destroy)(m);
+  if (res == 0 || res == errno_EBUSY)
+    MutexDestroy(cur_thread(), (uptr)m, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeLock(cur_thread(), (uptr)m, true, pc);
+  int res = REAL(pthread_mutex_lock)(m);
+  MutexAfterLock(cur_thread(), (uptr)m, true, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_mutex_trylock)(m);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, true, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_timedlock, pthread_mutex_t *m,
+            const struct timespec *abstime) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_mutex_timedlock)(m, abstime);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, true, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeUnlock(cur_thread(), (uptr)m, true, pc);
+  return REAL(pthread_mutex_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_spin_init, pthread_spinlock_t *m, int pshared) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_spin_init)(m, pshared);
+  if (res == 0)
+    MutexInit(cur_thread(), (uptr)m, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_spin_destroy)(m);
+  if (res == 0)
+    MutexDestroy(cur_thread(), (uptr)m, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeLock(cur_thread(), (uptr)m, true, pc);
+  int res = REAL(pthread_spin_lock)(m);
+  MutexAfterLock(cur_thread(), (uptr)m, true, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_spin_trylock)(m);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, true, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeUnlock(cur_thread(), (uptr)m, true, pc);
+  return REAL(pthread_spin_unlock)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_init, pthread_rwlock_t *m,
+            const pthread_rwlockattr_t *attr) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_rwlock_init)(m, attr);
+  if (res == 0)
+    MutexInit(cur_thread(), (uptr)m, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexDestroy(cur_thread(), (uptr)m, pc);
+  return REAL(pthread_rwlock_destroy)(m);
+}
+
+INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeLock(cur_thread(), (uptr)m, false, pc);
+  int res = REAL(pthread_rwlock_rdlock)(m);
+  MutexAfterLock(cur_thread(), (uptr)m, false, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_rwlock_tryrdlock)(m);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, false, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m,
+            const timespec *abstime) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, false, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  MutexBeforeLock(cur_thread(), (uptr)m, true, pc);
+  int res = REAL(pthread_rwlock_wrlock)(m);
+  MutexAfterLock(cur_thread(), (uptr)m, true, false, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_rwlock_trywrlock)(m);
+  if (res == 0)
+    MutexAfterLock(cur_thread(), (uptr)m, true, true, pc);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m,
+            const timespec *abstime) {
+  uptr pc = GET_CURRENT_PC();
+  InitThread();
+  int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
+  if (res == 0...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/212748
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to