1 //===-- dd_interceptors.cpp -----------------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <pthread.h> 10 11 #include "dd_rtl.h" 12 #include "interception/interception.h" 13 #include "sanitizer_common/sanitizer_allocator_internal.h" 14 #include "sanitizer_common/sanitizer_procmaps.h" 15 16 using namespace __dsan; 17 18 __attribute__((tls_model("initial-exec"))) 19 static __thread Thread *thr; 20 __attribute__((tls_model("initial-exec"))) 21 static __thread volatile int initing; 22 static bool inited; 23 static uptr g_data_start; 24 static uptr g_data_end; 25 26 static bool InitThread() { 27 if (initing) 28 return false; 29 if (thr != 0) 30 return true; 31 initing = true; 32 if (!inited) { 33 inited = true; 34 Initialize(); 35 } 36 thr = (Thread*)InternalAlloc(sizeof(*thr)); 37 internal_memset(thr, 0, sizeof(*thr)); 38 ThreadInit(thr); 39 initing = false; 40 return true; 41 } 42 43 INTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) { 44 InitThread(); 45 MutexDestroy(thr, (uptr)m); 46 return REAL(pthread_mutex_destroy)(m); 47 } 48 49 INTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) { 50 InitThread(); 51 MutexBeforeLock(thr, (uptr)m, true); 52 int res = REAL(pthread_mutex_lock)(m); 53 MutexAfterLock(thr, (uptr)m, true, false); 54 return res; 55 } 56 57 INTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) { 58 InitThread(); 59 int res = REAL(pthread_mutex_trylock)(m); 60 if (res == 0) 61 MutexAfterLock(thr, (uptr)m, true, true); 62 return res; 63 } 64 65 INTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) { 66 InitThread(); 67 MutexBeforeUnlock(thr, (uptr)m, true); 68 return REAL(pthread_mutex_unlock)(m); 69 } 70 71 INTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) { 72 InitThread(); 73 int res = REAL(pthread_spin_destroy)(m); 74 MutexDestroy(thr, (uptr)m); 75 return res; 76 } 77 78 INTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) { 79 InitThread(); 80 MutexBeforeLock(thr, (uptr)m, true); 81 int res = REAL(pthread_spin_lock)(m); 82 MutexAfterLock(thr, (uptr)m, true, false); 83 return res; 84 } 85 86 INTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) { 87 InitThread(); 88 int res = REAL(pthread_spin_trylock)(m); 89 if (res == 0) 90 MutexAfterLock(thr, (uptr)m, true, true); 91 return res; 92 } 93 94 INTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) { 95 InitThread(); 96 MutexBeforeUnlock(thr, (uptr)m, true); 97 return REAL(pthread_spin_unlock)(m); 98 } 99 100 INTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) { 101 InitThread(); 102 MutexDestroy(thr, (uptr)m); 103 return REAL(pthread_rwlock_destroy)(m); 104 } 105 106 INTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) { 107 InitThread(); 108 MutexBeforeLock(thr, (uptr)m, false); 109 int res = REAL(pthread_rwlock_rdlock)(m); 110 MutexAfterLock(thr, (uptr)m, false, false); 111 return res; 112 } 113 114 INTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) { 115 InitThread(); 116 int res = REAL(pthread_rwlock_tryrdlock)(m); 117 if (res == 0) 118 MutexAfterLock(thr, (uptr)m, false, true); 119 return res; 120 } 121 122 INTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m, 123 const timespec *abstime) { 124 InitThread(); 125 int res = REAL(pthread_rwlock_timedrdlock)(m, abstime); 126 if (res == 0) 127 MutexAfterLock(thr, (uptr)m, false, true); 128 return res; 129 } 130 131 INTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) { 132 InitThread(); 133 MutexBeforeLock(thr, (uptr)m, true); 134 int res = REAL(pthread_rwlock_wrlock)(m); 135 MutexAfterLock(thr, (uptr)m, true, false); 136 return res; 137 } 138 139 INTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) { 140 InitThread(); 141 int res = REAL(pthread_rwlock_trywrlock)(m); 142 if (res == 0) 143 MutexAfterLock(thr, (uptr)m, true, true); 144 return res; 145 } 146 147 INTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m, 148 const timespec *abstime) { 149 InitThread(); 150 int res = REAL(pthread_rwlock_timedwrlock)(m, abstime); 151 if (res == 0) 152 MutexAfterLock(thr, (uptr)m, true, true); 153 return res; 154 } 155 156 INTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) { 157 InitThread(); 158 MutexBeforeUnlock(thr, (uptr)m, true); // note: not necessary write unlock 159 return REAL(pthread_rwlock_unlock)(m); 160 } 161 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; 174 } 175 176 INTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c, 177 const pthread_condattr_t *a) { 178 InitThread(); 179 pthread_cond_t *cond = init_cond(c, true); 180 return REAL(pthread_cond_init)(cond, a); 181 } 182 183 INTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) { 184 InitThread(); 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); 190 return res; 191 } 192 193 INTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m, 194 const timespec *abstime) { 195 InitThread(); 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); 201 return res; 202 } 203 204 INTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) { 205 InitThread(); 206 pthread_cond_t *cond = init_cond(c); 207 return REAL(pthread_cond_signal)(cond); 208 } 209 210 INTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) { 211 InitThread(); 212 pthread_cond_t *cond = init_cond(c); 213 return REAL(pthread_cond_broadcast)(cond); 214 } 215 216 INTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) { 217 InitThread(); 218 pthread_cond_t *cond = init_cond(c); 219 int res = REAL(pthread_cond_destroy)(cond); 220 InternalFree(cond); 221 atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed); 222 return res; 223 } 224 225 // for symbolizer 226 INTERCEPTOR(char*, realpath, const char *path, char *resolved_path) { 227 InitThread(); 228 return REAL(realpath)(path, resolved_path); 229 } 230 231 INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { 232 InitThread(); 233 return REAL(read)(fd, ptr, count); 234 } 235 236 INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { 237 InitThread(); 238 return REAL(pread)(fd, ptr, count, offset); 239 } 240 241 extern "C" { 242 void __dsan_before_mutex_lock(uptr m, int writelock) { 243 if (!InitThread()) 244 return; 245 MutexBeforeLock(thr, m, writelock); 246 } 247 248 void __dsan_after_mutex_lock(uptr m, int writelock, int trylock) { 249 if (!InitThread()) 250 return; 251 MutexAfterLock(thr, m, writelock, trylock); 252 } 253 254 void __dsan_before_mutex_unlock(uptr m, int writelock) { 255 if (!InitThread()) 256 return; 257 MutexBeforeUnlock(thr, m, writelock); 258 } 259 260 void __dsan_mutex_destroy(uptr m) { 261 if (!InitThread()) 262 return; 263 // if (m >= g_data_start && m < g_data_end) 264 // return; 265 MutexDestroy(thr, m); 266 } 267 } // extern "C" 268 269 namespace __dsan { 270 271 static void InitDataSeg() { 272 MemoryMappingLayout proc_maps(true); 273 char name[128]; 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 279 // reliable. 280 bool is_bss = segment.offset == 0 && 281 (segment.filename[0] == 0 || 282 internal_strcmp(segment.filename, "[heap]") == 0) && 283 prev_is_data; 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; 287 } 288 VPrintf(1, "guessed data_start=%p data_end=%p\n", g_data_start, g_data_end); 289 CHECK_LT(g_data_start, g_data_end); 290 CHECK_GE((uptr)&g_data_start, g_data_start); 291 CHECK_LT((uptr)&g_data_start, g_data_end); 292 } 293 294 void InitializeInterceptors() { 295 INTERCEPT_FUNCTION(pthread_mutex_destroy); 296 INTERCEPT_FUNCTION(pthread_mutex_lock); 297 INTERCEPT_FUNCTION(pthread_mutex_trylock); 298 INTERCEPT_FUNCTION(pthread_mutex_unlock); 299 300 INTERCEPT_FUNCTION(pthread_spin_destroy); 301 INTERCEPT_FUNCTION(pthread_spin_lock); 302 INTERCEPT_FUNCTION(pthread_spin_trylock); 303 INTERCEPT_FUNCTION(pthread_spin_unlock); 304 305 INTERCEPT_FUNCTION(pthread_rwlock_destroy); 306 INTERCEPT_FUNCTION(pthread_rwlock_rdlock); 307 INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock); 308 INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock); 309 INTERCEPT_FUNCTION(pthread_rwlock_wrlock); 310 INTERCEPT_FUNCTION(pthread_rwlock_trywrlock); 311 INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock); 312 INTERCEPT_FUNCTION(pthread_rwlock_unlock); 313 314 INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2"); 315 INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2"); 316 INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2"); 317 INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2"); 318 INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2"); 319 INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2"); 320 321 // for symbolizer 322 INTERCEPT_FUNCTION(realpath); 323 INTERCEPT_FUNCTION(read); 324 INTERCEPT_FUNCTION(pread); 325 326 InitDataSeg(); 327 } 328 329 } // namespace __dsan 330