asan_mac.cc revision 6895adc39c4e09371154c8037366ad4464163ed0
1//===-- asan_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 AddressSanitizer, an address sanity checker. 11// 12// Mac-specific details. 13//===----------------------------------------------------------------------===// 14 15#ifdef __APPLE__ 16 17#include "asan_interceptors.h" 18#include "asan_internal.h" 19#include "asan_mapping.h" 20#include "asan_procmaps.h" 21#include "asan_stack.h" 22#include "asan_thread.h" 23#include "asan_thread_registry.h" 24#include "sanitizer_common/sanitizer_libc.h" 25 26#include <crt_externs.h> // for _NSGetEnviron 27#include <mach-o/dyld.h> 28#include <mach-o/loader.h> 29#include <sys/mman.h> 30#include <sys/resource.h> 31#include <sys/sysctl.h> 32#include <sys/ucontext.h> 33#include <pthread.h> 34#include <fcntl.h> 35#include <unistd.h> 36#include <libkern/OSAtomic.h> 37#include <CoreFoundation/CFString.h> 38 39namespace __asan { 40 41void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { 42 ucontext_t *ucontext = (ucontext_t*)context; 43# if __WORDSIZE == 64 44 *pc = ucontext->uc_mcontext->__ss.__rip; 45 *bp = ucontext->uc_mcontext->__ss.__rbp; 46 *sp = ucontext->uc_mcontext->__ss.__rsp; 47# else 48 *pc = ucontext->uc_mcontext->__ss.__eip; 49 *bp = ucontext->uc_mcontext->__ss.__ebp; 50 *sp = ucontext->uc_mcontext->__ss.__esp; 51# endif // __WORDSIZE 52} 53 54enum { 55 MACOS_VERSION_UNKNOWN = 0, 56 MACOS_VERSION_LEOPARD, 57 MACOS_VERSION_SNOW_LEOPARD, 58 MACOS_VERSION_LION, 59}; 60 61static int GetMacosVersion() { 62 int mib[2] = { CTL_KERN, KERN_OSRELEASE }; 63 char version[100]; 64 uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); 65 for (int i = 0; i < maxlen; i++) version[i] = '\0'; 66 // Get the version length. 67 CHECK(sysctl(mib, 2, 0, &len, 0, 0) != -1); 68 CHECK(len < maxlen); 69 CHECK(sysctl(mib, 2, version, &len, 0, 0) != -1); 70 switch (version[0]) { 71 case '9': return MACOS_VERSION_LEOPARD; 72 case '1': { 73 switch (version[1]) { 74 case '0': return MACOS_VERSION_SNOW_LEOPARD; 75 case '1': return MACOS_VERSION_LION; 76 default: return MACOS_VERSION_UNKNOWN; 77 } 78 } 79 default: return MACOS_VERSION_UNKNOWN; 80 } 81} 82 83bool PlatformHasDifferentMemcpyAndMemmove() { 84 // On OS X 10.7 memcpy() and memmove() are both resolved 85 // into memmove$VARIANT$sse42. 86 // See also http://code.google.com/p/address-sanitizer/issues/detail?id=34. 87 // TODO(glider): need to check dynamically that memcpy() and memmove() are 88 // actually the same function. 89 return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; 90} 91 92// No-op. Mac does not support static linkage anyway. 93void *AsanDoesNotSupportStaticLinkage() { 94 return 0; 95} 96 97bool AsanInterceptsSignal(int signum) { 98 return (signum == SIGSEGV || signum == SIGBUS) && FLAG_handle_segv; 99} 100 101void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) { 102 return internal_mmap((void*)fixed_addr, size, 103 PROT_READ | PROT_WRITE, 104 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 105 0, 0); 106} 107 108void *AsanMprotect(uptr fixed_addr, uptr size) { 109 return internal_mmap((void*)fixed_addr, size, 110 PROT_NONE, 111 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 112 0, 0); 113} 114 115const char *AsanGetEnv(const char *name) { 116 char ***env_ptr = _NSGetEnviron(); 117 CHECK(env_ptr); 118 char **environ = *env_ptr; 119 CHECK(environ); 120 uptr name_len = internal_strlen(name); 121 while (*environ != 0) { 122 uptr len = internal_strlen(*environ); 123 if (len > name_len) { 124 const char *p = *environ; 125 if (!internal_memcmp(p, name, name_len) && 126 p[name_len] == '=') { // Match. 127 return *environ + name_len + 1; // String starting after =. 128 } 129 } 130 environ++; 131 } 132 return 0; 133} 134 135void AsanThread::SetThreadStackTopAndBottom() { 136 uptr stacksize = pthread_get_stacksize_np(pthread_self()); 137 void *stackaddr = pthread_get_stackaddr_np(pthread_self()); 138 stack_top_ = (uptr)stackaddr; 139 stack_bottom_ = stack_top_ - stacksize; 140 int local; 141 CHECK(AddrIsInStack((uptr)&local)); 142} 143 144AsanLock::AsanLock(LinkerInitialized) { 145 // We assume that OS_SPINLOCK_INIT is zero 146} 147 148void AsanLock::Lock() { 149 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); 150 CHECK(OS_SPINLOCK_INIT == 0); 151 CHECK(owner_ != (uptr)pthread_self()); 152 OSSpinLockLock((OSSpinLock*)&opaque_storage_); 153 CHECK(!owner_); 154 owner_ = (uptr)pthread_self(); 155} 156 157void AsanLock::Unlock() { 158 CHECK(owner_ == (uptr)pthread_self()); 159 owner_ = 0; 160 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 161} 162 163void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 164 size = 0; 165 trace[0] = pc; 166 if ((max_s) > 1) { 167 max_size = max_s; 168 FastUnwindStack(pc, bp); 169 } 170} 171 172// The range of pages to be used for escape islands. 173// TODO(glider): instead of mapping a fixed range we must find a range of 174// unmapped pages in vmmap and take them. 175// These constants were chosen empirically and may not work if the shadow 176// memory layout changes. Unfortunately they do necessarily depend on 177// kHighMemBeg or kHighMemEnd. 178static void *island_allocator_pos = 0; 179 180#if __WORDSIZE == 32 181# define kIslandEnd (0xffdf0000 - kPageSize) 182# define kIslandBeg (kIslandEnd - 256 * kPageSize) 183#else 184# define kIslandEnd (0x7fffffdf0000 - kPageSize) 185# define kIslandBeg (kIslandEnd - 256 * kPageSize) 186#endif 187 188extern "C" 189mach_error_t __interception_allocate_island(void **ptr, 190 uptr unused_size, 191 void *unused_hint) { 192 if (!island_allocator_pos) { 193 island_allocator_pos = 194 internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg, 195 PROT_READ | PROT_WRITE | PROT_EXEC, 196 MAP_PRIVATE | MAP_ANON | MAP_FIXED, 197 -1, 0); 198 if (island_allocator_pos != (void*)kIslandBeg) { 199 return KERN_NO_SPACE; 200 } 201 if (FLAG_v) { 202 Report("Mapped pages %p--%p for branch islands.\n", 203 (void*)kIslandBeg, (void*)kIslandEnd); 204 } 205 // Should not be very performance-critical. 206 internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg); 207 }; 208 *ptr = island_allocator_pos; 209 island_allocator_pos = (char*)island_allocator_pos + kPageSize; 210 if (FLAG_v) { 211 Report("Branch island allocated at %p\n", *ptr); 212 } 213 return err_none; 214} 215 216extern "C" 217mach_error_t __interception_deallocate_island(void *ptr) { 218 // Do nothing. 219 // TODO(glider): allow to free and reuse the island memory. 220 return err_none; 221} 222 223// Support for the following functions from libdispatch on Mac OS: 224// dispatch_async_f() 225// dispatch_async() 226// dispatch_sync_f() 227// dispatch_sync() 228// dispatch_after_f() 229// dispatch_after() 230// dispatch_group_async_f() 231// dispatch_group_async() 232// TODO(glider): libdispatch API contains other functions that we don't support 233// yet. 234// 235// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are 236// they can cause jobs to run on a thread different from the current one. 237// TODO(glider): if so, we need a test for this (otherwise we should remove 238// them). 239// 240// The following functions use dispatch_barrier_async_f() (which isn't a library 241// function but is exported) and are thus supported: 242// dispatch_source_set_cancel_handler_f() 243// dispatch_source_set_cancel_handler() 244// dispatch_source_set_event_handler_f() 245// dispatch_source_set_event_handler() 246// 247// The reference manual for Grand Central Dispatch is available at 248// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html 249// The implementation details are at 250// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c 251 252typedef void* pthread_workqueue_t; 253typedef void* pthread_workitem_handle_t; 254 255typedef void* dispatch_group_t; 256typedef void* dispatch_queue_t; 257typedef u64 dispatch_time_t; 258typedef void (*dispatch_function_t)(void *block); 259typedef void* (*worker_t)(void *block); 260 261// A wrapper for the ObjC blocks used to support libdispatch. 262typedef struct { 263 void *block; 264 dispatch_function_t func; 265 u32 parent_tid; 266} asan_block_context_t; 267 268// We use extern declarations of libdispatch functions here instead 269// of including <dispatch/dispatch.h>. This header is not present on 270// Mac OS X Leopard and eariler, and although we don't expect ASan to 271// work on legacy systems, it's bad to break the build of 272// LLVM compiler-rt there. 273extern "C" { 274void dispatch_async_f(dispatch_queue_t dq, void *ctxt, 275 dispatch_function_t func); 276void dispatch_sync_f(dispatch_queue_t dq, void *ctxt, 277 dispatch_function_t func); 278void dispatch_after_f(dispatch_time_t when, dispatch_queue_t dq, void *ctxt, 279 dispatch_function_t func); 280void dispatch_barrier_async_f(dispatch_queue_t dq, void *ctxt, 281 dispatch_function_t func); 282void dispatch_group_async_f(dispatch_group_t group, dispatch_queue_t dq, 283 void *ctxt, dispatch_function_t func); 284int pthread_workqueue_additem_np(pthread_workqueue_t workq, 285 void *(*workitem_func)(void *), void * workitem_arg, 286 pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp); 287} // extern "C" 288 289extern "C" 290void asan_dispatch_call_block_and_release(void *block) { 291 GET_STACK_TRACE_HERE(kStackTraceMax); 292 asan_block_context_t *context = (asan_block_context_t*)block; 293 if (FLAG_v >= 2) { 294 Report("asan_dispatch_call_block_and_release(): " 295 "context: %p, pthread_self: %p\n", 296 block, pthread_self()); 297 } 298 AsanThread *t = asanThreadRegistry().GetCurrent(); 299 if (!t) { 300 t = AsanThread::Create(context->parent_tid, 0, 0, &stack); 301 asanThreadRegistry().RegisterThread(t); 302 t->Init(); 303 asanThreadRegistry().SetCurrent(t); 304 } 305 // Call the original dispatcher for the block. 306 context->func(context->block); 307 asan_free(context, &stack); 308} 309 310} // namespace __asan 311 312using namespace __asan; // NOLINT 313 314// Wrap |ctxt| and |func| into an asan_block_context_t. 315// The caller retains control of the allocated context. 316extern "C" 317asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, 318 AsanStackTrace *stack) { 319 asan_block_context_t *asan_ctxt = 320 (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); 321 asan_ctxt->block = ctxt; 322 asan_ctxt->func = func; 323 asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); 324 return asan_ctxt; 325} 326 327// TODO(glider): can we reduce code duplication by introducing a macro? 328INTERCEPTOR(void, dispatch_async_f, dispatch_queue_t dq, void *ctxt, 329 dispatch_function_t func) { 330 GET_STACK_TRACE_HERE(kStackTraceMax); 331 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 332 if (FLAG_v >= 2) { 333 Report("dispatch_async_f(): context: %p, pthread_self: %p\n", 334 asan_ctxt, pthread_self()); 335 PRINT_CURRENT_STACK(); 336 } 337 return REAL(dispatch_async_f)(dq, (void*)asan_ctxt, 338 asan_dispatch_call_block_and_release); 339} 340 341INTERCEPTOR(void, dispatch_sync_f, dispatch_queue_t dq, void *ctxt, 342 dispatch_function_t func) { 343 GET_STACK_TRACE_HERE(kStackTraceMax); 344 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 345 if (FLAG_v >= 2) { 346 Report("dispatch_sync_f(): context: %p, pthread_self: %p\n", 347 asan_ctxt, pthread_self()); 348 PRINT_CURRENT_STACK(); 349 } 350 return REAL(dispatch_sync_f)(dq, (void*)asan_ctxt, 351 asan_dispatch_call_block_and_release); 352} 353 354INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, 355 dispatch_queue_t dq, void *ctxt, 356 dispatch_function_t func) { 357 GET_STACK_TRACE_HERE(kStackTraceMax); 358 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 359 if (FLAG_v >= 2) { 360 Report("dispatch_after_f: %p\n", asan_ctxt); 361 PRINT_CURRENT_STACK(); 362 } 363 return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, 364 asan_dispatch_call_block_and_release); 365} 366 367INTERCEPTOR(void, dispatch_barrier_async_f, dispatch_queue_t dq, void *ctxt, 368 dispatch_function_t func) { 369 GET_STACK_TRACE_HERE(kStackTraceMax); 370 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 371 if (FLAG_v >= 2) { 372 Report("dispatch_barrier_async_f(): context: %p, pthread_self: %p\n", 373 asan_ctxt, pthread_self()); 374 PRINT_CURRENT_STACK(); 375 } 376 REAL(dispatch_barrier_async_f)(dq, (void*)asan_ctxt, 377 asan_dispatch_call_block_and_release); 378} 379 380INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, 381 dispatch_queue_t dq, void *ctxt, 382 dispatch_function_t func) { 383 GET_STACK_TRACE_HERE(kStackTraceMax); 384 asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); 385 if (FLAG_v >= 2) { 386 Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", 387 asan_ctxt, pthread_self()); 388 PRINT_CURRENT_STACK(); 389 } 390 REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, 391 asan_dispatch_call_block_and_release); 392} 393 394// The following stuff has been extremely helpful while looking for the 395// unhandled functions that spawned jobs on Chromium shutdown. If the verbosity 396// level is 2 or greater, we wrap pthread_workqueue_additem_np() in order to 397// find the points of worker thread creation (each of such threads may be used 398// to run several tasks, that's why this is not enough to support the whole 399// libdispatch API. 400extern "C" 401void *wrap_workitem_func(void *arg) { 402 if (FLAG_v >= 2) { 403 Report("wrap_workitem_func: %p, pthread_self: %p\n", arg, pthread_self()); 404 } 405 asan_block_context_t *ctxt = (asan_block_context_t*)arg; 406 worker_t fn = (worker_t)(ctxt->func); 407 void *result = fn(ctxt->block); 408 GET_STACK_TRACE_HERE(kStackTraceMax); 409 asan_free(arg, &stack); 410 return result; 411} 412 413INTERCEPTOR(int, pthread_workqueue_additem_np, pthread_workqueue_t workq, 414 void *(*workitem_func)(void *), void * workitem_arg, 415 pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) { 416 GET_STACK_TRACE_HERE(kStackTraceMax); 417 asan_block_context_t *asan_ctxt = 418 (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack); 419 asan_ctxt->block = workitem_arg; 420 asan_ctxt->func = (dispatch_function_t)workitem_func; 421 asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrInvalid(); 422 if (FLAG_v >= 2) { 423 Report("pthread_workqueue_additem_np: %p\n", asan_ctxt); 424 PRINT_CURRENT_STACK(); 425 } 426 return REAL(pthread_workqueue_additem_np)(workq, wrap_workitem_func, 427 asan_ctxt, itemhandlep, 428 gencountp); 429} 430 431// CF_RC_BITS, the layout of CFRuntimeBase and __CFStrIsConstant are internal 432// and subject to change in further CoreFoundation versions. Apple does not 433// guarantee any binary compatibility from release to release. 434 435// See http://opensource.apple.com/source/CF/CF-635.15/CFInternal.h 436#if defined(__BIG_ENDIAN__) 437#define CF_RC_BITS 0 438#endif 439 440#if defined(__LITTLE_ENDIAN__) 441#define CF_RC_BITS 3 442#endif 443 444// See http://opensource.apple.com/source/CF/CF-635.15/CFRuntime.h 445typedef struct __CFRuntimeBase { 446 uptr _cfisa; 447 u8 _cfinfo[4]; 448#if __LP64__ 449 u32 _rc; 450#endif 451} CFRuntimeBase; 452 453// See http://opensource.apple.com/source/CF/CF-635.15/CFString.c 454int __CFStrIsConstant(CFStringRef str) { 455 CFRuntimeBase *base = (CFRuntimeBase*)str; 456#if __LP64__ 457 return base->_rc == 0; 458#else 459 return (base->_cfinfo[CF_RC_BITS]) == 0; 460#endif 461} 462 463INTERCEPTOR(CFStringRef, CFStringCreateCopy, CFAllocatorRef alloc, 464 CFStringRef str) { 465 if (__CFStrIsConstant(str)) { 466 return str; 467 } else { 468 return REAL(CFStringCreateCopy)(alloc, str); 469 } 470} 471 472namespace __asan { 473 474void InitializeMacInterceptors() { 475 CHECK(INTERCEPT_FUNCTION(dispatch_async_f)); 476 CHECK(INTERCEPT_FUNCTION(dispatch_sync_f)); 477 CHECK(INTERCEPT_FUNCTION(dispatch_after_f)); 478 CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f)); 479 CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f)); 480 // We don't need to intercept pthread_workqueue_additem_np() to support the 481 // libdispatch API, but it helps us to debug the unsupported functions. Let's 482 // intercept it only during verbose runs. 483 if (FLAG_v >= 2) { 484 CHECK(INTERCEPT_FUNCTION(pthread_workqueue_additem_np)); 485 } 486 // Normally CFStringCreateCopy should not copy constant CF strings. 487 // Replacing the default CFAllocator causes constant strings to be copied 488 // rather than just returned, which leads to bugs in big applications like 489 // Chromium and WebKit, see 490 // http://code.google.com/p/address-sanitizer/issues/detail?id=10 491 // Until this problem is fixed we need to check that the string is 492 // non-constant before calling CFStringCreateCopy. 493 CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy)); 494} 495 496} // namespace __asan 497 498#endif // __APPLE__ 499