|
46 | 46 |
|
47 | 47 | using namespace __sanitizer;
|
48 | 48 |
|
| 49 | + |
| 50 | +#if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \ |
| 51 | + defined(__s390x__) |
| 52 | +#define PTHREAD_ABI_BASE "GLIBC_2.3.2" |
| 53 | +#elif defined(__aarch64__) || SANITIZER_PPC64V2 |
| 54 | +#define PTHREAD_ABI_BASE "GLIBC_2.17" |
| 55 | +#elif SANITIZER_LOONGARCH64 |
| 56 | +#define PTHREAD_ABI_BASE "GLIBC_2.36" |
| 57 | +#elif SANITIZER_RISCV64 |
| 58 | +# define PTHREAD_ABI_BASE "GLIBC_2.27" |
| 59 | +#endif |
| 60 | + |
| 61 | +DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, usize size) |
| 62 | +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr) |
| 63 | + |
49 | 64 | namespace {
|
50 | 65 | struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
|
51 | 66 | static bool UseImpl() { return !__rtsan_is_initialized(); }
|
52 | 67 | };
|
53 | 68 | } // namespace
|
54 | 69 |
|
| 70 | +// See note in tsan or ddsan as to why this is necessary |
| 71 | +static pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) { |
| 72 | + if (!common_flags()->legacy_pthread_cond) |
| 73 | + return c; |
| 74 | + |
| 75 | + atomic_uintptr_t *p = (atomic_uintptr_t *)c; |
| 76 | + uptr cond = atomic_load(p, memory_order_acquire); |
| 77 | + if (!force && cond != 0) |
| 78 | + return (pthread_cond_t *)cond; |
| 79 | + void *newcond = WRAP(malloc)(sizeof(pthread_cond_t)); |
| 80 | + internal_memset(newcond, 0, sizeof(pthread_cond_t)); |
| 81 | + if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond, |
| 82 | + memory_order_acq_rel)) |
| 83 | + return (pthread_cond_t *)newcond; |
| 84 | + WRAP(free)(newcond); |
| 85 | + return (pthread_cond_t *)cond; |
| 86 | +} |
| 87 | + |
55 | 88 | // Filesystem
|
56 | 89 |
|
57 | 90 | INTERCEPTOR(int, open, const char *path, int oflag, ...) {
|
@@ -766,26 +799,49 @@ INTERCEPTOR(int, pthread_join, pthread_t thread, void **value_ptr) {
|
766 | 799 | return REAL(pthread_join)(thread, value_ptr);
|
767 | 800 | }
|
768 | 801 |
|
| 802 | +INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *cond, |
| 803 | + const pthread_condattr_t *a) { |
| 804 | + __rtsan_notify_intercepted_call("pthread_cond_init"); |
| 805 | + pthread_cond_t *c = init_cond(cond, true); |
| 806 | + return REAL(pthread_cond_init)(c, a); |
| 807 | +} |
| 808 | + |
769 | 809 | INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *cond) {
|
770 | 810 | __rtsan_notify_intercepted_call("pthread_cond_signal");
|
771 |
| - return REAL(pthread_cond_signal)(cond); |
| 811 | + pthread_cond_t *c = init_cond(cond); |
| 812 | + return REAL(pthread_cond_signal)(c); |
772 | 813 | }
|
773 | 814 |
|
774 | 815 | INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *cond) {
|
775 | 816 | __rtsan_notify_intercepted_call("pthread_cond_broadcast");
|
776 |
| - return REAL(pthread_cond_broadcast)(cond); |
| 817 | + pthread_cond_t *c = init_cond(cond); |
| 818 | + return REAL(pthread_cond_broadcast)(c); |
777 | 819 | }
|
778 | 820 |
|
779 | 821 | INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *cond,
|
780 | 822 | pthread_mutex_t *mutex) {
|
781 | 823 | __rtsan_notify_intercepted_call("pthread_cond_wait");
|
782 |
| - return REAL(pthread_cond_wait)(cond, mutex); |
| 824 | + pthread_cond_t *c = init_cond(cond); |
| 825 | + return REAL(pthread_cond_wait)(c, mutex); |
783 | 826 | }
|
784 | 827 |
|
785 | 828 | INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *cond,
|
786 | 829 | pthread_mutex_t *mutex, const timespec *ts) {
|
787 | 830 | __rtsan_notify_intercepted_call("pthread_cond_timedwait");
|
788 |
| - return REAL(pthread_cond_timedwait)(cond, mutex, ts); |
| 831 | + pthread_cond_t *c = init_cond(cond); |
| 832 | + return REAL(pthread_cond_timedwait)(c, mutex, ts); |
| 833 | +} |
| 834 | + |
| 835 | +INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *cond) { |
| 836 | + __rtsan_notify_intercepted_call("pthread_cond_destroy"); |
| 837 | + pthread_cond_t *c = init_cond(cond); |
| 838 | + int res = REAL(pthread_cond_destroy)(c); |
| 839 | + if (common_flags()->legacy_pthread_cond) { |
| 840 | + // Free our aux cond and zero the pointer to not leave dangling pointers. |
| 841 | + WRAP(free)(c); |
| 842 | + atomic_store((atomic_uintptr_t *)c, 0, memory_order_relaxed); |
| 843 | + } |
| 844 | + return res; |
789 | 845 | }
|
790 | 846 |
|
791 | 847 | INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *lock) {
|
@@ -1641,10 +1697,14 @@ void __rtsan::InitializeInterceptors() {
|
1641 | 1697 | INTERCEPT_FUNCTION(pthread_mutex_lock);
|
1642 | 1698 | INTERCEPT_FUNCTION(pthread_mutex_unlock);
|
1643 | 1699 | INTERCEPT_FUNCTION(pthread_join);
|
1644 |
| - INTERCEPT_FUNCTION(pthread_cond_signal); |
1645 |
| - INTERCEPT_FUNCTION(pthread_cond_broadcast); |
1646 |
| - INTERCEPT_FUNCTION(pthread_cond_wait); |
1647 |
| - INTERCEPT_FUNCTION(pthread_cond_timedwait); |
| 1700 | + |
| 1701 | + INTERCEPT_FUNCTION_VER(pthread_cond_init, PTHREAD_ABI_BASE); |
| 1702 | + INTERCEPT_FUNCTION_VER(pthread_cond_signal, PTHREAD_ABI_BASE); |
| 1703 | + INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE); |
| 1704 | + INTERCEPT_FUNCTION_VER(pthread_cond_wait, PTHREAD_ABI_BASE); |
| 1705 | + INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE); |
| 1706 | + INTERCEPT_FUNCTION_VER(pthread_cond_destroy, PTHREAD_ABI_BASE); |
| 1707 | + |
1648 | 1708 | INTERCEPT_FUNCTION(pthread_rwlock_rdlock);
|
1649 | 1709 | INTERCEPT_FUNCTION(pthread_rwlock_unlock);
|
1650 | 1710 | INTERCEPT_FUNCTION(pthread_rwlock_wrlock);
|
|
0 commit comments