1 //===-- tsan_platform_mac.cc ----------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of ThreadSanitizer (TSan), a race detector. 11 // 12 // Mac-specific code. 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_common/sanitizer_platform.h" 16 #if SANITIZER_MAC 17 18 #include "sanitizer_common/sanitizer_atomic.h" 19 #include "sanitizer_common/sanitizer_common.h" 20 #include "sanitizer_common/sanitizer_libc.h" 21 #include "sanitizer_common/sanitizer_posix.h" 22 #include "sanitizer_common/sanitizer_procmaps.h" 23 #include "tsan_platform.h" 24 #include "tsan_rtl.h" 25 #include "tsan_flags.h" 26 27 #include <pthread.h> 28 #include <signal.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdarg.h> 33 #include <sys/mman.h> 34 #include <sys/syscall.h> 35 #include <sys/time.h> 36 #include <sys/types.h> 37 #include <sys/resource.h> 38 #include <sys/stat.h> 39 #include <unistd.h> 40 #include <errno.h> 41 #include <sched.h> 42 43 namespace __tsan { 44 45 #ifndef SANITIZER_GO 46 static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) { 47 atomic_uintptr_t *a = (atomic_uintptr_t *)dst; 48 void *val = (void *)atomic_load_relaxed(a); 49 atomic_signal_fence(memory_order_acquire); // Turns the previous load into 50 // acquire wrt signals. 51 if (UNLIKELY(val == nullptr)) { 52 val = (void *)internal_mmap(nullptr, size, PROT_READ | PROT_WRITE, 53 MAP_PRIVATE | MAP_ANON, -1, 0); 54 CHECK(val); 55 void *cmp = nullptr; 56 if (!atomic_compare_exchange_strong(a, (uintptr_t *)&cmp, (uintptr_t)val, 57 memory_order_acq_rel)) { 58 internal_munmap(val, size); 59 val = cmp; 60 } 61 } 62 return val; 63 } 64 65 // On OS X, accessing TLVs via __thread or manually by using pthread_key_* is 66 // problematic, because there are several places where interceptors are called 67 // when TLVs are not accessible (early process startup, thread cleanup, ...). 68 // The following provides a "poor man's TLV" implementation, where we use the 69 // shadow memory of the pointer returned by pthread_self() to store a pointer to 70 // the ThreadState object. The main thread's ThreadState is stored separately 71 // in a static variable, because we need to access it even before the 72 // shadow memory is set up. 73 static uptr main_thread_identity = 0; 74 ALIGNED(64) static char main_thread_state[sizeof(ThreadState)]; 75 76 ThreadState *cur_thread() { 77 uptr thread_identity = (uptr)pthread_self(); 78 if (thread_identity == main_thread_identity || main_thread_identity == 0) { 79 return (ThreadState *)&main_thread_state; 80 } 81 ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity); 82 ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate( 83 (uptr *)fake_tls, sizeof(ThreadState)); 84 return thr; 85 } 86 87 // TODO(kuba.brecka): This is not async-signal-safe. In particular, we call 88 // munmap first and then clear `fake_tls`; if we receive a signal in between, 89 // handler will try to access the unmapped ThreadState. 90 void cur_thread_finalize() { 91 uptr thread_identity = (uptr)pthread_self(); 92 if (thread_identity == main_thread_identity) { 93 // Calling dispatch_main() or xpc_main() actually invokes pthread_exit to 94 // exit the main thread. Let's keep the main thread's ThreadState. 95 return; 96 } 97 ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity); 98 internal_munmap(*fake_tls, sizeof(ThreadState)); 99 *fake_tls = nullptr; 100 } 101 #endif 102 103 uptr GetShadowMemoryConsumption() { 104 return 0; 105 } 106 107 void FlushShadowMemory() { 108 } 109 110 void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) { 111 } 112 113 #ifndef SANITIZER_GO 114 void InitializeShadowMemoryPlatform() { } 115 116 // On OS X, GCD worker threads are created without a call to pthread_create. We 117 // need to properly register these threads with ThreadCreate and ThreadStart. 118 // These threads don't have a parent thread, as they are created "spuriously". 119 // We're using a libpthread API that notifies us about a newly created thread. 120 // The `thread == pthread_self()` check indicates this is actually a worker 121 // thread. If it's just a regular thread, this hook is called on the parent 122 // thread. 123 typedef void (*pthread_introspection_hook_t)(unsigned int event, 124 pthread_t thread, void *addr, 125 size_t size); 126 extern "C" pthread_introspection_hook_t pthread_introspection_hook_install( 127 pthread_introspection_hook_t hook); 128 static const uptr PTHREAD_INTROSPECTION_THREAD_CREATE = 1; 129 static const uptr PTHREAD_INTROSPECTION_THREAD_TERMINATE = 3; 130 static pthread_introspection_hook_t prev_pthread_introspection_hook; 131 static void my_pthread_introspection_hook(unsigned int event, pthread_t thread, 132 void *addr, size_t size) { 133 if (event == PTHREAD_INTROSPECTION_THREAD_CREATE) { 134 if (thread == pthread_self()) { 135 // The current thread is a newly created GCD worker thread. 136 ThreadState *thr = cur_thread(); 137 Processor *proc = ProcCreate(); 138 ProcWire(proc, thr); 139 ThreadState *parent_thread_state = nullptr; // No parent. 140 int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true); 141 CHECK_NE(tid, 0); 142 ThreadStart(thr, tid, GetTid()); 143 } 144 } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) { 145 if (thread == pthread_self()) { 146 ThreadState *thr = cur_thread(); 147 if (thr->tctx) { 148 DestroyThreadState(); 149 } 150 } 151 } 152 153 if (prev_pthread_introspection_hook != nullptr) 154 prev_pthread_introspection_hook(event, thread, addr, size); 155 } 156 #endif 157 158 void InitializePlatformEarly() { 159 } 160 161 void InitializePlatform() { 162 DisableCoreDumperIfNecessary(); 163 #ifndef SANITIZER_GO 164 CheckAndProtect(); 165 166 CHECK_EQ(main_thread_identity, 0); 167 main_thread_identity = (uptr)pthread_self(); 168 169 prev_pthread_introspection_hook = 170 pthread_introspection_hook_install(&my_pthread_introspection_hook); 171 #endif 172 } 173 174 #ifndef SANITIZER_GO 175 // Note: this function runs with async signals enabled, 176 // so it must not touch any tsan state. 177 int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, 178 void *abstime), void *c, void *m, void *abstime, 179 void(*cleanup)(void *arg), void *arg) { 180 // pthread_cleanup_push/pop are hardcore macros mess. 181 // We can't intercept nor call them w/o including pthread.h. 182 int res; 183 pthread_cleanup_push(cleanup, arg); 184 res = fn(c, m, abstime); 185 pthread_cleanup_pop(0); 186 return res; 187 } 188 #endif 189 190 } // namespace __tsan 191 192 #endif // SANITIZER_MAC 193