1 //===-- dd_interceptors.cpp -----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
12 #include "interception/interception.h"
13 #include "sanitizer_common/sanitizer_allocator_internal.h"
14 #include "sanitizer_common/sanitizer_procmaps.h"
16 using namespace __dsan
;
18 __attribute__((tls_model("initial-exec")))
19 static __thread Thread
*thr
;
20 __attribute__((tls_model("initial-exec")))
21 static __thread
volatile int initing
;
23 static uptr g_data_start
;
24 static uptr g_data_end
;
26 static bool InitThread() {
36 thr
= (Thread
*)InternalAlloc(sizeof(*thr
));
37 internal_memset(thr
, 0, sizeof(*thr
));
43 INTERCEPTOR(int, pthread_mutex_destroy
, pthread_mutex_t
*m
) {
45 MutexDestroy(thr
, (uptr
)m
);
46 return REAL(pthread_mutex_destroy
)(m
);
49 INTERCEPTOR(int, pthread_mutex_lock
, pthread_mutex_t
*m
) {
51 MutexBeforeLock(thr
, (uptr
)m
, true);
52 int res
= REAL(pthread_mutex_lock
)(m
);
53 MutexAfterLock(thr
, (uptr
)m
, true, false);
57 INTERCEPTOR(int, pthread_mutex_trylock
, pthread_mutex_t
*m
) {
59 int res
= REAL(pthread_mutex_trylock
)(m
);
61 MutexAfterLock(thr
, (uptr
)m
, true, true);
65 INTERCEPTOR(int, pthread_mutex_unlock
, pthread_mutex_t
*m
) {
67 MutexBeforeUnlock(thr
, (uptr
)m
, true);
68 return REAL(pthread_mutex_unlock
)(m
);
71 INTERCEPTOR(int, pthread_spin_destroy
, pthread_spinlock_t
*m
) {
73 int res
= REAL(pthread_spin_destroy
)(m
);
74 MutexDestroy(thr
, (uptr
)m
);
78 INTERCEPTOR(int, pthread_spin_lock
, pthread_spinlock_t
*m
) {
80 MutexBeforeLock(thr
, (uptr
)m
, true);
81 int res
= REAL(pthread_spin_lock
)(m
);
82 MutexAfterLock(thr
, (uptr
)m
, true, false);
86 INTERCEPTOR(int, pthread_spin_trylock
, pthread_spinlock_t
*m
) {
88 int res
= REAL(pthread_spin_trylock
)(m
);
90 MutexAfterLock(thr
, (uptr
)m
, true, true);
94 INTERCEPTOR(int, pthread_spin_unlock
, pthread_spinlock_t
*m
) {
96 MutexBeforeUnlock(thr
, (uptr
)m
, true);
97 return REAL(pthread_spin_unlock
)(m
);
100 INTERCEPTOR(int, pthread_rwlock_destroy
, pthread_rwlock_t
*m
) {
102 MutexDestroy(thr
, (uptr
)m
);
103 return REAL(pthread_rwlock_destroy
)(m
);
106 INTERCEPTOR(int, pthread_rwlock_rdlock
, pthread_rwlock_t
*m
) {
108 MutexBeforeLock(thr
, (uptr
)m
, false);
109 int res
= REAL(pthread_rwlock_rdlock
)(m
);
110 MutexAfterLock(thr
, (uptr
)m
, false, false);
114 INTERCEPTOR(int, pthread_rwlock_tryrdlock
, pthread_rwlock_t
*m
) {
116 int res
= REAL(pthread_rwlock_tryrdlock
)(m
);
118 MutexAfterLock(thr
, (uptr
)m
, false, true);
122 INTERCEPTOR(int, pthread_rwlock_timedrdlock
, pthread_rwlock_t
*m
,
123 const timespec
*abstime
) {
125 int res
= REAL(pthread_rwlock_timedrdlock
)(m
, abstime
);
127 MutexAfterLock(thr
, (uptr
)m
, false, true);
131 INTERCEPTOR(int, pthread_rwlock_wrlock
, pthread_rwlock_t
*m
) {
133 MutexBeforeLock(thr
, (uptr
)m
, true);
134 int res
= REAL(pthread_rwlock_wrlock
)(m
);
135 MutexAfterLock(thr
, (uptr
)m
, true, false);
139 INTERCEPTOR(int, pthread_rwlock_trywrlock
, pthread_rwlock_t
*m
) {
141 int res
= REAL(pthread_rwlock_trywrlock
)(m
);
143 MutexAfterLock(thr
, (uptr
)m
, true, true);
147 INTERCEPTOR(int, pthread_rwlock_timedwrlock
, pthread_rwlock_t
*m
,
148 const timespec
*abstime
) {
150 int res
= REAL(pthread_rwlock_timedwrlock
)(m
, abstime
);
152 MutexAfterLock(thr
, (uptr
)m
, true, true);
156 INTERCEPTOR(int, pthread_rwlock_unlock
, pthread_rwlock_t
*m
) {
158 MutexBeforeUnlock(thr
, (uptr
)m
, true); // note: not necessary write unlock
159 return REAL(pthread_rwlock_unlock
)(m
);
162 static pthread_cond_t
*init_cond(pthread_cond_t
*c
, bool force
= false) {
163 atomic_uintptr_t
*p
= (atomic_uintptr_t
*)c
;
164 uptr cond
= atomic_load(p
, memory_order_acquire
);
165 if (!force
&& cond
!= 0)
166 return (pthread_cond_t
*)cond
;
167 void *newcond
= InternalAlloc(sizeof(pthread_cond_t
));
168 internal_memset(newcond
, 0, sizeof(pthread_cond_t
));
169 if (atomic_compare_exchange_strong(p
, &cond
, (uptr
)newcond
,
170 memory_order_acq_rel
))
171 return (pthread_cond_t
*)newcond
;
172 InternalFree(newcond
);
173 return (pthread_cond_t
*)cond
;
176 INTERCEPTOR(int, pthread_cond_init
, pthread_cond_t
*c
,
177 const pthread_condattr_t
*a
) {
179 pthread_cond_t
*cond
= init_cond(c
, true);
180 return REAL(pthread_cond_init
)(cond
, a
);
183 INTERCEPTOR(int, pthread_cond_wait
, pthread_cond_t
*c
, pthread_mutex_t
*m
) {
185 pthread_cond_t
*cond
= init_cond(c
);
186 MutexBeforeUnlock(thr
, (uptr
)m
, true);
187 MutexBeforeLock(thr
, (uptr
)m
, true);
188 int res
= REAL(pthread_cond_wait
)(cond
, m
);
189 MutexAfterLock(thr
, (uptr
)m
, true, false);
193 INTERCEPTOR(int, pthread_cond_timedwait
, pthread_cond_t
*c
, pthread_mutex_t
*m
,
194 const timespec
*abstime
) {
196 pthread_cond_t
*cond
= init_cond(c
);
197 MutexBeforeUnlock(thr
, (uptr
)m
, true);
198 MutexBeforeLock(thr
, (uptr
)m
, true);
199 int res
= REAL(pthread_cond_timedwait
)(cond
, m
, abstime
);
200 MutexAfterLock(thr
, (uptr
)m
, true, false);
204 INTERCEPTOR(int, pthread_cond_signal
, pthread_cond_t
*c
) {
206 pthread_cond_t
*cond
= init_cond(c
);
207 return REAL(pthread_cond_signal
)(cond
);
210 INTERCEPTOR(int, pthread_cond_broadcast
, pthread_cond_t
*c
) {
212 pthread_cond_t
*cond
= init_cond(c
);
213 return REAL(pthread_cond_broadcast
)(cond
);
216 INTERCEPTOR(int, pthread_cond_destroy
, pthread_cond_t
*c
) {
218 pthread_cond_t
*cond
= init_cond(c
);
219 int res
= REAL(pthread_cond_destroy
)(cond
);
221 atomic_store((atomic_uintptr_t
*)c
, 0, memory_order_relaxed
);
226 INTERCEPTOR(char*, realpath
, const char *path
, char *resolved_path
) {
228 return REAL(realpath
)(path
, resolved_path
);
231 INTERCEPTOR(SSIZE_T
, read
, int fd
, void *ptr
, SIZE_T count
) {
233 return REAL(read
)(fd
, ptr
, count
);
236 INTERCEPTOR(SSIZE_T
, pread
, int fd
, void *ptr
, SIZE_T count
, OFF_T offset
) {
238 return REAL(pread
)(fd
, ptr
, count
, offset
);
242 void __dsan_before_mutex_lock(uptr m
, int writelock
) {
245 MutexBeforeLock(thr
, m
, writelock
);
248 void __dsan_after_mutex_lock(uptr m
, int writelock
, int trylock
) {
251 MutexAfterLock(thr
, m
, writelock
, trylock
);
254 void __dsan_before_mutex_unlock(uptr m
, int writelock
) {
257 MutexBeforeUnlock(thr
, m
, writelock
);
260 void __dsan_mutex_destroy(uptr m
) {
263 // if (m >= g_data_start && m < g_data_end)
265 MutexDestroy(thr
, m
);
271 static void InitDataSeg() {
272 MemoryMappingLayout
proc_maps(true);
274 MemoryMappedSegment
segment(name
, ARRAY_SIZE(name
));
275 bool prev_is_data
= false;
276 while (proc_maps
.Next(&segment
)) {
277 bool is_data
= segment
.offset
!= 0 && segment
.filename
[0] != 0;
278 // BSS may get merged with [heap] in /proc/self/maps. This is not very
280 bool is_bss
= segment
.offset
== 0 &&
281 (segment
.filename
[0] == 0 ||
282 internal_strcmp(segment
.filename
, "[heap]") == 0) &&
284 if (g_data_start
== 0 && is_data
) g_data_start
= segment
.start
;
285 if (is_bss
) g_data_end
= segment
.end
;
286 prev_is_data
= is_data
;
288 VPrintf(1, "guessed data_start=0x%zx data_end=0x%zx\n", g_data_start
,
290 CHECK_LT(g_data_start
, g_data_end
);
291 CHECK_GE((uptr
)&g_data_start
, g_data_start
);
292 CHECK_LT((uptr
)&g_data_start
, g_data_end
);
295 void InitializeInterceptors() {
296 INTERCEPT_FUNCTION(pthread_mutex_destroy
);
297 INTERCEPT_FUNCTION(pthread_mutex_lock
);
298 INTERCEPT_FUNCTION(pthread_mutex_trylock
);
299 INTERCEPT_FUNCTION(pthread_mutex_unlock
);
301 INTERCEPT_FUNCTION(pthread_spin_destroy
);
302 INTERCEPT_FUNCTION(pthread_spin_lock
);
303 INTERCEPT_FUNCTION(pthread_spin_trylock
);
304 INTERCEPT_FUNCTION(pthread_spin_unlock
);
306 INTERCEPT_FUNCTION(pthread_rwlock_destroy
);
307 INTERCEPT_FUNCTION(pthread_rwlock_rdlock
);
308 INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock
);
309 INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock
);
310 INTERCEPT_FUNCTION(pthread_rwlock_wrlock
);
311 INTERCEPT_FUNCTION(pthread_rwlock_trywrlock
);
312 INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock
);
313 INTERCEPT_FUNCTION(pthread_rwlock_unlock
);
315 INTERCEPT_FUNCTION_VER(pthread_cond_init
, "GLIBC_2.3.2");
316 INTERCEPT_FUNCTION_VER(pthread_cond_signal
, "GLIBC_2.3.2");
317 INTERCEPT_FUNCTION_VER(pthread_cond_broadcast
, "GLIBC_2.3.2");
318 INTERCEPT_FUNCTION_VER(pthread_cond_wait
, "GLIBC_2.3.2");
319 INTERCEPT_FUNCTION_VER(pthread_cond_timedwait
, "GLIBC_2.3.2");
320 INTERCEPT_FUNCTION_VER(pthread_cond_destroy
, "GLIBC_2.3.2");
323 INTERCEPT_FUNCTION(realpath
);
324 INTERCEPT_FUNCTION(read
);
325 INTERCEPT_FUNCTION(pread
);
330 } // namespace __dsan