1 1.1 kamil //===-- asan_mac.cc -------------------------------------------------------===// 2 1.1 kamil // 3 1.1 kamil // The LLVM Compiler Infrastructure 4 1.1 kamil // 5 1.1 kamil // This file is distributed under the University of Illinois Open Source 6 1.1 kamil // License. See LICENSE.TXT for details. 7 1.1 kamil // 8 1.1 kamil //===----------------------------------------------------------------------===// 9 1.1 kamil // 10 1.1 kamil // This file is a part of AddressSanitizer, an address sanity checker. 11 1.1 kamil // 12 1.1 kamil // Mac-specific details. 13 1.1 kamil //===----------------------------------------------------------------------===// 14 1.1 kamil 15 1.1 kamil #include "sanitizer_common/sanitizer_platform.h" 16 1.1 kamil #if SANITIZER_MAC 17 1.1 kamil 18 1.1 kamil #include "asan_interceptors.h" 19 1.1 kamil #include "asan_internal.h" 20 1.1 kamil #include "asan_mapping.h" 21 1.1 kamil #include "asan_stack.h" 22 1.1 kamil #include "asan_thread.h" 23 1.1 kamil #include "sanitizer_common/sanitizer_atomic.h" 24 1.1 kamil #include "sanitizer_common/sanitizer_libc.h" 25 1.1 kamil #include "sanitizer_common/sanitizer_mac.h" 26 1.1 kamil 27 1.1 kamil #include <dlfcn.h> 28 1.1 kamil #include <fcntl.h> 29 1.1 kamil #include <libkern/OSAtomic.h> 30 1.1 kamil #include <mach-o/dyld.h> 31 1.1 kamil #include <mach-o/getsect.h> 32 1.1 kamil #include <mach-o/loader.h> 33 1.1 kamil #include <pthread.h> 34 1.1 kamil #include <stdlib.h> // for free() 35 1.1 kamil #include <sys/mman.h> 36 1.1 kamil #include <sys/resource.h> 37 1.1 kamil #include <sys/sysctl.h> 38 1.1 kamil #include <sys/ucontext.h> 39 1.1 kamil #include <unistd.h> 40 1.1 kamil 41 1.1 kamil // from <crt_externs.h>, but we don't have that file on iOS 42 1.1 kamil extern "C" { 43 1.1 kamil extern char ***_NSGetArgv(void); 44 1.1 kamil extern char ***_NSGetEnviron(void); 45 1.1 kamil } 46 1.1 kamil 47 1.1 kamil namespace __asan { 48 1.1 kamil 49 1.1 kamil void InitializePlatformInterceptors() {} 50 1.1 kamil void InitializePlatformExceptionHandlers() {} 51 1.1 kamil bool IsSystemHeapAddress (uptr addr) { return false; } 52 1.1 kamil 53 1.1 kamil // No-op. Mac does not support static linkage anyway. 54 1.1 kamil void *AsanDoesNotSupportStaticLinkage() { 55 1.1 kamil return 0; 56 1.1 kamil } 57 1.1 kamil 58 1.1 kamil uptr FindDynamicShadowStart() { 59 1.1 kamil uptr granularity = GetMmapGranularity(); 60 1.1 kamil uptr alignment = 8 * granularity; 61 1.1 kamil uptr left_padding = granularity; 62 1.1 kamil uptr space_size = kHighShadowEnd + left_padding; 63 1.1 kamil 64 1.1 kamil uptr largest_gap_found = 0; 65 1.1 kamil uptr max_occupied_addr = 0; 66 1.1 kamil VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); 67 1.1 kamil uptr shadow_start = 68 1.1 kamil FindAvailableMemoryRange(space_size, alignment, granularity, 69 1.1 kamil &largest_gap_found, &max_occupied_addr); 70 1.1 kamil // If the shadow doesn't fit, restrict the address space to make it fit. 71 1.1 kamil if (shadow_start == 0) { 72 1.1 kamil VReport( 73 1.1 kamil 2, 74 1.1 kamil "Shadow doesn't fit, largest_gap_found = %p, max_occupied_addr = %p\n", 75 1.1 kamil largest_gap_found, max_occupied_addr); 76 1.1 kamil uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment); 77 1.1 kamil if (new_max_vm < max_occupied_addr) { 78 1.1 kamil Report("Unable to find a memory range for dynamic shadow.\n"); 79 1.1 kamil Report( 80 1.1 kamil "space_size = %p, largest_gap_found = %p, max_occupied_addr = %p, " 81 1.1 kamil "new_max_vm = %p\n", 82 1.1 kamil space_size, largest_gap_found, max_occupied_addr, new_max_vm); 83 1.1 kamil CHECK(0 && "cannot place shadow"); 84 1.1 kamil } 85 1.1 kamil RestrictMemoryToMaxAddress(new_max_vm); 86 1.1 kamil kHighMemEnd = new_max_vm - 1; 87 1.1 kamil space_size = kHighShadowEnd + left_padding; 88 1.1 kamil VReport(2, "FindDynamicShadowStart, space_size = %p\n", space_size); 89 1.1 kamil shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity, 90 1.1 kamil nullptr, nullptr); 91 1.1 kamil if (shadow_start == 0) { 92 1.1 kamil Report("Unable to find a memory range after restricting VM.\n"); 93 1.1 kamil CHECK(0 && "cannot place shadow after restricting vm"); 94 1.1 kamil } 95 1.1 kamil } 96 1.1 kamil CHECK_NE((uptr)0, shadow_start); 97 1.1 kamil CHECK(IsAligned(shadow_start, alignment)); 98 1.1 kamil return shadow_start; 99 1.1 kamil } 100 1.1 kamil 101 1.1 kamil // No-op. Mac does not support static linkage anyway. 102 1.1 kamil void AsanCheckDynamicRTPrereqs() {} 103 1.1 kamil 104 1.1 kamil // No-op. Mac does not support static linkage anyway. 105 1.1 kamil void AsanCheckIncompatibleRT() {} 106 1.1 kamil 107 1.1 kamil void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 108 1.1 kamil // Find the Mach-O header for the image containing the needle 109 1.1 kamil Dl_info info; 110 1.1 kamil int err = dladdr(needle, &info); 111 1.1 kamil if (err == 0) return; 112 1.1 kamil 113 1.1 kamil #if __LP64__ 114 1.1 kamil const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; 115 1.1 kamil #else 116 1.1 kamil const struct mach_header *mh = (struct mach_header *)info.dli_fbase; 117 1.1 kamil #endif 118 1.1 kamil 119 1.1 kamil // Look up the __asan_globals section in that image and register its globals 120 1.1 kamil unsigned long size = 0; 121 1.1 kamil __asan_global *globals = (__asan_global *)getsectiondata( 122 1.1 kamil mh, 123 1.1 kamil "__DATA", "__asan_globals", 124 1.1 kamil &size); 125 1.1 kamil 126 1.1 kamil if (!globals) return; 127 1.1 kamil if (size % sizeof(__asan_global) != 0) return; 128 1.1 kamil op(globals, size / sizeof(__asan_global)); 129 1.1 kamil } 130 1.1 kamil 131 1.1 kamil void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 132 1.1 kamil UNIMPLEMENTED(); 133 1.1 kamil } 134 1.1 kamil 135 1.1 kamil // Support for the following functions from libdispatch on Mac OS: 136 1.1 kamil // dispatch_async_f() 137 1.1 kamil // dispatch_async() 138 1.1 kamil // dispatch_sync_f() 139 1.1 kamil // dispatch_sync() 140 1.1 kamil // dispatch_after_f() 141 1.1 kamil // dispatch_after() 142 1.1 kamil // dispatch_group_async_f() 143 1.1 kamil // dispatch_group_async() 144 1.1 kamil // TODO(glider): libdispatch API contains other functions that we don't support 145 1.1 kamil // yet. 146 1.1 kamil // 147 1.1 kamil // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are 148 1.1 kamil // they can cause jobs to run on a thread different from the current one. 149 1.1 kamil // TODO(glider): if so, we need a test for this (otherwise we should remove 150 1.1 kamil // them). 151 1.1 kamil // 152 1.1 kamil // The following functions use dispatch_barrier_async_f() (which isn't a library 153 1.1 kamil // function but is exported) and are thus supported: 154 1.1 kamil // dispatch_source_set_cancel_handler_f() 155 1.1 kamil // dispatch_source_set_cancel_handler() 156 1.1 kamil // dispatch_source_set_event_handler_f() 157 1.1 kamil // dispatch_source_set_event_handler() 158 1.1 kamil // 159 1.1 kamil // The reference manual for Grand Central Dispatch is available at 160 1.1 kamil // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html 161 1.1 kamil // The implementation details are at 162 1.1 kamil // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c 163 1.1 kamil 164 1.1 kamil typedef void* dispatch_group_t; 165 1.1 kamil typedef void* dispatch_queue_t; 166 1.1 kamil typedef void* dispatch_source_t; 167 1.1 kamil typedef u64 dispatch_time_t; 168 1.1 kamil typedef void (*dispatch_function_t)(void *block); 169 1.1 kamil typedef void* (*worker_t)(void *block); 170 1.1 kamil 171 1.1 kamil // A wrapper for the ObjC blocks used to support libdispatch. 172 1.1 kamil typedef struct { 173 1.1 kamil void *block; 174 1.1 kamil dispatch_function_t func; 175 1.1 kamil u32 parent_tid; 176 1.1 kamil } asan_block_context_t; 177 1.1 kamil 178 1.1 kamil ALWAYS_INLINE 179 1.1 kamil void asan_register_worker_thread(int parent_tid, StackTrace *stack) { 180 1.1 kamil AsanThread *t = GetCurrentThread(); 181 1.1 kamil if (!t) { 182 1.1 kamil t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, 183 1.1 kamil parent_tid, stack, /* detached */ true); 184 1.1 kamil t->Init(); 185 1.1 kamil asanThreadRegistry().StartThread(t->tid(), GetTid(), 186 1.1 kamil /* workerthread */ true, 0); 187 1.1 kamil SetCurrentThread(t); 188 1.1 kamil } 189 1.1 kamil } 190 1.1 kamil 191 1.1 kamil // For use by only those functions that allocated the context via 192 1.1 kamil // alloc_asan_context(). 193 1.1 kamil extern "C" 194 1.1 kamil void asan_dispatch_call_block_and_release(void *block) { 195 1.1 kamil GET_STACK_TRACE_THREAD; 196 1.1 kamil asan_block_context_t *context = (asan_block_context_t*)block; 197 1.1 kamil VReport(2, 198 1.1 kamil "asan_dispatch_call_block_and_release(): " 199 1.1 kamil "context: %p, pthread_self: %p\n", 200 1.1 kamil block, pthread_self()); 201 1.1 kamil asan_register_worker_thread(context->parent_tid, &stack); 202 1.1 kamil // Call the original dispatcher for the block. 203 1.1 kamil context->func(context->block); 204 1.1 kamil asan_free(context, &stack, FROM_MALLOC); 205 1.1 kamil } 206 1.1 kamil 207 1.1 kamil } // namespace __asan 208 1.1 kamil 209 1.1 kamil using namespace __asan; // NOLINT 210 1.1 kamil 211 1.1 kamil // Wrap |ctxt| and |func| into an asan_block_context_t. 212 1.1 kamil // The caller retains control of the allocated context. 213 1.1 kamil extern "C" 214 1.1 kamil asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, 215 1.1 kamil BufferedStackTrace *stack) { 216 1.1 kamil asan_block_context_t *asan_ctxt = 217 1.1 kamil (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); 218 1.1 kamil asan_ctxt->block = ctxt; 219 1.1 kamil asan_ctxt->func = func; 220 1.1 kamil asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); 221 1.1 kamil return asan_ctxt; 222 1.1 kamil } 223 1.1 kamil 224 1.1 kamil // Define interceptor for dispatch_*_f function with the three most common 225 1.1 kamil // parameters: dispatch_queue_t, context, dispatch_function_t. 226 1.1 kamil #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ 227 1.1 kamil INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ 228 1.1 kamil dispatch_function_t func) { \ 229 1.1 kamil GET_STACK_TRACE_THREAD; \ 230 1.1 kamil asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ 231 1.1 kamil if (Verbosity() >= 2) { \ 232 1.1 kamil Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ 233 1.1 kamil asan_ctxt, pthread_self()); \ 234 1.1 kamil PRINT_CURRENT_STACK(); \ 235 1.1 kamil } \ 236 1.1 kamil return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \ 237 1.1 kamil asan_dispatch_call_block_and_release); \ 238 1.1 kamil } 239 1.1 kamil 240 1.1 kamil INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) 241 1.1 kamil INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) 242 1.1 kamil INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) 243 1.1 kamil 244 1.1 kamil INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, 245 1.1 kamil dispatch_queue_t dq, void *ctxt, 246 1.1 kamil dispatch_function_t func) { 247 1.1 kamil GET_STACK_TRACE_THREAD; 248 1.1 kamil asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 249 1.1 kamil if (Verbosity() >= 2) { 250 1.1 kamil Report("dispatch_after_f: %p\n", asan_ctxt); 251 1.1 kamil PRINT_CURRENT_STACK(); 252 1.1 kamil } 253 1.1 kamil return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, 254 1.1 kamil asan_dispatch_call_block_and_release); 255 1.1 kamil } 256 1.1 kamil 257 1.1 kamil INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, 258 1.1 kamil dispatch_queue_t dq, void *ctxt, 259 1.1 kamil dispatch_function_t func) { 260 1.1 kamil GET_STACK_TRACE_THREAD; 261 1.1 kamil asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 262 1.1 kamil if (Verbosity() >= 2) { 263 1.1 kamil Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", 264 1.1 kamil asan_ctxt, pthread_self()); 265 1.1 kamil PRINT_CURRENT_STACK(); 266 1.1 kamil } 267 1.1 kamil REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, 268 1.1 kamil asan_dispatch_call_block_and_release); 269 1.1 kamil } 270 1.1 kamil 271 1.1 kamil #if !defined(MISSING_BLOCKS_SUPPORT) 272 1.1 kamil extern "C" { 273 1.1 kamil void dispatch_async(dispatch_queue_t dq, void(^work)(void)); 274 1.1 kamil void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, 275 1.1 kamil void(^work)(void)); 276 1.1 kamil void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, 277 1.1 kamil void(^work)(void)); 278 1.1 kamil void dispatch_source_set_cancel_handler(dispatch_source_t ds, 279 1.1 kamil void(^work)(void)); 280 1.1 kamil void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); 281 1.1 kamil } 282 1.1 kamil 283 1.1 kamil #define GET_ASAN_BLOCK(work) \ 284 1.1 kamil void (^asan_block)(void); \ 285 1.1 kamil int parent_tid = GetCurrentTidOrInvalid(); \ 286 1.1 kamil asan_block = ^(void) { \ 287 1.1 kamil GET_STACK_TRACE_THREAD; \ 288 1.1 kamil asan_register_worker_thread(parent_tid, &stack); \ 289 1.1 kamil work(); \ 290 1.1 kamil } 291 1.1 kamil 292 1.1 kamil INTERCEPTOR(void, dispatch_async, 293 1.1 kamil dispatch_queue_t dq, void(^work)(void)) { 294 1.1 kamil ENABLE_FRAME_POINTER; 295 1.1 kamil GET_ASAN_BLOCK(work); 296 1.1 kamil REAL(dispatch_async)(dq, asan_block); 297 1.1 kamil } 298 1.1 kamil 299 1.1 kamil INTERCEPTOR(void, dispatch_group_async, 300 1.1 kamil dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { 301 1.1 kamil ENABLE_FRAME_POINTER; 302 1.1 kamil GET_ASAN_BLOCK(work); 303 1.1 kamil REAL(dispatch_group_async)(dg, dq, asan_block); 304 1.1 kamil } 305 1.1 kamil 306 1.1 kamil INTERCEPTOR(void, dispatch_after, 307 1.1 kamil dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { 308 1.1 kamil ENABLE_FRAME_POINTER; 309 1.1 kamil GET_ASAN_BLOCK(work); 310 1.1 kamil REAL(dispatch_after)(when, queue, asan_block); 311 1.1 kamil } 312 1.1 kamil 313 1.1 kamil INTERCEPTOR(void, dispatch_source_set_cancel_handler, 314 1.1 kamil dispatch_source_t ds, void(^work)(void)) { 315 1.1 kamil if (!work) { 316 1.1 kamil REAL(dispatch_source_set_cancel_handler)(ds, work); 317 1.1 kamil return; 318 1.1 kamil } 319 1.1 kamil ENABLE_FRAME_POINTER; 320 1.1 kamil GET_ASAN_BLOCK(work); 321 1.1 kamil REAL(dispatch_source_set_cancel_handler)(ds, asan_block); 322 1.1 kamil } 323 1.1 kamil 324 1.1 kamil INTERCEPTOR(void, dispatch_source_set_event_handler, 325 1.1 kamil dispatch_source_t ds, void(^work)(void)) { 326 1.1 kamil ENABLE_FRAME_POINTER; 327 1.1 kamil GET_ASAN_BLOCK(work); 328 1.1 kamil REAL(dispatch_source_set_event_handler)(ds, asan_block); 329 1.1 kamil } 330 1.1 kamil #endif 331 1.1 kamil 332 1.1 kamil #endif // SANITIZER_MAC 333