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