# 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)
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)
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
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);
}
}
}
// ---------------------- 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);
}
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. "
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);
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);
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)
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;
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);
if (protect) {
if (!CheckMemoryRangeAvailability(start, size))
return false;
- if (!ProtectMemoryRange(start, size))
+ if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
return false;
}
}
// 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
COMMON_FLAG(bool, intercept_strpbrk, true,
"If set, uses custom wrappers for strpbrk function "
"to find more errors.")
+COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer "
+ "mappings in /proc/self/maps with "
+ "user-readable names")
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)),
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);
}
#include "sanitizer_symbolizer.h"
#include <errno.h>
+#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
namespace __sanitizer {
#endif
}
+#if SANITIZER_ANDROID
+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 *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
}
}
-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)
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)
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.
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
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 "
// 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 "
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.
// 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;
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.
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);
}
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();
--- /dev/null
+// 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 <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+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
--- /dev/null
+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
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']