[compiler-rt] r206423 - Move pthread_cond_* interceptors from sanitizer_common with all the ugly hacks to TSan

Alexey Samsonov samsonov at google.com
Wed Apr 16 16:06:46 PDT 2014


Author: samsonov
Date: Wed Apr 16 18:06:46 2014
New Revision: 206423

URL: http://llvm.org/viewvc/llvm-project?rev=206423&view=rev
Log:
Move pthread_cond_* interceptors from sanitizer_common with all the ugly hacks to TSan

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc Wed Apr 16 18:06:46 2014
@@ -2648,145 +2648,6 @@ INTERCEPTOR(int, pthread_mutex_unlock, v
 #define INIT_PTHREAD_MUTEX_UNLOCK
 #endif
 
-#if SANITIZER_INTERCEPT_PTHREAD_COND
-// Problem:
-// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
-// pthread_cond_t has different size in the different versions.
-// If call new REAL functions for old pthread_cond_t, they will corrupt memory
-// after pthread_cond_t (old cond is smaller).
-// If we call old REAL functions for new pthread_cond_t, we will lose  some
-// functionality (e.g. old functions do not support waiting against
-// CLOCK_REALTIME).
-// Proper handling would require to have 2 versions of interceptors as well.
-// But this is messy, in particular requires linker scripts when sanitizer
-// runtime is linked into a shared library.
-// Instead we assume we don't have dynamic libraries built against old
-// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag
-// that allows to work with old libraries (but this mode does not support
-// some features, e.g. pthread_condattr_getpshared).
-static void *init_cond(void *c, bool force = false) {
-  // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions.
-  // So we allocate additional memory on the side large enough to hold
-  // any pthread_cond_t object. Always call new REAL functions, but pass
-  // the aux object to them.
-  // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes
-  // first word of pthread_cond_t to zero.
-  // It's all relevant only for linux.
-  if (!common_flags()->legacy_pthread_cond)
-    return c;
-  atomic_uintptr_t *p = (atomic_uintptr_t*)c;
-  uptr cond = atomic_load(p, memory_order_acquire);
-  if (!force && cond != 0)
-    return (void*)cond;
-  void *newcond = WRAP(malloc)(pthread_cond_t_sz);
-  internal_memset(newcond, 0, pthread_cond_t_sz);
-  if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
-      memory_order_acq_rel))
-    return newcond;
-  WRAP(free)(newcond);
-  return (void*)cond;
-}
-
-struct CondMutexUnlockCtx {
-  void *ctx;
-  void *m;
-};
-
-static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
-  COMMON_INTERCEPTOR_MUTEX_LOCK(arg->ctx, arg->m);
-}
-
-namespace __sanitizer {
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
-    void *abstime), void *c, void *m, void *abstime,
-    void(*cleanup)(void *arg), void *arg);
-}  // namespace __sanitizer
-
-INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
-  void *cond = init_cond(c, true);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_init, cond, a);
-  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, sizeof(uptr));
-  return REAL(pthread_cond_init)(cond, a);
-}
-
-INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
-  void *cond = init_cond(c);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_wait, cond, m);
-  COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, sizeof(uptr));
-  CondMutexUnlockCtx arg = {ctx, m};
-  // This ensures that we handle mutex lock even in case of pthread_cancel.
-  // See test/tsan/cond_cancel.cc.
-  int res = __sanitizer::call_pthread_cancel_with_cleanup(
-      (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
-      cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
-  if (res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
-  COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
-  return res;
-}
-
-INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
-  void *cond = init_cond(c);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_timedwait, cond, m, abstime);
-  COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, sizeof(uptr));
-  CondMutexUnlockCtx arg = {ctx, m};
-  // This ensures that we handle mutex lock even in case of pthread_cancel.
-  // See test/tsan/cond_cancel.cc.
-  int res = __sanitizer::call_pthread_cancel_with_cleanup(
-      REAL(pthread_cond_timedwait), cond, m, abstime,
-      (void(*)(void *arg))cond_mutex_unlock, &arg);
-  if (res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
-  COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
-  return res;
-}
-
-INTERCEPTOR(int, pthread_cond_signal, void *c) {
-  void *cond = init_cond(c);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_signal, cond);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, sizeof(uptr));
-  return REAL(pthread_cond_signal)(cond);
-}
-
-INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
-  void *cond = init_cond(c);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_broadcast, cond);
-  COMMON_INTERCEPTOR_READ_RANGE(ctx, c, sizeof(uptr));
-  return REAL(pthread_cond_broadcast)(cond);
-}
-
-INTERCEPTOR(int, pthread_cond_destroy, void *c) {
-  void *cond = init_cond(c);
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_destroy, cond);
-  COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, sizeof(uptr));
-  int res = REAL(pthread_cond_destroy)(cond);
-  if (common_flags()->legacy_pthread_cond) {
-    // Free our aux cond and zero the pointer to not leave dangling pointers.
-    WRAP(free)(cond);
-    atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
-  }
-  return res;
-}
-
-#define INIT_PTHREAD_COND \
-  INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2"); \
-  INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2"); \
-  INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); \
-  INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2"); \
-  INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); \
-  INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2")
-#else
-#define INIT_PTHREAD_COND
-#endif
-
 #if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
 static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
@@ -3934,7 +3795,6 @@ INTERCEPTOR(int, xdr_string, __sanitizer
   INIT__EXIT;                              \
   INIT_PTHREAD_MUTEX_LOCK;                 \
   INIT_PTHREAD_MUTEX_UNLOCK;               \
-  INIT_PTHREAD_COND;                       \
   INIT_GETMNTENT;                          \
   INIT_GETMNTENT_R;                        \
   INIT_STATFS;                             \

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_linux_libcdep.cc Wed Apr 16 18:06:46 2014
@@ -527,18 +527,6 @@ void SetIndirectCallWrapper(uptr wrapper
   indirect_call_wrapper = wrapper;
 }
 
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
-    void *abstime), void *c, void *m, void *abstime,
-    void(*cleanup)(void *arg), void *arg) {
-  // pthread_cleanup_push/pop are hardcore macros mess.
-  // We can't intercept nor call them w/o including pthread.h.
-  int res;
-  pthread_cleanup_push(cleanup, arg);
-  res = fn(c, m, abstime);
-  pthread_cleanup_pop(0);
-  return res;
-}
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mac.cc Wed Apr 16 18:06:46 2014
@@ -302,18 +302,6 @@ MacosVersion GetMacosVersion() {
   return result;
 }
 
-int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
-    void *abstime), void *c, void *m, void *abstime,
-    void(*cleanup)(void *arg), void *arg) {
-  // pthread_cleanup_push/pop are hardcore macros mess.
-  // We can't intercept nor call them w/o including pthread.h.
-  int res;
-  pthread_cleanup_push(cleanup, arg);
-  res = fn(c, m, abstime);
-  pthread_cleanup_pop(0);
-  return res;
-}
-
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_MAC

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_platform_interceptors.h Wed Apr 16 18:06:46 2014
@@ -181,7 +181,6 @@
 #define SANITIZER_INTERCEPT__EXIT SI_LINUX
 
 #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PTHREAD_COND SI_NOT_WINDOWS
 #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
 
 #define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interceptors.cc Wed Apr 16 18:06:46 2014
@@ -213,6 +213,7 @@ ScopedInterceptor::~ScopedInterceptor()
 
 #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
 #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
+#define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
 
 #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
 
@@ -915,6 +916,122 @@ TSAN_INTERCEPTOR(int, pthread_detach, vo
   return res;
 }
 
+// Problem:
+// NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
+// pthread_cond_t has different size in the different versions.
+// If call new REAL functions for old pthread_cond_t, they will corrupt memory
+// after pthread_cond_t (old cond is smaller).
+// If we call old REAL functions for new pthread_cond_t, we will lose  some
+// functionality (e.g. old functions do not support waiting against
+// CLOCK_REALTIME).
+// Proper handling would require to have 2 versions of interceptors as well.
+// But this is messy, in particular requires linker scripts when sanitizer
+// runtime is linked into a shared library.
+// Instead we assume we don't have dynamic libraries built against old
+// pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag
+// that allows to work with old libraries (but this mode does not support
+// some features, e.g. pthread_condattr_getpshared).
+static void *init_cond(void *c, bool force = false) {
+  // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions.
+  // So we allocate additional memory on the side large enough to hold
+  // any pthread_cond_t object. Always call new REAL functions, but pass
+  // the aux object to them.
+  // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes
+  // first word of pthread_cond_t to zero.
+  // It's all relevant only for linux.
+  if (!common_flags()->legacy_pthread_cond)
+    return c;
+  atomic_uintptr_t *p = (atomic_uintptr_t*)c;
+  uptr cond = atomic_load(p, memory_order_acquire);
+  if (!force && cond != 0)
+    return (void*)cond;
+  void *newcond = WRAP(malloc)(pthread_cond_t_sz);
+  internal_memset(newcond, 0, pthread_cond_t_sz);
+  if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
+      memory_order_acq_rel))
+    return newcond;
+  WRAP(free)(newcond);
+  return (void*)cond;
+}
+
+struct CondMutexUnlockCtx {
+  ThreadState *thr;
+  uptr pc;
+  void *m;
+};
+
+static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
+  MutexLock(arg->thr, arg->pc, (uptr)arg->m);
+}
+
+INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
+  void *cond = init_cond(c, true);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+  return REAL(pthread_cond_init)(cond, a);
+}
+
+INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
+  void *cond = init_cond(c);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
+  MutexUnlock(thr, pc, (uptr)m);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+  CondMutexUnlockCtx arg = {thr, pc, m};
+  // This ensures that we handle mutex lock even in case of pthread_cancel.
+  // See test/tsan/cond_cancel.cc.
+  int res = call_pthread_cancel_with_cleanup(
+      (int(*)(void *c, void *m, void *abstime))REAL(pthread_cond_wait),
+      cond, m, 0, (void(*)(void *arg))cond_mutex_unlock, &arg);
+  if (res == errno_EOWNERDEAD)
+    MutexRepair(thr, pc, (uptr)m);
+  MutexLock(thr, pc, (uptr)m);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
+  void *cond = init_cond(c);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
+  MutexUnlock(thr, pc, (uptr)m);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+  CondMutexUnlockCtx arg = {thr, pc, m};
+  // This ensures that we handle mutex lock even in case of pthread_cancel.
+  // See test/tsan/cond_cancel.cc.
+  int res = call_pthread_cancel_with_cleanup(
+      REAL(pthread_cond_timedwait), cond, m, abstime,
+      (void(*)(void *arg))cond_mutex_unlock, &arg);
+  if (res == errno_EOWNERDEAD)
+    MutexRepair(thr, pc, (uptr)m);
+  MutexLock(thr, pc, (uptr)m);
+  return res;
+}
+
+INTERCEPTOR(int, pthread_cond_signal, void *c) {
+  void *cond = init_cond(c);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+  return REAL(pthread_cond_signal)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
+  void *cond = init_cond(c);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+  return REAL(pthread_cond_broadcast)(cond);
+}
+
+INTERCEPTOR(int, pthread_cond_destroy, void *c) {
+  void *cond = init_cond(c);
+  SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond);
+  MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
+  int res = REAL(pthread_cond_destroy)(cond);
+  if (common_flags()->legacy_pthread_cond) {
+    // Free our aux cond and zero the pointer to not leave dangling pointers.
+    WRAP(free)(cond);
+    atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
+  }
+  return res;
+}
+
 TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a);
   int res = REAL(pthread_mutex_init)(m, a);
@@ -2209,6 +2326,13 @@ void InitializeInterceptors() {
   TSAN_INTERCEPT(pthread_join);
   TSAN_INTERCEPT(pthread_detach);
 
+  TSAN_INTERCEPT_VER(pthread_cond_init, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_signal, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_wait, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
+  TSAN_INTERCEPT_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+
   TSAN_INTERCEPT(pthread_mutex_init);
   TSAN_INTERCEPT(pthread_mutex_destroy);
   TSAN_INTERCEPT(pthread_mutex_trylock);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform.h Wed Apr 16 18:06:46 2014
@@ -165,6 +165,10 @@ bool IsGlobalVar(uptr addr);
 int ExtractResolvFDs(void *state, int *fds, int nfd);
 int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
 
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+    void *abstime), void *c, void *m, void *abstime,
+    void(*cleanup)(void *arg), void *arg);
+
 }  // namespace __tsan
 
 #else  // defined(__LP64__) || defined(_WIN64)

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_linux.cc Wed Apr 16 18:06:46 2014
@@ -358,8 +358,19 @@ int ExtractRecvmsgFDs(void *msgp, int *f
   }
   return res;
 }
-#endif
 
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+    void *abstime), void *c, void *m, void *abstime,
+    void(*cleanup)(void *arg), void *arg) {
+  // pthread_cleanup_push/pop are hardcore macros mess.
+  // We can't intercept nor call them w/o including pthread.h.
+  int res;
+  pthread_cleanup_push(cleanup, arg);
+  res = fn(c, m, abstime);
+  pthread_cleanup_pop(0);
+  return res;
+}
+#endif
 
 }  // namespace __tsan
 

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc?rev=206423&r1=206422&r2=206423&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_platform_mac.cc Wed Apr 16 18:06:46 2014
@@ -91,6 +91,20 @@ void FinalizePlatform() {
   fflush(0);
 }
 
+#ifndef TSAN_GO
+int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
+    void *abstime), void *c, void *m, void *abstime,
+    void(*cleanup)(void *arg), void *arg) {
+  // pthread_cleanup_push/pop are hardcore macros mess.
+  // We can't intercept nor call them w/o including pthread.h.
+  int res;
+  pthread_cleanup_push(cleanup, arg);
+  res = fn(c, m, abstime);
+  pthread_cleanup_pop(0);
+  return res;
+}
+#endif
+
 }  // namespace __tsan
 
 #endif  // SANITIZER_MAC





More information about the llvm-commits mailing list