1 //===-- sanitizer_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 shared between various sanitizers' runtime libraries and 11 // implements OSX-specific functions. 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_platform.h" 15 #if SANITIZER_MAC 16 #include "sanitizer_mac.h" 17 18 // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so 19 // the clients will most certainly use 64-bit ones as well. 20 #ifndef _DARWIN_USE_64_BIT_INODE 21 #define _DARWIN_USE_64_BIT_INODE 1 22 #endif 23 #include <stdio.h> 24 25 #include "sanitizer_common.h" 26 #include "sanitizer_flags.h" 27 #include "sanitizer_internal_defs.h" 28 #include "sanitizer_libc.h" 29 #include "sanitizer_placement_new.h" 30 #include "sanitizer_platform_limits_posix.h" 31 #include "sanitizer_procmaps.h" 32 33 #if !SANITIZER_IOS 34 #include <crt_externs.h> // for _NSGetEnviron 35 #else 36 extern char **environ; 37 #endif 38 39 #if defined(__has_include) && __has_include(<os/trace.h>) 40 #define SANITIZER_OS_TRACE 1 41 #include <os/trace.h> 42 #else 43 #define SANITIZER_OS_TRACE 0 44 #endif 45 46 #if !SANITIZER_IOS 47 #include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron 48 #else 49 extern "C" { 50 extern char ***_NSGetArgv(void); 51 } 52 #endif 53 54 #include <asl.h> 55 #include <dlfcn.h> // for dladdr() 56 #include <errno.h> 57 #include <fcntl.h> 58 #include <libkern/OSAtomic.h> 59 #include <mach-o/dyld.h> 60 #include <mach/mach.h> 61 #include <mach/vm_statistics.h> 62 #include <pthread.h> 63 #include <sched.h> 64 #include <signal.h> 65 #include <stdlib.h> 66 #include <sys/mman.h> 67 #include <sys/resource.h> 68 #include <sys/stat.h> 69 #include <sys/sysctl.h> 70 #include <sys/types.h> 71 #include <sys/wait.h> 72 #include <unistd.h> 73 #include <util.h> 74 75 // from <crt_externs.h>, but we don't have that file on iOS 76 extern "C" { 77 extern char ***_NSGetArgv(void); 78 extern char ***_NSGetEnviron(void); 79 } 80 81 namespace __sanitizer { 82 83 #include "sanitizer_syscall_generic.inc" 84 85 // Direct syscalls, don't call libmalloc hooks. 86 extern "C" void *__mmap(void *addr, size_t len, int prot, int flags, int fildes, 87 off_t off); 88 extern "C" int __munmap(void *, size_t); 89 90 // ---------------------- sanitizer_libc.h 91 uptr internal_mmap(void *addr, size_t length, int prot, int flags, 92 int fd, u64 offset) { 93 if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL); 94 return (uptr)__mmap(addr, length, prot, flags, fd, offset); 95 } 96 97 uptr internal_munmap(void *addr, uptr length) { 98 return __munmap(addr, length); 99 } 100 101 int internal_mprotect(void *addr, uptr length, int prot) { 102 return mprotect(addr, length, prot); 103 } 104 105 uptr internal_close(fd_t fd) { 106 return close(fd); 107 } 108 109 uptr internal_open(const char *filename, int flags) { 110 return open(filename, flags); 111 } 112 113 uptr internal_open(const char *filename, int flags, u32 mode) { 114 return open(filename, flags, mode); 115 } 116 117 uptr internal_read(fd_t fd, void *buf, uptr count) { 118 return read(fd, buf, count); 119 } 120 121 uptr internal_write(fd_t fd, const void *buf, uptr count) { 122 return write(fd, buf, count); 123 } 124 125 uptr internal_stat(const char *path, void *buf) { 126 return stat(path, (struct stat *)buf); 127 } 128 129 uptr internal_lstat(const char *path, void *buf) { 130 return lstat(path, (struct stat *)buf); 131 } 132 133 uptr internal_fstat(fd_t fd, void *buf) { 134 return fstat(fd, (struct stat *)buf); 135 } 136 137 uptr internal_filesize(fd_t fd) { 138 struct stat st; 139 if (internal_fstat(fd, &st)) 140 return -1; 141 return (uptr)st.st_size; 142 } 143 144 uptr internal_dup2(int oldfd, int newfd) { 145 return dup2(oldfd, newfd); 146 } 147 148 uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 149 return readlink(path, buf, bufsize); 150 } 151 152 uptr internal_unlink(const char *path) { 153 return unlink(path); 154 } 155 156 uptr internal_sched_yield() { 157 return sched_yield(); 158 } 159 160 void internal__exit(int exitcode) { 161 _exit(exitcode); 162 } 163 164 unsigned int internal_sleep(unsigned int seconds) { 165 return sleep(seconds); 166 } 167 168 uptr internal_getpid() { 169 return getpid(); 170 } 171 172 int internal_sigaction(int signum, const void *act, void *oldact) { 173 return sigaction(signum, 174 (struct sigaction *)act, (struct sigaction *)oldact); 175 } 176 177 void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); } 178 179 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, 180 __sanitizer_sigset_t *oldset) { 181 return sigprocmask(how, set, oldset); 182 } 183 184 // Doesn't call pthread_atfork() handlers. 185 extern "C" pid_t __fork(void); 186 187 int internal_fork() { 188 return __fork(); 189 } 190 191 int internal_forkpty(int *amaster) { 192 int master, slave; 193 if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1; 194 int pid = __fork(); 195 if (pid == -1) { 196 close(master); 197 close(slave); 198 return -1; 199 } 200 if (pid == 0) { 201 close(master); 202 if (login_tty(slave) != 0) { 203 // We already forked, there's not much we can do. Let's quit. 204 Report("login_tty failed (errno %d)\n", errno); 205 internal__exit(1); 206 } 207 } else { 208 *amaster = master; 209 close(slave); 210 } 211 return pid; 212 } 213 214 uptr internal_rename(const char *oldpath, const char *newpath) { 215 return rename(oldpath, newpath); 216 } 217 218 uptr internal_ftruncate(fd_t fd, uptr size) { 219 return ftruncate(fd, size); 220 } 221 222 uptr internal_execve(const char *filename, char *const argv[], 223 char *const envp[]) { 224 return execve(filename, argv, envp); 225 } 226 227 uptr internal_waitpid(int pid, int *status, int options) { 228 return waitpid(pid, status, options); 229 } 230 231 // ----------------- sanitizer_common.h 232 bool FileExists(const char *filename) { 233 struct stat st; 234 if (stat(filename, &st)) 235 return false; 236 // Sanity check: filename is a regular file. 237 return S_ISREG(st.st_mode); 238 } 239 240 uptr GetTid() { 241 // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes. 242 uint64_t tid; 243 pthread_threadid_np(nullptr, &tid); 244 return tid; 245 } 246 247 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 248 uptr *stack_bottom) { 249 CHECK(stack_top); 250 CHECK(stack_bottom); 251 uptr stacksize = pthread_get_stacksize_np(pthread_self()); 252 // pthread_get_stacksize_np() returns an incorrect stack size for the main 253 // thread on Mavericks. See 254 // https://github.com/google/sanitizers/issues/261 255 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && 256 stacksize == (1 << 19)) { 257 struct rlimit rl; 258 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0); 259 // Most often rl.rlim_cur will be the desired 8M. 260 if (rl.rlim_cur < kMaxThreadStackSize) { 261 stacksize = rl.rlim_cur; 262 } else { 263 stacksize = kMaxThreadStackSize; 264 } 265 } 266 void *stackaddr = pthread_get_stackaddr_np(pthread_self()); 267 *stack_top = (uptr)stackaddr; 268 *stack_bottom = *stack_top - stacksize; 269 } 270 271 char **GetEnviron() { 272 #if !SANITIZER_IOS 273 char ***env_ptr = _NSGetEnviron(); 274 if (!env_ptr) { 275 Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is " 276 "called after libSystem_initializer().\n"); 277 CHECK(env_ptr); 278 } 279 char **environ = *env_ptr; 280 #endif 281 CHECK(environ); 282 return environ; 283 } 284 285 const char *GetEnv(const char *name) { 286 char **env = GetEnviron(); 287 uptr name_len = internal_strlen(name); 288 while (*env != 0) { 289 uptr len = internal_strlen(*env); 290 if (len > name_len) { 291 const char *p = *env; 292 if (!internal_memcmp(p, name, name_len) && 293 p[name_len] == '=') { // Match. 294 return *env + name_len + 1; // String starting after =. 295 } 296 } 297 env++; 298 } 299 return 0; 300 } 301 302 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 303 CHECK_LE(kMaxPathLength, buf_len); 304 305 // On OS X the executable path is saved to the stack by dyld. Reading it 306 // from there is much faster than calling dladdr, especially for large 307 // binaries with symbols. 308 InternalScopedString exe_path(kMaxPathLength); 309 uint32_t size = exe_path.size(); 310 if (_NSGetExecutablePath(exe_path.data(), &size) == 0 && 311 realpath(exe_path.data(), buf) != 0) { 312 return internal_strlen(buf); 313 } 314 return 0; 315 } 316 317 uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { 318 return ReadBinaryName(buf, buf_len); 319 } 320 321 void ReExec() { 322 UNIMPLEMENTED(); 323 } 324 325 uptr GetPageSize() { 326 return sysconf(_SC_PAGESIZE); 327 } 328 329 BlockingMutex::BlockingMutex() { 330 internal_memset(this, 0, sizeof(*this)); 331 } 332 333 void BlockingMutex::Lock() { 334 CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); 335 CHECK_EQ(OS_SPINLOCK_INIT, 0); 336 CHECK_NE(owner_, (uptr)pthread_self()); 337 OSSpinLockLock((OSSpinLock*)&opaque_storage_); 338 CHECK(!owner_); 339 owner_ = (uptr)pthread_self(); 340 } 341 342 void BlockingMutex::Unlock() { 343 CHECK(owner_ == (uptr)pthread_self()); 344 owner_ = 0; 345 OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); 346 } 347 348 void BlockingMutex::CheckLocked() { 349 CHECK_EQ((uptr)pthread_self(), owner_); 350 } 351 352 u64 NanoTime() { 353 return 0; 354 } 355 356 uptr GetTlsSize() { 357 return 0; 358 } 359 360 void InitTlsSize() { 361 } 362 363 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 364 uptr *tls_addr, uptr *tls_size) { 365 #ifndef SANITIZER_GO 366 uptr stack_top, stack_bottom; 367 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 368 *stk_addr = stack_bottom; 369 *stk_size = stack_top - stack_bottom; 370 *tls_addr = 0; 371 *tls_size = 0; 372 #else 373 *stk_addr = 0; 374 *stk_size = 0; 375 *tls_addr = 0; 376 *tls_size = 0; 377 #endif 378 } 379 380 void ListOfModules::init() { 381 clear(); 382 MemoryMappingLayout memory_mapping(false); 383 memory_mapping.DumpListOfModules(&modules_); 384 } 385 386 bool IsHandledDeadlySignal(int signum) { 387 if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM)) 388 // Handling fatal signals on watchOS and tvOS devices is disallowed. 389 return false; 390 return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; 391 } 392 393 MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED; 394 395 MacosVersion GetMacosVersionInternal() { 396 int mib[2] = { CTL_KERN, KERN_OSRELEASE }; 397 char version[100]; 398 uptr len = 0, maxlen = sizeof(version) / sizeof(version[0]); 399 for (uptr i = 0; i < maxlen; i++) version[i] = '\0'; 400 // Get the version length. 401 CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1); 402 CHECK_LT(len, maxlen); 403 CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1); 404 switch (version[0]) { 405 case '9': return MACOS_VERSION_LEOPARD; 406 case '1': { 407 switch (version[1]) { 408 case '0': return MACOS_VERSION_SNOW_LEOPARD; 409 case '1': return MACOS_VERSION_LION; 410 case '2': return MACOS_VERSION_MOUNTAIN_LION; 411 case '3': return MACOS_VERSION_MAVERICKS; 412 case '4': return MACOS_VERSION_YOSEMITE; 413 default: 414 if (IsDigit(version[1])) 415 return MACOS_VERSION_UNKNOWN_NEWER; 416 else 417 return MACOS_VERSION_UNKNOWN; 418 } 419 } 420 default: return MACOS_VERSION_UNKNOWN; 421 } 422 } 423 424 MacosVersion GetMacosVersion() { 425 atomic_uint32_t *cache = 426 reinterpret_cast<atomic_uint32_t*>(&cached_macos_version); 427 MacosVersion result = 428 static_cast<MacosVersion>(atomic_load(cache, memory_order_acquire)); 429 if (result == MACOS_VERSION_UNINITIALIZED) { 430 result = GetMacosVersionInternal(); 431 atomic_store(cache, result, memory_order_release); 432 } 433 return result; 434 } 435 436 uptr GetRSS() { 437 struct task_basic_info info; 438 unsigned count = TASK_BASIC_INFO_COUNT; 439 kern_return_t result = 440 task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &count); 441 if (UNLIKELY(result != KERN_SUCCESS)) { 442 Report("Cannot get task info. Error: %d\n", result); 443 Die(); 444 } 445 return info.resident_size; 446 } 447 448 void *internal_start_thread(void(*func)(void *arg), void *arg) { 449 // Start the thread with signals blocked, otherwise it can steal user signals. 450 __sanitizer_sigset_t set, old; 451 internal_sigfillset(&set); 452 internal_sigprocmask(SIG_SETMASK, &set, &old); 453 pthread_t th; 454 pthread_create(&th, 0, (void*(*)(void *arg))func, arg); 455 internal_sigprocmask(SIG_SETMASK, &old, 0); 456 return th; 457 } 458 459 void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } 460 461 #ifndef SANITIZER_GO 462 static BlockingMutex syslog_lock(LINKER_INITIALIZED); 463 #endif 464 465 void WriteOneLineToSyslog(const char *s) { 466 #ifndef SANITIZER_GO 467 syslog_lock.CheckLocked(); 468 asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); 469 #endif 470 } 471 472 void LogMessageOnPrintf(const char *str) { 473 // Log all printf output to CrashLog. 474 if (common_flags()->abort_on_error) 475 CRAppendCrashLogMessage(str); 476 } 477 478 void LogFullErrorReport(const char *buffer) { 479 #ifndef SANITIZER_GO 480 // Log with os_trace. This will make it into the crash log. 481 #if SANITIZER_OS_TRACE 482 if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { 483 // os_trace requires the message (format parameter) to be a string literal. 484 if (internal_strncmp(SanitizerToolName, "AddressSanitizer", 485 sizeof("AddressSanitizer") - 1) == 0) 486 os_trace("Address Sanitizer reported a failure."); 487 else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", 488 sizeof("UndefinedBehaviorSanitizer") - 1) == 0) 489 os_trace("Undefined Behavior Sanitizer reported a failure."); 490 else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", 491 sizeof("ThreadSanitizer") - 1) == 0) 492 os_trace("Thread Sanitizer reported a failure."); 493 else 494 os_trace("Sanitizer tool reported a failure."); 495 496 if (common_flags()->log_to_syslog) 497 os_trace("Consult syslog for more information."); 498 } 499 #endif 500 501 // Log to syslog. 502 // The logging on OS X may call pthread_create so we need the threading 503 // environment to be fully initialized. Also, this should never be called when 504 // holding the thread registry lock since that may result in a deadlock. If 505 // the reporting thread holds the thread registry mutex, and asl_log waits 506 // for GCD to dispatch a new thread, the process will deadlock, because the 507 // pthread_create wrapper needs to acquire the lock as well. 508 BlockingMutexLock l(&syslog_lock); 509 if (common_flags()->log_to_syslog) 510 WriteToSyslog(buffer); 511 512 // The report is added to CrashLog as part of logging all of Printf output. 513 #endif 514 } 515 516 SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) { 517 #if defined(__x86_64__) || defined(__i386__) 518 ucontext_t *ucontext = static_cast<ucontext_t*>(context); 519 return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ; 520 #else 521 return UNKNOWN; 522 #endif 523 } 524 525 void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { 526 ucontext_t *ucontext = (ucontext_t*)context; 527 # if defined(__aarch64__) 528 *pc = ucontext->uc_mcontext->__ss.__pc; 529 # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 530 *bp = ucontext->uc_mcontext->__ss.__fp; 531 # else 532 *bp = ucontext->uc_mcontext->__ss.__lr; 533 # endif 534 *sp = ucontext->uc_mcontext->__ss.__sp; 535 # elif defined(__x86_64__) 536 *pc = ucontext->uc_mcontext->__ss.__rip; 537 *bp = ucontext->uc_mcontext->__ss.__rbp; 538 *sp = ucontext->uc_mcontext->__ss.__rsp; 539 # elif defined(__arm__) 540 *pc = ucontext->uc_mcontext->__ss.__pc; 541 *bp = ucontext->uc_mcontext->__ss.__r[7]; 542 *sp = ucontext->uc_mcontext->__ss.__sp; 543 # elif defined(__i386__) 544 *pc = ucontext->uc_mcontext->__ss.__eip; 545 *bp = ucontext->uc_mcontext->__ss.__ebp; 546 *sp = ucontext->uc_mcontext->__ss.__esp; 547 # else 548 # error "Unknown architecture" 549 # endif 550 } 551 552 #ifndef SANITIZER_GO 553 static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; 554 LowLevelAllocator allocator_for_env; 555 556 // Change the value of the env var |name|, leaking the original value. 557 // If |name_value| is NULL, the variable is deleted from the environment, 558 // otherwise the corresponding "NAME=value" string is replaced with 559 // |name_value|. 560 void LeakyResetEnv(const char *name, const char *name_value) { 561 char **env = GetEnviron(); 562 uptr name_len = internal_strlen(name); 563 while (*env != 0) { 564 uptr len = internal_strlen(*env); 565 if (len > name_len) { 566 const char *p = *env; 567 if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { 568 // Match. 569 if (name_value) { 570 // Replace the old value with the new one. 571 *env = const_cast<char*>(name_value); 572 } else { 573 // Shift the subsequent pointers back. 574 char **del = env; 575 do { 576 del[0] = del[1]; 577 } while (*del++); 578 } 579 } 580 } 581 env++; 582 } 583 } 584 585 SANITIZER_WEAK_CXX_DEFAULT_IMPL 586 bool ReexecDisabled() { 587 return false; 588 } 589 590 extern "C" SANITIZER_WEAK_ATTRIBUTE double dyldVersionNumber; 591 static const double kMinDyldVersionWithAutoInterposition = 360.0; 592 593 bool DyldNeedsEnvVariable() { 594 // Although sanitizer support was added to LLVM on OS X 10.7+, GCC users 595 // still may want use them on older systems. On older Darwin platforms, dyld 596 // doesn't export dyldVersionNumber symbol and we simply return true. 597 if (!&dyldVersionNumber) return true; 598 // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if 599 // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via 600 // GetMacosVersion() doesn't work for the simulator. Let's instead check 601 // `dyldVersionNumber`, which is exported by dyld, against a known version 602 // number from the first OS release where this appeared. 603 return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; 604 } 605 606 void MaybeReexec() { 607 if (ReexecDisabled()) return; 608 609 // Make sure the dynamic runtime library is preloaded so that the 610 // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec 611 // ourselves. 612 Dl_info info; 613 RAW_CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); 614 char *dyld_insert_libraries = 615 const_cast<char*>(GetEnv(kDyldInsertLibraries)); 616 uptr old_env_len = dyld_insert_libraries ? 617 internal_strlen(dyld_insert_libraries) : 0; 618 uptr fname_len = internal_strlen(info.dli_fname); 619 const char *dylib_name = StripModuleName(info.dli_fname); 620 uptr dylib_name_len = internal_strlen(dylib_name); 621 622 bool lib_is_in_env = dyld_insert_libraries && 623 internal_strstr(dyld_insert_libraries, dylib_name); 624 if (DyldNeedsEnvVariable() && !lib_is_in_env) { 625 // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime 626 // library. 627 InternalScopedString program_name(1024); 628 uint32_t buf_size = program_name.size(); 629 _NSGetExecutablePath(program_name.data(), &buf_size); 630 char *new_env = const_cast<char*>(info.dli_fname); 631 if (dyld_insert_libraries) { 632 // Append the runtime dylib name to the existing value of 633 // DYLD_INSERT_LIBRARIES. 634 new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); 635 internal_strncpy(new_env, dyld_insert_libraries, old_env_len); 636 new_env[old_env_len] = ':'; 637 // Copy fname_len and add a trailing zero. 638 internal_strncpy(new_env + old_env_len + 1, info.dli_fname, 639 fname_len + 1); 640 // Ok to use setenv() since the wrappers don't depend on the value of 641 // asan_inited. 642 setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); 643 } else { 644 // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. 645 setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); 646 } 647 VReport(1, "exec()-ing the program with\n"); 648 VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); 649 VReport(1, "to enable wrappers.\n"); 650 execv(program_name.data(), *_NSGetArgv()); 651 652 // We get here only if execv() failed. 653 Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " 654 "which is required for the sanitizer to work. We tried to set the " 655 "environment variable and re-execute itself, but execv() failed, " 656 "possibly because of sandbox restrictions. Make sure to launch the " 657 "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); 658 RAW_CHECK("execv failed" && 0); 659 } 660 661 // Verify that interceptors really work. We'll use dlsym to locate 662 // "pthread_create", if interceptors are working, it should really point to 663 // "wrap_pthread_create" within our own dylib. 664 Dl_info info_pthread_create; 665 void *dlopen_addr = dlsym(RTLD_DEFAULT, "pthread_create"); 666 RAW_CHECK(dladdr(dlopen_addr, &info_pthread_create)); 667 if (internal_strcmp(info.dli_fname, info_pthread_create.dli_fname) != 0) { 668 Report( 669 "ERROR: Interceptors are not working. This may be because %s is " 670 "loaded too late (e.g. via dlopen). Please launch the executable " 671 "with:\n%s=%s\n", 672 SanitizerToolName, kDyldInsertLibraries, info.dli_fname); 673 RAW_CHECK("interceptors not installed" && 0); 674 } 675 676 if (!lib_is_in_env) 677 return; 678 679 // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove 680 // the dylib from the environment variable, because interceptors are installed 681 // and we don't want our children to inherit the variable. 682 683 uptr env_name_len = internal_strlen(kDyldInsertLibraries); 684 // Allocate memory to hold the previous env var name, its value, the '=' 685 // sign and the '\0' char. 686 char *new_env = (char*)allocator_for_env.Allocate( 687 old_env_len + 2 + env_name_len); 688 RAW_CHECK(new_env); 689 internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); 690 internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); 691 new_env[env_name_len] = '='; 692 char *new_env_pos = new_env + env_name_len + 1; 693 694 // Iterate over colon-separated pieces of |dyld_insert_libraries|. 695 char *piece_start = dyld_insert_libraries; 696 char *piece_end = NULL; 697 char *old_env_end = dyld_insert_libraries + old_env_len; 698 do { 699 if (piece_start[0] == ':') piece_start++; 700 piece_end = internal_strchr(piece_start, ':'); 701 if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; 702 if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; 703 uptr piece_len = piece_end - piece_start; 704 705 char *filename_start = 706 (char *)internal_memrchr(piece_start, '/', piece_len); 707 uptr filename_len = piece_len; 708 if (filename_start) { 709 filename_start += 1; 710 filename_len = piece_len - (filename_start - piece_start); 711 } else { 712 filename_start = piece_start; 713 } 714 715 // If the current piece isn't the runtime library name, 716 // append it to new_env. 717 if ((dylib_name_len != filename_len) || 718 (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { 719 if (new_env_pos != new_env + env_name_len + 1) { 720 new_env_pos[0] = ':'; 721 new_env_pos++; 722 } 723 internal_strncpy(new_env_pos, piece_start, piece_len); 724 new_env_pos += piece_len; 725 } 726 // Move on to the next piece. 727 piece_start = piece_end; 728 } while (piece_start < old_env_end); 729 730 // Can't use setenv() here, because it requires the allocator to be 731 // initialized. 732 // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in 733 // a separate function called after InitializeAllocator(). 734 if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; 735 LeakyResetEnv(kDyldInsertLibraries, new_env); 736 } 737 #endif // SANITIZER_GO 738 739 char **GetArgv() { 740 return *_NSGetArgv(); 741 } 742 743 } // namespace __sanitizer 744 745 #endif // SANITIZER_MAC 746