[clang] [compiler-rt] [llvm] [tsan] Revive TSAN's standalone deadlock sanitizer implementation (PR #212748)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 29 04:41:43 PDT 2026
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
More information about the cfe-commits
mailing list