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