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 @@ -165,22 +165,6 @@ return (void *)p; } -void *MmapFixedNoReserve(uptr fixed_addr, uptr size) { - 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); - 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 *MmapFixedOrDie(uptr fixed_addr, uptr size) { uptr PageSize = GetPageSizeCached(); uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), @@ -199,13 +183,6 @@ 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); -} - bool MprotectNoAccess(uptr addr, uptr size) { return 0 == internal_mprotect((void*)addr, size, PROT_NONE); } Index: lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -24,6 +24,7 @@ #include "sanitizer_symbolizer.h" #include +#include #include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include namespace __sanitizer { @@ -217,6 +219,49 @@ #endif } +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 *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 *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); +} + } // namespace __sanitizer #endif // SANITIZER_POSIX 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/sanitizer_common/tests/CMakeLists.txt =================================================================== --- lib/sanitizer_common/tests/CMakeLists.txt +++ lib/sanitizer_common/tests/CMakeLists.txt @@ -73,6 +73,7 @@ append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS) append_list_if(COMPILER_RT_HAS_LIBDL -ldl SANITIZER_TEST_LINK_FLAGS_COMMON) +append_list_if(COMPILER_RT_HAS_LIBRT -lrt SANITIZER_TEST_LINK_FLAGS_COMMON) append_list_if(COMPILER_RT_HAS_LIBPTHREAD -pthread SANITIZER_TEST_LINK_FLAGS_COMMON) # x86_64 FreeBSD 9.2 additionally requires libc++ to build the tests. Also, # 'libm' shall be specified explicitly to build i386 tests. 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/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc =================================================================== --- test/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc +++ test/sanitizer_common/TestCases/Posix/decorate_proc_maps.cc @@ -0,0 +1,60 @@ +// RUN: %clangxx -g %s -o %t +// RUN: %tool_options=decorate_proc_maps=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%tool_name +#include +#include +#include +#include +#include +#include +#include + +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; +} + +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-asan: rw-p {{.*}} [low shadow] +// CHECK-asan: ---p {{.*}} [shadow gap] +// CHECK-asan: rw-p {{.*}} [high shadow] + +// CHECK-msan: ---p {{.*}} [invalid] +// CHECK-msan: rw-p {{.*}} [shadow] +// CHECK-msan: ---p {{.*}} [origin] + +// CHECK-tsan: rw-p {{.*}} [shadow] +// CHECK-tsan: rw-p {{.*}} [meta shadow] +// CHECK-tsan: rw-p {{.*}} [trace 0] +// CHECK-tsan: rw-p {{.*}} [trace header 0] +// CHECK-tsan: rw-p {{.*}} [trace 1] +// CHECK-tsan: rw-p {{.*}} [trace header 1] + +// Nothing interesting with standalone LSan. +// CHECK-lsan: decorate_proc_maps Index: test/sanitizer_common/TestCases/Posix/lit.local.cfg =================================================================== --- test/sanitizer_common/TestCases/Posix/lit.local.cfg +++ test/sanitizer_common/TestCases/Posix/lit.local.cfg @@ -0,0 +1,9 @@ +def getRoot(config): + if not config.parent: + return config + return getRoot(config.parent) + +root = getRoot(config) + +if root.host_os in ['Windows']: + config.unsupported = True Index: test/sanitizer_common/lit.common.cfg =================================================================== --- test/sanitizer_common/lit.common.cfg +++ test/sanitizer_common/lit.common.cfg @@ -30,6 +30,7 @@ config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) +config.substitutions.append( ("%tool_name", config.tool_name) ) config.substitutions.append( ("%tool_options", tool_options) ) config.suffixes = ['.c', '.cc', '.cpp']