Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -420,6 +420,8 @@ __asan_option_detect_stack_use_after_return = flags()->detect_stack_use_after_return; + __sanitizer::InitializePlatformEarly(); + // Re-exec ourselves if we need to set additional env or command line args. MaybeReexec(); Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -896,6 +896,7 @@ bool IsMemoryAccess() const; }; +void InitializePlatformEarly(); void MaybeReexec(); template Index: lib/sanitizer_common/sanitizer_fuchsia.cc =================================================================== --- lib/sanitizer_common/sanitizer_fuchsia.cc +++ lib/sanitizer_common/sanitizer_fuchsia.cc @@ -89,6 +89,7 @@ *stack_top = *stack_bottom + size; } +void InitializePlatformEarly() {} void MaybeReexec() {} void CheckASLR() {} void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} Index: lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux.cc +++ lib/sanitizer_common/sanitizer_linux.cc @@ -186,7 +186,11 @@ offset / 4096); #endif } -#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD +uptr internal_mmap_shadow(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { + return internal_mmap(addr, length, prot, flags, fd, offset); +} +#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD #if !SANITIZER_OPENBSD uptr internal_munmap(void *addr, uptr length) { @@ -1950,6 +1954,10 @@ void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +void InitializePlatformEarly() { + // Do nothing. +} + void MaybeReexec() { // No need to re-exec on Linux. } Index: lib/sanitizer_common/sanitizer_linux_s390.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux_s390.cc +++ lib/sanitizer_common/sanitizer_linux_s390.cc @@ -55,6 +55,11 @@ # endif } +uptr internal_mmap_shadow(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { + return internal_mmap(addr, length, prot, flags, fd, offset); +} + uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr) { if (!fn || !child_stack) Index: lib/sanitizer_common/sanitizer_mac.h =================================================================== --- lib/sanitizer_common/sanitizer_mac.h +++ lib/sanitizer_common/sanitizer_mac.h @@ -40,6 +40,10 @@ MACOS_VERSION_MOUNTAIN_LION, MACOS_VERSION_MAVERICKS, MACOS_VERSION_YOSEMITE, + MACOS_VERSION_EL_CAPITAN, + MACOS_VERSION_SIERRA, + MACOS_VERSION_HIGH_SIERRA, + MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4, MACOS_VERSION_UNKNOWN_NEWER }; Index: lib/sanitizer_common/sanitizer_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac.cc +++ lib/sanitizer_common/sanitizer_mac.cc @@ -115,6 +115,21 @@ return (uptr)mmap(addr, length, prot, flags, fd, offset); } +// XNU on Darwin provides a mmap flag that optimizes allocation/deallocation of +// giant memory regions (i.e. shadow memory regions). +#define kXnuFastMmapFd 0x4 +static bool use_xnu_fast_mmap = false; + +uptr internal_mmap_shadow(void *addr, size_t length, int prot, int flags, + int fd, u64 offset) { + if (fd == -1) { + int fd = VM_MAKE_TAG(VM_MEMORY_SANITIZER); + if (use_xnu_fast_mmap) fd |= kXnuFastMmapFd; + } + if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset); + return (uptr)mmap(addr, length, prot, flags, fd, offset); +} + uptr internal_munmap(void *addr, uptr length) { if (&__munmap) return __munmap(addr, length); return munmap(addr, length); @@ -502,23 +517,33 @@ CHECK_NE(sysctl(mib, 2, 0, &len, 0, 0), -1); CHECK_LT(len, maxlen); CHECK_NE(sysctl(mib, 2, version, &len, 0, 0), -1); - switch (version[0]) { - case '9': return MACOS_VERSION_LEOPARD; - case '1': { - switch (version[1]) { - case '0': return MACOS_VERSION_SNOW_LEOPARD; - case '1': return MACOS_VERSION_LION; - case '2': return MACOS_VERSION_MOUNTAIN_LION; - case '3': return MACOS_VERSION_MAVERICKS; - case '4': return MACOS_VERSION_YOSEMITE; - default: - if (IsDigit(version[1])) - return MACOS_VERSION_UNKNOWN_NEWER; - else - return MACOS_VERSION_UNKNOWN; - } - } - default: return MACOS_VERSION_UNKNOWN; + + // Expect .(.) + CHECK_GE(len, 3); + const char *p = version; + int major = internal_simple_strtoll(p, &p, /*base=*/10); + if (*p != '.') return MACOS_VERSION_UNKNOWN; + p += 1; + int minor = internal_simple_strtoll(p, &p, /*base=*/10); + if (*p != '.') return MACOS_VERSION_UNKNOWN; + + switch (major) { + case 9: return MACOS_VERSION_LEOPARD; + case 10: return MACOS_VERSION_SNOW_LEOPARD; + case 11: return MACOS_VERSION_LION; + case 12: return MACOS_VERSION_MOUNTAIN_LION; + case 13: return MACOS_VERSION_MAVERICKS; + case 14: return MACOS_VERSION_YOSEMITE; + case 15: return MACOS_VERSION_EL_CAPITAN; + case 16: return MACOS_VERSION_SIERRA; + case 17: + // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4. + if (minor >= 5) + return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; + return MACOS_VERSION_HIGH_SIERRA; + default: + if (major < 9) return MACOS_VERSION_UNKNOWN; + return MACOS_VERSION_UNKNOWN_NEWER; } } @@ -661,6 +686,16 @@ void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +void InitializePlatformEarly() { + // Only use xnu_fast_mmap when on x86_64 and the OS supports it. + use_xnu_fast_mmap = +#if defined(__x86_64__) + GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; +#else + false; +#endif +} + #if !SANITIZER_GO static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; LowLevelAllocator allocator_for_env; Index: lib/sanitizer_common/sanitizer_openbsd.cc =================================================================== --- lib/sanitizer_common/sanitizer_openbsd.cc +++ lib/sanitizer_common/sanitizer_openbsd.cc @@ -45,6 +45,11 @@ return (uptr)mmap(addr, length, prot, flags, fd, offset); } +uptr internal_mmap_shadow(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset) { + return internal_mmap(addr, length, prot, flags, fd, offset); +} + uptr internal_munmap(void *addr, uptr length) { return munmap(addr, length); } int internal_mprotect(void *addr, uptr length, int prot) { Index: lib/sanitizer_common/sanitizer_posix.h =================================================================== --- lib/sanitizer_common/sanitizer_posix.h +++ lib/sanitizer_common/sanitizer_posix.h @@ -38,8 +38,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count); // Memory -uptr internal_mmap(void *addr, uptr length, int prot, int flags, - int fd, OFF_T offset); +uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset); +uptr internal_mmap_shadow(void *addr, uptr length, int prot, int flags, int fd, + OFF_T offset); uptr internal_munmap(void *addr, uptr length); int internal_mprotect(void *addr, uptr length, int prot); Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -334,9 +334,9 @@ if (fd == -1) flags |= MAP_ANON; uptr PageSize = GetPageSizeCached(); - uptr p = internal_mmap((void *)(fixed_addr & ~(PageSize - 1)), - RoundUpTo(size, PageSize), PROT_READ | PROT_WRITE, - flags, fd, 0); + uptr p = internal_mmap_shadow((void *)(fixed_addr & ~(PageSize - 1)), + RoundUpTo(size, PageSize), + PROT_READ | PROT_WRITE, flags, fd, 0); int reserrno; if (internal_iserror(p, &reserrno)) { Report("ERROR: %s failed to " @@ -387,8 +387,8 @@ unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; if (fd == -1) flags |= MAP_ANON; - return (void *)internal_mmap((void *)fixed_addr, size, PROT_NONE, flags, fd, - 0); + return (void *)internal_mmap_shadow((void *)fixed_addr, size, PROT_NONE, + flags, fd, 0); } void *MmapNoAccess(uptr size) { Index: lib/sanitizer_common/sanitizer_rtems.cc =================================================================== --- lib/sanitizer_common/sanitizer_rtems.cc +++ lib/sanitizer_common/sanitizer_rtems.cc @@ -95,6 +95,7 @@ *tls_addr = *tls_size = 0; } +void InitializePlatformEarly() {} void MaybeReexec() {} void CheckASLR() {} void DisableCoreDumperIfNecessary() {} Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -1025,6 +1025,10 @@ // Do nothing. } +void InitializePlatformEarly() { + // Do nothing. +} + void MaybeReexec() { // No need to re-exec on Windows. } Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -359,7 +359,9 @@ CheckASLR(); InitializeFlags(&ctx->flags, options); AvoidCVE_2016_2143(); - InitializePlatformEarly(); + __sanitizer::InitializePlatformEarly(); + __tsan::InitializePlatformEarly(); + #if !SANITIZER_GO // Re-exec ourselves if we need to set additional env or command line args. MaybeReexec();