Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -106,8 +106,6 @@ void *AsanDlSymNext(const char *sym); -void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); - // Add convenient macro for interface functions that may be represented as // weak hooks. #define ASAN_MALLOC_HOOK(ptr, size) \ Index: lib/asan/asan_poisoning.h =================================================================== --- lib/asan/asan_poisoning.h +++ lib/asan/asan_poisoning.h @@ -64,7 +64,7 @@ if (page_end != shadow_end) { REAL(memset)((void *)page_end, 0, shadow_end - page_end); } - ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); + MmapFixedNoReserveAllowOverwrite(page_beg, page_end - page_beg); } } } Index: lib/asan/asan_shadow_setup.cc =================================================================== --- lib/asan/asan_shadow_setup.cc +++ lib/asan/asan_shadow_setup.cc @@ -24,7 +24,6 @@ CHECK_EQ((beg % GetMmapGranularity()), 0); CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); uptr size = end - beg + 1; - DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. void *res = MmapFixedNoReserve(beg, size, name); if (res != (void *)beg) { Report( Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -88,14 +88,26 @@ // Behaves just like MmapOrDie, but tolerates out of memory condition, in that // case returns nullptr. void *MmapOrDieOnFatalError(uptr size, const char *mem_type); +// Maps the specified memory region with "NORESERVE". Fails if any part of the +// memory region is already used. On success returns 'fixed_addr'. void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); +// Same as MmapFixedNoReserve, but doesn't fail when the memory region or a part +// of it is already used, instead overwrites any existing mapping. +void *MmapFixedNoReserveAllowOverwrite(uptr fixed_addr, uptr size, + const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size); // Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in // that case returns nullptr. void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size); +// Maps the specified memory region and disallows any access to it. Fails if any +// part of the memory region is already used. On success returns 'fixed_addr'. void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); +// Same as MmapFixedNoAccess, but doesn't fail when the memory region or a part +// of it is already used, instead overwrites any existing mapping. +void *MmapFixedNoAccessAllowOverwrite(uptr fixed_addr, uptr size, + const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. // Dies on all but out of memory errors, in the latter case returns nullptr. Index: lib/sanitizer_common/sanitizer_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -558,6 +558,66 @@ #endif // SANITIZER_LINUX +#if SANITIZER_ANDROID || SANITIZER_GO +int GetNamedMappingFd(const char *name, uptr size) { + return -1; +} +#else +int GetNamedMappingFd(const char *name, uptr size) { + if (!common_flags()->decorate_proc_maps) + return -1; + char shmname[200]; + CHECK(internal_strlen(name) < sizeof(shmname) - 10); + internal_snprintf(shmname, sizeof(shmname), "%zu [%s]", internal_getpid(), + name); + int fd = shm_open(shmname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); + CHECK_GE(fd, 0); + int res = internal_ftruncate(fd, size); + CHECK_EQ(0, res); + res = shm_unlink(shmname); + CHECK_EQ(0, res); + return fd; +} +#endif + +void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + // FIXME: This should disallow overwriting already existing mappings. + return MmapFixedNoReserveAllowOverwrite(fixed_addr, size, name); +} + +void *MmapFixedNoReserveAllowOverwrite(uptr fixed_addr, uptr size, + const char *name = nullptr) { + int fd = name ? GetNamedMappingFd(name, size) : -1; + unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; + 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); + int reserrno; + if (internal_iserror(p, &reserrno)) + Report("ERROR: %s failed to " + "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", + SanitizerToolName, size, size, fixed_addr, reserrno); + return (void *)p; +} + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + // FIXME: This should disallow overwriting already existing mappings. + return MmapFixedNoAccessAllowOverwrite(fixed_addr, size, name); +} + +void *MmapFixedNoAccessAllowOverwrite(uptr fixed_addr, uptr size, + const char *name = nullptr) { + int fd = name ? GetNamedMappingFd(name, size) : -1; + 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); +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX Index: lib/sanitizer_common/sanitizer_mac_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_mac_libcdep.cc +++ lib/sanitizer_common/sanitizer_mac_libcdep.cc @@ -15,6 +15,7 @@ #if SANITIZER_MAC #include "sanitizer_mac.h" +#include #include namespace __sanitizer { @@ -25,6 +26,52 @@ CHECK(res != MAP_FAILED); } +static void *DarwinMmapFixed(uptr fixed_addr, uptr size, int flags, + bool noaccess = false) { + uptr PageSize = GetPageSizeCached(); + vm_address_t p = (vm_address_t)(fixed_addr & ~(PageSize - 1)); + size = RoundUpTo(size, PageSize); + flags |= VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL); + kern_return_t r = vm_allocate(mach_task_self(), &p, size, flags); + if (r != KERN_SUCCESS) { + Report( + "ERROR: %s failed to allocate 0x%zx (%zd) bytes at address %zx " + "(vm_allocate returned: 0x%zx)\n", + SanitizerToolName, size, size, p, (uptr)r); + return 0; + } + if (noaccess) { + r = vm_protect(mach_task_self(), p, size, 0, VM_PROT_NONE); + if (r != KERN_SUCCESS) { + Report( + "ERROR: %s failed to vm_protect 0x%zx (%zd) bytes at address %zx " + "(vm_protect returned: 0x%zx)\n", + SanitizerToolName, size, size, p, (uptr)r); + return 0; + } + } + return (void *)p; +} + +void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { + return DarwinMmapFixed(fixed_addr, size, 0); +} + +void *MmapFixedNoReserveAllowOverwrite(uptr fixed_addr, uptr size, + const char *name) { + return DarwinMmapFixed(fixed_addr, size, VM_FLAGS_OVERWRITE); +} + +void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { + return DarwinMmapFixed(fixed_addr, size, 0, /*noaccess*/ true); +} + +void *MmapFixedNoAccessAllowOverwrite(uptr fixed_addr, uptr size, + const char *name) { + return DarwinMmapFixed(fixed_addr, size, VM_FLAGS_OVERWRITE, + /*noaccess*/ true); +} + } // namespace __sanitizer #endif // SANITIZER_MAC Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -249,55 +249,6 @@ #endif } -#if SANITIZER_ANDROID || SANITIZER_GO -int GetNamedMappingFd(const char *name, uptr size) { - return -1; -} -#else -int GetNamedMappingFd(const char *name, uptr size) { - if (!common_flags()->decorate_proc_maps) - return -1; - char shmname[200]; - CHECK(internal_strlen(name) < sizeof(shmname) - 10); - internal_snprintf(shmname, sizeof(shmname), "%zu [%s]", internal_getpid(), - name); - int fd = shm_open(shmname, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); - CHECK_GE(fd, 0); - int res = internal_ftruncate(fd, size); - CHECK_EQ(0, res); - res = shm_unlink(shmname); - CHECK_EQ(0, res); - return fd; -} -#endif - -void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { - int fd = name ? GetNamedMappingFd(name, size) : -1; - unsigned flags = MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE; - 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); - int reserrno; - if (internal_iserror(p, &reserrno)) - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", - SanitizerToolName, size, size, fixed_addr, reserrno); - IncreaseTotalMmap(size); - return (void *)p; -} - -void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { - int fd = name ? GetNamedMappingFd(name, size) : -1; - 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); -} - void *MmapNoAccess(uptr size) { unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0); Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -222,6 +222,12 @@ return p; } +void *MmapFixedNoReserveAllowOverwrite(uptr fixed_addr, uptr size, + const char *name) { + // FIXME: This should actually allow overwriting existing memory. + return MmapFixedNoReserve(fixed_addr, size, name); +} + // Memory space mapped by 'MmapFixedOrDie' must have been reserved by // 'MmapFixedNoAccess'. void *MmapFixedOrDie(uptr fixed_addr, uptr size) { @@ -264,6 +270,12 @@ return res; } +void *MmapFixedNoAccessAllowOverwrite(uptr fixed_addr, uptr size, + const char *name) { + // FIXME: This should actually allow overwriting existing memory. + return MmapFixedNoAccess(fixed_addr, size, name); +} + void *MmapNoAccess(uptr size) { void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS); if (res == 0) Index: lib/tsan/go/buildgo.sh =================================================================== --- lib/tsan/go/buildgo.sh +++ lib/tsan/go/buildgo.sh @@ -76,6 +76,7 @@ $SRCS ../rtl/tsan_platform_mac.cc ../../sanitizer_common/sanitizer_mac.cc + ../../sanitizer_common/sanitizer_mac_libcdep.cc ../../sanitizer_common/sanitizer_posix.cc ../../sanitizer_common/sanitizer_posix_libcdep.cc ../../sanitizer_common/sanitizer_procmaps_mac.cc