Index: cmake/config-ix.cmake =================================================================== --- cmake/config-ix.cmake +++ cmake/config-ix.cmake @@ -62,6 +62,7 @@ # Libraries. check_library_exists(c printf "" COMPILER_RT_HAS_LIBC) check_library_exists(dl dlopen "" COMPILER_RT_HAS_LIBDL) +check_library_exists(rt shm_open "" COMPILER_RT_HAS_LIBRT) check_library_exists(m pow "" COMPILER_RT_HAS_LIBM) check_library_exists(pthread pthread_create "" COMPILER_RT_HAS_LIBPTHREAD) check_library_exists(stdc++ __cxa_throw "" COMPILER_RT_HAS_LIBSTDCXX) Index: lib/asan/CMakeLists.txt =================================================================== --- lib/asan/CMakeLists.txt +++ lib/asan/CMakeLists.txt @@ -66,6 +66,7 @@ append_list_if(COMPILER_RT_HAS_LIBC c ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBDL dl ASAN_DYNAMIC_LIBS) +append_list_if(COMPILER_RT_HAS_LIBRT rt ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBM m ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD pthread ASAN_DYNAMIC_LIBS) append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ ASAN_DYNAMIC_LIBS) Index: lib/asan/asan_internal.h =================================================================== --- lib/asan/asan_internal.h +++ lib/asan/asan_internal.h @@ -93,7 +93,7 @@ void *AsanDlSymNext(const char *sym); -void ReserveShadowMemoryRange(uptr beg, uptr end); +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name); // Platform-specific options. #if SANITIZER_MAC 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); + ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr); } } } Index: lib/asan/asan_rtl.cc =================================================================== --- lib/asan/asan_rtl.cc +++ lib/asan/asan_rtl.cc @@ -89,12 +89,12 @@ // ---------------------- mmap -------------------- {{{1 // Reserve memory range [beg, end]. // We need to use inclusive range because end+1 may not be representable. -void ReserveShadowMemoryRange(uptr beg, uptr end) { +void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { CHECK_EQ((beg % GetPageSizeCached()), 0); CHECK_EQ(((end + 1) % GetPageSizeCached()), 0); uptr size = end - beg + 1; DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. - void *res = MmapFixedNoReserve(beg, size); + void *res = MmapFixedNoReserve(beg, size, name); if (res != (void*)beg) { Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " "Perhaps you're using ulimit -v\n", size); @@ -298,7 +298,7 @@ } static void ProtectGap(uptr addr, uptr size) { - void *res = MmapNoAccess(addr, size); + void *res = MmapNoAccess(addr, size, "shadow gap"); if (addr == (uptr)res) return; Report("ERROR: Failed to protect the shadow gap. " @@ -422,9 +422,9 @@ if (full_shadow_is_available) { // mmap the low shadow plus at least one page at the left. if (kLowShadowBeg) - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); // protect the gap. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1); @@ -433,11 +433,11 @@ MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) { CHECK(kLowShadowBeg != kLowShadowEnd); // mmap the low shadow plus at least one page at the left. - ReserveShadowMemoryRange(shadow_start, kLowShadowEnd); + ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow"); // mmap the mid shadow. - ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd); + ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow"); // mmap the high shadow. - ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd); + ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow"); // protect the gaps. ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1); ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1); Index: lib/asan/tests/CMakeLists.txt =================================================================== --- lib/asan/tests/CMakeLists.txt +++ lib/asan/tests/CMakeLists.txt @@ -99,6 +99,7 @@ set(ASAN_UNITTEST_NOINST_LINKFLAGS ${ASAN_UNITTEST_COMMON_LINKFLAGS}) append_list_if(COMPILER_RT_HAS_LIBM -lm ASAN_UNITTEST_NOINST_LINKFLAGS) append_list_if(COMPILER_RT_HAS_LIBDL -ldl ASAN_UNITTEST_NOINST_LINKFLAGS) +append_list_if(COMPILER_RT_HAS_LIBRT -lrt ASAN_UNITTEST_NOINST_LINKFLAGS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_UNITTEST_NOINST_LINKFLAGS) append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread ASAN_DYNAMIC_UNITTEST_INSTRUMENTED_LINKFLAGS) Index: lib/msan/msan_linux.cc =================================================================== --- lib/msan/msan_linux.cc +++ lib/msan/msan_linux.cc @@ -53,16 +53,16 @@ return true; } -static bool ProtectMemoryRange(uptr beg, uptr size) { +static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { if (size > 0) { - void *addr = MmapNoAccess(beg, size); + void *addr = MmapNoAccess(beg, size, name); if (beg == 0 && addr != 0) { // Depending on the kernel configuration, we may not be able to protect // the page at address zero. uptr gap = 16 * GetPageSizeCached(); beg += gap; size -= gap; - addr = MmapNoAccess(beg, size); + addr = MmapNoAccess(beg, size, name); } if ((uptr)addr != beg) { uptr end = beg + size - 1; @@ -135,7 +135,7 @@ if (map) { if (!CheckMemoryRangeAvailability(start, size)) return false; - if ((uptr)MmapFixedNoReserve(start, size) != start) + if ((uptr)MmapFixedNoReserve(start, size, kMemoryLayout[i].name) != start) return false; if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(start, size); @@ -143,7 +143,7 @@ if (protect) { if (!CheckMemoryRangeAvailability(start, size)) return false; - if (!ProtectMemoryRange(start, size)) + if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name)) return false; } } Index: lib/sanitizer_common/sanitizer_common.h =================================================================== --- lib/sanitizer_common/sanitizer_common.h +++ lib/sanitizer_common/sanitizer_common.h @@ -69,10 +69,11 @@ // Memory management void *MmapOrDie(uptr size, const char *mem_type); void UnmapOrDie(void *addr, uptr size); -void *MmapFixedNoReserve(uptr fixed_addr, uptr size); +void *MmapFixedNoReserve(uptr fixed_addr, uptr size, + const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size); -void *MmapNoAccess(uptr fixed_addr, uptr size); +void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); // Map aligned chunk of address space; size and alignment are powers of two. void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); // Disallow access to a memory range. Use MmapNoAccess to allocate an Index: lib/sanitizer_common/sanitizer_flags.inc =================================================================== --- lib/sanitizer_common/sanitizer_flags.inc +++ lib/sanitizer_common/sanitizer_flags.inc @@ -153,4 +153,7 @@ COMMON_FLAG(bool, no_huge_pages_for_shadow, true, "If true, the shadow is not allowed to use huge pages. ") COMMON_FLAG(bool, strict_string_checks, false, - "If set check that string arguments are properly null-terminated") + "If set, check that string arguments are properly null-terminated") +COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer " + "mappings in /proc/self/maps with " + "user-readable names") Index: lib/sanitizer_common/sanitizer_posix.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix.cc +++ lib/sanitizer_common/sanitizer_posix.cc @@ -147,6 +147,22 @@ DecreaseTotalMmap(size); } +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; +} + void *MmapNoReserveOrDie(uptr size, const char *mem_type) { uptr PageSize = GetPageSizeCached(); uptr p = internal_mmap(0, @@ -165,13 +181,15 @@ return (void *)p; } -void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { +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, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, - -1, 0); + 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 " @@ -199,11 +217,13 @@ return (void *)p; } -void *MmapNoAccess(uptr fixed_addr, uptr size) { - return (void *)internal_mmap((void*)fixed_addr, size, - PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED | - MAP_NORESERVE, -1, 0); +void *MmapNoAccess(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); } bool MprotectNoAccess(uptr addr, uptr size) { Index: lib/sanitizer_common/sanitizer_win.cc =================================================================== --- lib/sanitizer_common/sanitizer_win.cc +++ lib/sanitizer_common/sanitizer_win.cc @@ -104,9 +104,10 @@ } } -void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { +void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { // FIXME: is this really "NoReserve"? On Win32 this does not matter much, // but on Win64 it does. + (void)name; // unsupported void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (p == 0) @@ -125,7 +126,8 @@ return MmapOrDie(size, mem_type); } -void *MmapNoAccess(uptr fixed_addr, uptr size) { +void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) { + (void)name; // unsupported void *res = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); if (res == 0) Index: lib/tsan/go/buildgo.sh =================================================================== --- lib/tsan/go/buildgo.sh +++ lib/tsan/go/buildgo.sh @@ -36,7 +36,7 @@ if [ "`uname -a | grep Linux`" != "" ]; then SUFFIX="linux_amd64" OSCFLAGS="-fPIC -ffreestanding -Wno-maybe-uninitialized -Wno-unused-const-variable -Werror -Wno-unknown-warning-option" - OSLDFLAGS="-lpthread -fPIC -fpie" + OSLDFLAGS="-lpthread -lrt -fPIC -fpie" SRCS=" $SRCS ../rtl/tsan_platform_linux.cc Index: lib/tsan/rtl/tsan_platform_linux.cc =================================================================== --- lib/tsan/rtl/tsan_platform_linux.cc +++ lib/tsan/rtl/tsan_platform_linux.cc @@ -202,8 +202,8 @@ void InitializeShadowMemory() { // Map memory shadow. - uptr shadow = (uptr)MmapFixedNoReserve(kShadowBeg, - kShadowEnd - kShadowBeg); + uptr shadow = + (uptr)MmapFixedNoReserve(kShadowBeg, kShadowEnd - kShadowBeg, "shadow"); if (shadow != kShadowBeg) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); Printf("FATAL: Make sure to compile with -fPIE and " @@ -232,7 +232,8 @@ // Map meta shadow. uptr meta_size = kMetaShadowEnd - kMetaShadowBeg; - uptr meta = (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size); + uptr meta = + (uptr)MmapFixedNoReserve(kMetaShadowBeg, meta_size, "meta shadow"); if (meta != kMetaShadowBeg) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); Printf("FATAL: Make sure to compile with -fPIE and " Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -574,7 +574,7 @@ } void MapShadow(uptr addr, uptr size); -void MapThreadTrace(uptr addr, uptr size); +void MapThreadTrace(uptr addr, uptr size, const char *name); void DontNeedShadowFor(uptr addr, uptr size); void InitializeShadowMemory(); void InitializeInterceptors(); Index: lib/tsan/rtl/tsan_rtl.cc =================================================================== --- lib/tsan/rtl/tsan_rtl.cc +++ lib/tsan/rtl/tsan_rtl.cc @@ -67,9 +67,12 @@ static ThreadContextBase *CreateThreadContext(u32 tid) { // Map thread trace when context is created. - MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event)); + char name[50]; + internal_snprintf(name, sizeof(name), "trace %u", tid); + MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event), name); const uptr hdr = GetThreadTraceHeader(tid); - MapThreadTrace(hdr, sizeof(Trace)); + internal_snprintf(name, sizeof(name), "trace header %u", tid); + MapThreadTrace(hdr, sizeof(Trace), name); new((void*)hdr) Trace(); // We are going to use only a small part of the trace with the default // value of history_size. However, the constructor writes to the whole trace. @@ -237,7 +240,7 @@ // Global data is not 64K aligned, but there are no adjacent mappings, // so we can get away with unaligned mapping. // CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment - MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier); + MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier, "shadow"); // Meta shadow is 2:1, so tread carefully. static bool data_mapped = false; @@ -249,7 +252,7 @@ if (!data_mapped) { // First call maps data+bss. data_mapped = true; - MmapFixedNoReserve(meta_begin, meta_end - meta_begin); + MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); } else { // Mapping continous heap. // Windows wants 64K alignment. @@ -259,19 +262,19 @@ return; if (meta_begin < mapped_meta_end) meta_begin = mapped_meta_end; - MmapFixedNoReserve(meta_begin, meta_end - meta_begin); + MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); mapped_meta_end = meta_end; } VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n", addr, addr+size, meta_begin, meta_end); } -void MapThreadTrace(uptr addr, uptr size) { +void MapThreadTrace(uptr addr, uptr size, const char *name) { DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size); CHECK_GE(addr, kTraceMemBeg); CHECK_LE(addr + size, kTraceMemEnd); CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment - uptr addr1 = (uptr)MmapFixedNoReserve(addr, size); + uptr addr1 = (uptr)MmapFixedNoReserve(addr, size, name); if (addr1 != addr) { Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n", addr, size, addr1); Index: test/asan/TestCases/Posix/decorate_proc_maps.cc =================================================================== --- test/asan/TestCases/Posix/decorate_proc_maps.cc +++ test/asan/TestCases/Posix/decorate_proc_maps.cc @@ -0,0 +1,14 @@ +// RUN: %clangxx_asan -g %s -o %t +// RUN: ASAN_OPTIONS=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s +#include "../../../utils/utils.h" + +int main(void) { + int fd = open("/proc/self/maps", O_RDONLY); + bool res = CopyFdToFd(fd, 2); + close(fd); + return !res; +} + +// CHECK: rw-p {{.*}} [low shadow] +// CHECK: ---p {{.*}} [shadow gap] +// CHECK: rw-p {{.*}} [high shadow] Index: test/msan/decorate_proc_maps.cc =================================================================== --- test/msan/decorate_proc_maps.cc +++ test/msan/decorate_proc_maps.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx_msan -g %s -o %t +// RUN: MSAN_OPTIONS=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -g -fsanitize-memory-track-origins %s -o %t +// RUN: MSAN_OPTIONS=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ORIGIN +#include "../utils/utils.h" + +int main(void) { + int fd = open("/proc/self/maps", O_RDONLY); + bool res = CopyFdToFd(fd, 2); + close(fd); + return !res; +} + +// CHECK: ---p {{.*}} [invalid] +// CHECK: rw-p {{.*}} [shadow] +// CHECK: ---p {{.*}} [origin] + +// CHECK-ORIGIN: ---p {{.*}} [invalid] +// CHECK-ORIGIN: rw-p {{.*}} [shadow] +// CHECK-ORIGIN: rw-p {{.*}} [origin] Index: test/tsan/decorate_proc_maps.cc =================================================================== --- test/tsan/decorate_proc_maps.cc +++ test/tsan/decorate_proc_maps.cc @@ -0,0 +1,27 @@ +// RUN: %clangxx_tsan -g %s -o %t +// RUN: TSAN_OPTIONS=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s +#include "../utils/utils.h" +#include + +void *ThreadFn(void *arg) { + (void)arg; + int fd = open("/proc/self/maps", O_RDONLY); + bool res = CopyFdToFd(fd, 2); + close(fd); + return (void *)!res; +} + +int main(void) { + pthread_t t; + void *res; + pthread_create(&t, 0, ThreadFn, 0); + pthread_join(t, &res); + return (int)(size_t)res; +} + +// CHECK: rw-p {{.*}} [shadow] +// CHECK: rw-p {{.*}} [meta shadow] +// CHECK: rw-p {{.*}} [trace 0] +// CHECK: rw-p {{.*}} [trace header 0] +// CHECK: rw-p {{.*}} [trace 1] +// CHECK: rw-p {{.*}} [trace header 1] Index: test/utils/utils.h =================================================================== --- test/utils/utils.h +++ test/utils/utils.h @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include + +inline bool CopyFdToFd(int in_fd, int out_fd) { + const size_t kBufSize = 0x10000; + static char buf[kBufSize]; + while (true) { + ssize_t got = read(in_fd, buf, kBufSize); + if (got > 0) { + write(out_fd, buf, got); + } else if (got == 0) { + break; + } else if (errno != EAGAIN || errno != EWOULDBLOCK || errno != EINTR) { + fprintf(stderr, "error reading file, errno %d\n", errno); + return false; + } + } + return true; +}