forked from OSchip/llvm-project
Add descriptive names to sanitizer entries in /proc/self/maps. Helps debugging.
This is done by creating a named shared memory region, unlinking it and setting up a private (i.e. copy-on-write) mapping of that instead of a regular anonymous mapping. I've experimented with regular (sparse) files, but they can not be scaled to the size of MSan shadow mapping, at least on Linux/X86_64 and ext3 fs. Controlled by a common flag, decorate_proc_maps, disabled by default. This patch has a few shortcomings: * not all mappings are annotated, especially in TSan. * our handling of memset() of shadow via mmap() puts small anonymous mappings inside larger named mappings, which looks ugly and can, in theory, hit the mapping number limit. llvm-svn: 238621
This commit is contained in:
parent
2cfd9d574d
commit
8e9c70be7f
|
@ -62,6 +62,7 @@ check_symbol_exists(__func__ "" COMPILER_RT_HAS_FUNC_SYMBOL)
|
|||
# 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)
|
||||
|
|
|
@ -66,6 +66,7 @@ append_list_if(MSVC /DEBUG ASAN_DYNAMIC_CFLAGS)
|
|||
|
||||
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)
|
||||
|
|
|
@ -93,7 +93,7 @@ void AppendToErrorMessageBuffer(const char *buffer);
|
|||
|
||||
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
|
||||
|
|
|
@ -64,7 +64,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,12 +89,12 @@ void ShowStatsAndAbort() {
|
|||
// ---------------------- 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 InitializeHighMemEnd() {
|
|||
}
|
||||
|
||||
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 @@ static void AsanInitInternal() {
|
|||
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 @@ static void AsanInitInternal() {
|
|||
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);
|
||||
|
|
|
@ -99,6 +99,7 @@ append_list_if(ANDROID atomic ASAN_UNITTEST_INSTRUMENTED_LIBS)
|
|||
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)
|
||||
|
|
|
@ -53,16 +53,16 @@ static bool CheckMemoryRangeAvailability(uptr beg, uptr size) {
|
|||
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 @@ bool InitShadow(bool init_origins) {
|
|||
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 @@ bool InitShadow(bool init_origins) {
|
|||
if (protect) {
|
||||
if (!CheckMemoryRangeAvailability(start, size))
|
||||
return false;
|
||||
if (!ProtectMemoryRange(start, size))
|
||||
if (!ProtectMemoryRange(start, size, kMemoryLayout[i].name))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,10 +69,11 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
|||
// 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
|
||||
|
|
|
@ -163,3 +163,6 @@ COMMON_FLAG(bool, intercept_strspn, true,
|
|||
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")
|
||||
|
|
|
@ -165,22 +165,6 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
|
|||
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 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "sanitizer_symbolizer.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace __sanitizer {
|
||||
|
@ -217,6 +219,55 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
|
|||
#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
|
||||
|
|
|
@ -104,9 +104,10 @@ void UnmapOrDie(void *addr, uptr size) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
|
|||
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)
|
||||
|
|
|
@ -73,6 +73,7 @@ append_list_if(ANDROID log SANITIZER_TEST_LINK_LIBS)
|
|||
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.
|
||||
|
|
|
@ -36,7 +36,7 @@ SRCS="
|
|||
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
|
||||
|
|
|
@ -202,8 +202,8 @@ static void MapRodata() {
|
|||
|
||||
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 @@ void InitializeShadowMemory() {
|
|||
|
||||
// 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 "
|
||||
|
|
|
@ -67,9 +67,12 @@ static char thread_registry_placeholder[sizeof(ThreadRegistry)];
|
|||
|
||||
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 @@ void MapShadow(uptr addr, uptr size) {
|
|||
// 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 @@ void MapShadow(uptr addr, uptr size) {
|
|||
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 @@ void MapShadow(uptr addr, uptr size) {
|
|||
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);
|
||||
|
|
|
@ -574,7 +574,7 @@ void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) {
|
|||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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 <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
|
|
@ -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
|
|
@ -30,6 +30,7 @@ def build_invocation(compile_flags):
|
|||
|
||||
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']
|
||||
|
|
Loading…
Reference in New Issue