[libsanitizer] merge from upstream r168514
From-SVN: r193756
This commit is contained in:
parent
8ddf5c28ea
commit
e297eb600d
72 changed files with 935 additions and 552 deletions
|
@ -1,3 +1,7 @@
|
|||
2012-11-23 Kostya Serebryany <kcc@google.com>
|
||||
|
||||
* c-c++-common/asan/memcmp-1.c: Update to match the new libsanitizer.
|
||||
|
||||
2012-11-23 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* gnat.dg/discr40.ad[sb]: New test.
|
||||
|
|
|
@ -13,6 +13,6 @@ main (int argc, char **argv)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* { dg-output "ERROR: AddressSanitizer stack-buffer-overflow.*(\n|\r\n|\r)" } */
|
||||
/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow.*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #0 0x\[0-9a-f\]+ (in _*(interceptor_|)memcmp |\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
/* { dg-output " #1 0x\[0-9a-f\]+ (in _*main|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
2012-11-23 Kostya Serebryany <kcc@google.com>
|
||||
|
||||
* merge.sh: a script that will help merges from upstream.
|
||||
* merge.sh: Support tsan, support added/removed files.
|
||||
* tsan/Makefile.am: Remove tsan_printf.cc.
|
||||
* tsan/Makefile.in: Regenerated.
|
||||
* other files: Merge from upstream r168514.
|
||||
|
||||
2012-11-23 Kostya Serebryany <kcc@google.com>
|
||||
|
||||
* merge.sh: New file.
|
||||
|
||||
2012-11-23 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
|
|
4
libsanitizer/MERGE
Normal file
4
libsanitizer/MERGE
Normal file
|
@ -0,0 +1,4 @@
|
|||
168514
|
||||
|
||||
The first line of this file holds the svn revision number of the
|
||||
last merge done from the master library sources.
|
|
@ -56,7 +56,7 @@ static const uptr kMallocSizeClassStepLog = 26;
|
|||
static const uptr kMallocSizeClassStep = 1UL << kMallocSizeClassStepLog;
|
||||
|
||||
static const uptr kMaxAllowedMallocSize =
|
||||
(__WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
|
||||
(SANITIZER_WORDSIZE == 32) ? 3UL << 30 : 8UL << 30;
|
||||
|
||||
static inline bool IsAligned(uptr a, uptr alignment) {
|
||||
return (a & (alignment - 1)) == 0;
|
||||
|
@ -83,7 +83,7 @@ static inline uptr RoundUpToPowerOfTwo(uptr size) {
|
|||
|
||||
unsigned long up; // NOLINT
|
||||
#if !defined(_WIN32) || defined(__clang__)
|
||||
up = __WORDSIZE - 1 - __builtin_clzl(size);
|
||||
up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
|
||||
#elif defined(_WIN64)
|
||||
_BitScanReverse64(&up, size);
|
||||
#else
|
||||
|
|
|
@ -49,6 +49,12 @@ using __sanitizer::uptr;
|
|||
# define ASAN_INTERCEPT_STRNLEN 0
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(ANDROID)
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 1
|
||||
#else
|
||||
# define ASAN_INTERCEPT_SWAPCONTEXT 0
|
||||
#endif
|
||||
|
||||
#if !defined(ANDROID) && !defined(_WIN32)
|
||||
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
|
||||
#else
|
||||
|
|
|
@ -134,6 +134,28 @@ DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
|
|||
struct sigaction *oldact);
|
||||
#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
|
||||
|
||||
#if ASAN_INTERCEPT_SWAPCONTEXT
|
||||
INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
|
||||
struct ucontext_t *ucp) {
|
||||
static bool reported_warning = false;
|
||||
if (!reported_warning) {
|
||||
Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
|
||||
"functions and may produce false positives in some cases!\n");
|
||||
reported_warning = true;
|
||||
}
|
||||
// Clear shadow memory for new context (it may share stack
|
||||
// with current context).
|
||||
ClearShadowMemoryForContext(ucp);
|
||||
int res = REAL(swapcontext)(oucp, ucp);
|
||||
// swapcontext technically does not return, but program may swap context to
|
||||
// "oucp" later, that would look as if swapcontext() returned 0.
|
||||
// We need to clear shadow for ucp once again, as it may be in arbitrary
|
||||
// state.
|
||||
ClearShadowMemoryForContext(ucp);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(void, longjmp, void *env, int val) {
|
||||
__asan_handle_no_return();
|
||||
REAL(longjmp)(env, val);
|
||||
|
@ -237,13 +259,17 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
|
|||
ASAN_WRITE_RANGE(from, size);
|
||||
ASAN_READ_RANGE(to, size);
|
||||
}
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
// Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
|
||||
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
|
||||
return internal_memcpy(to, from, size);
|
||||
#else
|
||||
return REAL(memcpy)(to, from, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
if (!asan_inited) return REAL(memmove)(to, from, size);
|
||||
#endif
|
||||
if (!asan_inited) return internal_memmove(to, from, size);
|
||||
if (asan_init_is_running) {
|
||||
return REAL(memmove)(to, from, size);
|
||||
}
|
||||
|
@ -252,7 +278,13 @@ INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
|
|||
ASAN_WRITE_RANGE(from, size);
|
||||
ASAN_READ_RANGE(to, size);
|
||||
}
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
// Interposing of resolver functions is broken on Mac OS 10.7 and 10.8.
|
||||
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=116.
|
||||
return internal_memmove(to, from, size);
|
||||
#else
|
||||
return REAL(memmove)(to, from, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
|
||||
|
@ -370,6 +402,14 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
|
|||
|
||||
#if ASAN_INTERCEPT_STRDUP
|
||||
INTERCEPTOR(char*, strdup, const char *s) {
|
||||
#if MAC_INTERPOSE_FUNCTIONS
|
||||
// FIXME: because internal_strdup() uses InternalAlloc(), which currently
|
||||
// just calls malloc() on Mac, we can't use internal_strdup() with the
|
||||
// dynamic runtime. We can remove the call to REAL(strdup) once InternalAlloc
|
||||
// starts using mmap() instead.
|
||||
// See also http://code.google.com/p/address-sanitizer/issues/detail?id=123.
|
||||
if (!asan_inited) return REAL(strdup)(s);
|
||||
#endif
|
||||
if (!asan_inited) return internal_strdup(s);
|
||||
ENSURE_ASAN_INITED();
|
||||
if (flags()->replace_str) {
|
||||
|
@ -669,6 +709,9 @@ void InitializeAsanInterceptors() {
|
|||
ASAN_INTERCEPT_FUNC(sigaction);
|
||||
ASAN_INTERCEPT_FUNC(signal);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT_SWAPCONTEXT
|
||||
ASAN_INTERCEPT_FUNC(swapcontext);
|
||||
#endif
|
||||
#if ASAN_INTERCEPT__LONGJMP
|
||||
ASAN_INTERCEPT_FUNC(_longjmp);
|
||||
#endif
|
||||
|
|
|
@ -114,6 +114,7 @@ bool AsanInterceptsSignal(int signum);
|
|||
void SetAlternateSignalStack();
|
||||
void UnsetAlternateSignalStack();
|
||||
void InstallSignalHandlers();
|
||||
void ClearShadowMemoryForContext(void *context);
|
||||
void AsanPlatformThreadInit();
|
||||
|
||||
// Wrapper for TLS/TSD.
|
||||
|
|
|
@ -66,6 +66,13 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
|||
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
*bp = ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
*sp = ucontext->uc_mcontext.gregs[REG_ESP];
|
||||
# elif defined(__powerpc__) || defined(__powerpc64__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
*pc = ucontext->uc_mcontext.regs->nip;
|
||||
*sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
|
||||
// The powerpc{,64}-linux ABIs do not specify r31 as the frame
|
||||
// pointer, but GCC always uses r31 when we need a frame pointer.
|
||||
*bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
|
||||
# elif defined(__sparc__)
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
uptr *stk_ptr;
|
||||
|
@ -149,8 +156,10 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
|||
stack->trace[0] = pc;
|
||||
if ((max_s) > 1) {
|
||||
stack->max_size = max_s;
|
||||
#ifdef __arm__
|
||||
#if defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)
|
||||
_Unwind_Backtrace(Unwind_Trace, stack);
|
||||
// Pop off the two ASAN functions from the backtrace.
|
||||
stack->PopStackFrames(2);
|
||||
#else
|
||||
if (!asan_inited) return;
|
||||
if (AsanThread *t = asanThreadRegistry().GetCurrent())
|
||||
|
@ -159,6 +168,23 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
|||
}
|
||||
}
|
||||
|
||||
#if !ASAN_ANDROID
|
||||
void ClearShadowMemoryForContext(void *context) {
|
||||
ucontext_t *ucp = (ucontext_t*)context;
|
||||
uptr sp = (uptr)ucp->uc_stack.ss_sp;
|
||||
uptr size = ucp->uc_stack.ss_size;
|
||||
// Align to page size.
|
||||
uptr bottom = sp & ~(kPageSize - 1);
|
||||
size += sp - bottom;
|
||||
size = RoundUpTo(size, kPageSize);
|
||||
PoisonShadow(bottom, size, 0);
|
||||
}
|
||||
#else
|
||||
void ClearShadowMemoryForContext(void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
#endif // __linux__
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace __asan {
|
|||
|
||||
void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
# if __WORDSIZE == 64
|
||||
# if SANITIZER_WORDSIZE == 64
|
||||
*pc = ucontext->uc_mcontext->__ss.__rip;
|
||||
*bp = ucontext->uc_mcontext->__ss.__rbp;
|
||||
*sp = ucontext->uc_mcontext->__ss.__rsp;
|
||||
|
@ -48,7 +48,7 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
|
|||
*pc = ucontext->uc_mcontext->__ss.__eip;
|
||||
*bp = ucontext->uc_mcontext->__ss.__ebp;
|
||||
*sp = ucontext->uc_mcontext->__ss.__esp;
|
||||
# endif // __WORDSIZE
|
||||
# endif // SANITIZER_WORDSIZE
|
||||
}
|
||||
|
||||
int GetMacosVersion() {
|
||||
|
@ -66,6 +66,7 @@ int GetMacosVersion() {
|
|||
switch (version[1]) {
|
||||
case '0': return MACOS_VERSION_SNOW_LEOPARD;
|
||||
case '1': return MACOS_VERSION_LION;
|
||||
case '2': return MACOS_VERSION_MOUNTAIN_LION;
|
||||
default: return MACOS_VERSION_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +129,14 @@ bool AsanInterceptsSignal(int signum) {
|
|||
}
|
||||
|
||||
void AsanPlatformThreadInit() {
|
||||
ReplaceCFAllocator();
|
||||
// For the first program thread, we can't replace the allocator before
|
||||
// __CFInitialize() has been called. If it hasn't, we'll call
|
||||
// MaybeReplaceCFAllocator() later on this thread.
|
||||
// For other threads __CFInitialize() has been called before their creation.
|
||||
// See also asan_malloc_mac.cc.
|
||||
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
|
||||
MaybeReplaceCFAllocator();
|
||||
}
|
||||
}
|
||||
|
||||
AsanLock::AsanLock(LinkerInitialized) {
|
||||
|
@ -161,6 +169,10 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
|||
}
|
||||
}
|
||||
|
||||
void ClearShadowMemoryForContext(void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
// The range of pages to be used for escape islands.
|
||||
// TODO(glider): instead of mapping a fixed range we must find a range of
|
||||
// unmapped pages in vmmap and take them.
|
||||
|
@ -169,7 +181,7 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
|
|||
// kHighMemBeg or kHighMemEnd.
|
||||
static void *island_allocator_pos = 0;
|
||||
|
||||
#if __WORDSIZE == 32
|
||||
#if SANITIZER_WORDSIZE == 32
|
||||
# define kIslandEnd (0xffdf0000 - kPageSize)
|
||||
# define kIslandBeg (kIslandEnd - 256 * kPageSize)
|
||||
#else
|
||||
|
|
|
@ -38,7 +38,8 @@ enum {
|
|||
MACOS_VERSION_UNKNOWN = 0,
|
||||
MACOS_VERSION_LEOPARD,
|
||||
MACOS_VERSION_SNOW_LEOPARD,
|
||||
MACOS_VERSION_LION
|
||||
MACOS_VERSION_LION,
|
||||
MACOS_VERSION_MOUNTAIN_LION
|
||||
};
|
||||
|
||||
// Used by asan_malloc_mac.cc and asan_mac.cc
|
||||
|
@ -47,7 +48,7 @@ extern "C" void __CFInitialize();
|
|||
namespace __asan {
|
||||
|
||||
int GetMacosVersion();
|
||||
void ReplaceCFAllocator();
|
||||
void MaybeReplaceCFAllocator();
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
|
|
|
@ -95,10 +95,6 @@ INTERCEPTOR(void, free, void *ptr) {
|
|||
}
|
||||
}
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceCFAllocator();
|
||||
}
|
||||
|
||||
// We can't always replace the default CFAllocator with cf_asan right in
|
||||
// ReplaceSystemMalloc(), because it is sometimes called before
|
||||
// __CFInitialize(), when the default allocator is invalid and replacing it may
|
||||
|
@ -116,7 +112,7 @@ INTERCEPTOR(void, __CFInitialize, void) {
|
|||
CHECK(asan_inited);
|
||||
#endif
|
||||
REAL(__CFInitialize)();
|
||||
if (!cf_asan && asan_inited) ReplaceCFAllocator();
|
||||
if (!cf_asan && asan_inited) MaybeReplaceCFAllocator();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -291,12 +287,10 @@ size_t mi_good_size(malloc_zone_t *zone, size_t size) {
|
|||
|
||||
boolean_t mi_check(malloc_zone_t *zone) {
|
||||
UNIMPLEMENTED();
|
||||
return true;
|
||||
}
|
||||
|
||||
void mi_print(malloc_zone_t *zone, boolean_t verbose) {
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
void mi_log(malloc_zone_t *zone, void *address) {
|
||||
|
@ -331,7 +325,7 @@ boolean_t mi_zone_locked(malloc_zone_t *zone) {
|
|||
extern int __CFRuntimeClassTableSize;
|
||||
|
||||
namespace __asan {
|
||||
void ReplaceCFAllocator() {
|
||||
void MaybeReplaceCFAllocator() {
|
||||
static CFAllocatorContext asan_context = {
|
||||
/*version*/ 0, /*info*/ &asan_zone,
|
||||
/*retain*/ 0, /*release*/ 0,
|
||||
|
@ -342,7 +336,7 @@ void ReplaceCFAllocator() {
|
|||
/*preferredSize*/ 0 };
|
||||
if (!cf_asan)
|
||||
cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
|
||||
if (CFAllocatorGetDefault() != cf_asan)
|
||||
if (flags()->replace_cfallocator && CFAllocatorGetDefault() != cf_asan)
|
||||
CFAllocatorSetDefault(cf_asan);
|
||||
}
|
||||
|
||||
|
@ -410,16 +404,14 @@ void ReplaceSystemMalloc() {
|
|||
// Make sure the default allocator was replaced.
|
||||
CHECK(malloc_default_zone() == &asan_zone);
|
||||
|
||||
if (flags()->replace_cfallocator) {
|
||||
// If __CFInitialize() hasn't been called yet, cf_asan will be created and
|
||||
// installed as the default allocator after __CFInitialize() finishes (see
|
||||
// the interceptor for __CFInitialize() above). Otherwise install cf_asan
|
||||
// right now. On both Snow Leopard and Lion __CFInitialize() calls
|
||||
// __CFAllocatorInitialize(), which initializes the _base._cfisa field of
|
||||
// the default allocators we check here.
|
||||
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
|
||||
ReplaceCFAllocator();
|
||||
}
|
||||
// If __CFInitialize() hasn't been called yet, cf_asan will be created and
|
||||
// installed as the default allocator after __CFInitialize() finishes (see
|
||||
// the interceptor for __CFInitialize() above). Otherwise install cf_asan
|
||||
// right now. On both Snow Leopard and Lion __CFInitialize() calls
|
||||
// __CFAllocatorInitialize(), which initializes the _base._cfisa field of
|
||||
// the default allocators we check here.
|
||||
if (((CFRuntimeBase*)kCFAllocatorSystemDefault)->_cfisa) {
|
||||
MaybeReplaceCFAllocator();
|
||||
}
|
||||
}
|
||||
} // namespace __asan
|
||||
|
|
|
@ -28,10 +28,14 @@ extern __attribute__((visibility("default"))) uptr __asan_mapping_offset;
|
|||
# define SHADOW_OFFSET (0)
|
||||
# else
|
||||
# define SHADOW_SCALE (3)
|
||||
# if __WORDSIZE == 32
|
||||
# if SANITIZER_WORDSIZE == 32
|
||||
# define SHADOW_OFFSET (1 << 29)
|
||||
# else
|
||||
# define SHADOW_OFFSET (1ULL << 44)
|
||||
# if defined(__powerpc64__)
|
||||
# define SHADOW_OFFSET (1ULL << 41)
|
||||
# else
|
||||
# define SHADOW_OFFSET (1ULL << 44)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
|
||||
|
@ -40,11 +44,15 @@ extern __attribute__((visibility("default"))) uptr __asan_mapping_offset;
|
|||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
|
||||
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
# if defined(__powerpc64__)
|
||||
static const uptr kHighMemEnd = 0x00000fffffffffffUL;
|
||||
# else
|
||||
static const uptr kHighMemEnd = 0x00007fffffffffffUL;
|
||||
#else // __WORDSIZE == 32
|
||||
# endif
|
||||
#else // SANITIZER_WORDSIZE == 32
|
||||
static const uptr kHighMemEnd = 0xffffffff;
|
||||
#endif // __WORDSIZE
|
||||
#endif // SANITIZER_WORDSIZE
|
||||
|
||||
|
||||
#define kLowMemBeg 0
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "asan_stack.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <new>
|
||||
|
||||
namespace __asan {
|
||||
// This function is a no-op. We need it to make sure that object file
|
||||
|
@ -26,29 +25,40 @@ void ReplaceOperatorsNewAndDelete() { }
|
|||
|
||||
using namespace __asan; // NOLINT
|
||||
|
||||
// On Android new() goes through malloc interceptors.
|
||||
#if !ASAN_ANDROID
|
||||
|
||||
// Fake std::nothrow_t to avoid including <new>.
|
||||
namespace std {
|
||||
struct nothrow_t {};
|
||||
} // namespace std
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
GET_STACK_TRACE_HERE_FOR_MALLOC;\
|
||||
return asan_memalign(0, size, &stack);
|
||||
|
||||
#if ASAN_ANDROID
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
#else
|
||||
void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) throw()
|
||||
{ OPERATOR_NEW_BODY; }
|
||||
#endif
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
GET_STACK_TRACE_HERE_FOR_FREE(ptr);\
|
||||
asan_free(ptr, &stack);
|
||||
|
||||
void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
|
||||
void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
|
||||
void operator delete(void *ptr, std::nothrow_t const&) throw()
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) { OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr) { OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
void operator delete[](void *ptr, std::nothrow_t const&) throw()
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,7 @@ void AppendToErrorMessageBuffer(const char *buffer) {
|
|||
|
||||
static void PrintBytes(const char *before, uptr *a) {
|
||||
u8 *bytes = (u8*)a;
|
||||
uptr byte_num = (__WORDSIZE) / 8;
|
||||
uptr byte_num = (SANITIZER_WORDSIZE) / 8;
|
||||
Printf("%s%p:", before, (void*)a);
|
||||
for (uptr i = 0; i < byte_num; i++) {
|
||||
Printf(" %x%x", bytes[i] >> 4, bytes[i] & 15);
|
||||
|
@ -178,7 +178,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
|
|||
Printf(" [%zu, %zu) '%s'\n", beg, beg + size, buf);
|
||||
}
|
||||
Printf("HINT: this may be a false positive if your program uses "
|
||||
"some custom stack unwind mechanism\n"
|
||||
"some custom stack unwind mechanism or swapcontext\n"
|
||||
" (longjmp and C++ exceptions *are* supported)\n");
|
||||
DescribeThread(t->summary());
|
||||
return true;
|
||||
|
@ -287,7 +287,9 @@ class ScopedInErrorReport {
|
|||
// an error report will finish doing it.
|
||||
SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
|
||||
}
|
||||
Die();
|
||||
// If we're still not dead for some reason, use raw Exit() instead of
|
||||
// Die() to bypass any additional checks.
|
||||
Exit(flags()->exitcode);
|
||||
}
|
||||
__asan_on_error();
|
||||
reporting_thread_tid = asanThreadRegistry().GetCurrentTidOrInvalid();
|
||||
|
@ -320,7 +322,7 @@ class ScopedInErrorReport {
|
|||
|
||||
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer crashed on unknown address %p"
|
||||
Report("ERROR: AddressSanitizer: SEGV on unknown address %p"
|
||||
" (pc %p sp %p bp %p T%d)\n",
|
||||
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
|
||||
asanThreadRegistry().GetCurrentTidOrInvalid());
|
||||
|
@ -331,14 +333,14 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
|
|||
|
||||
void ReportDoubleFree(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting double-free on %p:\n", addr);
|
||||
Report("ERROR: AddressSanitizer: attempting double-free on %p:\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
}
|
||||
|
||||
void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting free on address "
|
||||
Report("ERROR: AddressSanitizer: attempting free on address "
|
||||
"which was not malloc()-ed: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
DescribeHeapAddress(addr, 1);
|
||||
|
@ -346,7 +348,7 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
|
|||
|
||||
void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting to call "
|
||||
Report("ERROR: AddressSanitizer: attempting to call "
|
||||
"malloc_usable_size() for pointer which is "
|
||||
"not owned: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
|
@ -355,7 +357,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
|
|||
|
||||
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer attempting to call "
|
||||
Report("ERROR: AddressSanitizer: attempting to call "
|
||||
"__asan_get_allocated_size() for pointer which is "
|
||||
"not owned: %p\n", addr);
|
||||
PrintStack(stack);
|
||||
|
@ -366,7 +368,7 @@ void ReportStringFunctionMemoryRangesOverlap(
|
|||
const char *function, const char *offset1, uptr length1,
|
||||
const char *offset2, uptr length2, StackTrace *stack) {
|
||||
ScopedInErrorReport in_report;
|
||||
Report("ERROR: AddressSanitizer %s-param-overlap: "
|
||||
Report("ERROR: AddressSanitizer: %s-param-overlap: "
|
||||
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
|
||||
function, offset1, offset1 + length1, offset2, offset2 + length2);
|
||||
PrintStack(stack);
|
||||
|
@ -459,7 +461,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
|||
}
|
||||
}
|
||||
|
||||
Report("ERROR: AddressSanitizer %s on address "
|
||||
Report("ERROR: AddressSanitizer: %s on address "
|
||||
"%p at pc 0x%zx bp 0x%zx sp 0x%zx\n",
|
||||
bug_descr, (void*)addr, pc, bp, sp);
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
f->unmap_shadow_on_exit = false;
|
||||
f->abort_on_error = false;
|
||||
f->atexit = false;
|
||||
f->disable_core = (__WORDSIZE == 64);
|
||||
f->disable_core = (SANITIZER_WORDSIZE == 64);
|
||||
f->strip_path_prefix = "";
|
||||
f->allow_reexec = true;
|
||||
f->print_full_thread_history = true;
|
||||
|
|
|
@ -54,7 +54,8 @@ void AsanStats::Print() {
|
|||
static AsanLock print_lock(LINKER_INITIALIZED);
|
||||
|
||||
static void PrintAccumulatedStats() {
|
||||
AsanStats stats = asanThreadRegistry().GetAccumulatedStats();
|
||||
AsanStats stats;
|
||||
asanThreadRegistry().GetAccumulatedStats(&stats);
|
||||
// Use lock to keep reports from mixing up.
|
||||
ScopedLock lock(&print_lock);
|
||||
stats.Print();
|
||||
|
|
|
@ -116,25 +116,25 @@ void AsanThread::ClearShadowForThreadStack() {
|
|||
|
||||
const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
|
||||
uptr bottom = 0;
|
||||
bool is_fake_stack = false;
|
||||
if (AddrIsInStack(addr)) {
|
||||
bottom = stack_bottom();
|
||||
} else {
|
||||
bottom = fake_stack().AddrIsInFakeStack(addr);
|
||||
CHECK(bottom);
|
||||
is_fake_stack = true;
|
||||
*offset = addr - bottom;
|
||||
return (const char *)((uptr*)bottom)[1];
|
||||
}
|
||||
uptr aligned_addr = addr & ~(__WORDSIZE/8 - 1); // align addr.
|
||||
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
|
||||
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
|
||||
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr != kAsanStackLeftRedzoneMagic) {
|
||||
*shadow_ptr != kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
}
|
||||
|
||||
while (shadow_ptr >= shadow_bottom &&
|
||||
*shadow_ptr == kAsanStackLeftRedzoneMagic) {
|
||||
*shadow_ptr == kAsanStackLeftRedzoneMagic) {
|
||||
shadow_ptr--;
|
||||
}
|
||||
|
||||
|
@ -144,8 +144,7 @@ const char *AsanThread::GetFrameNameByAddr(uptr addr, uptr *offset) {
|
|||
}
|
||||
|
||||
uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
|
||||
CHECK((ptr[0] == kCurrentStackFrameMagic) ||
|
||||
(is_fake_stack && ptr[0] == kRetiredStackFrameMagic));
|
||||
CHECK(ptr[0] == kCurrentStackFrameMagic);
|
||||
*offset = addr - (uptr)ptr;
|
||||
return (const char*)ptr[1];
|
||||
}
|
||||
|
|
|
@ -102,16 +102,20 @@ AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
|
|||
return (t) ? t->stats() : main_thread_.stats();
|
||||
}
|
||||
|
||||
AsanStats AsanThreadRegistry::GetAccumulatedStats() {
|
||||
void AsanThreadRegistry::GetAccumulatedStats(AsanStats *stats) {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_;
|
||||
internal_memcpy(stats, &accumulated_stats_, sizeof(accumulated_stats_));
|
||||
}
|
||||
|
||||
uptr AsanThreadRegistry::GetCurrentAllocatedBytes() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_.malloced - accumulated_stats_.freed;
|
||||
uptr malloced = accumulated_stats_.malloced;
|
||||
uptr freed = accumulated_stats_.freed;
|
||||
// Return sane value if malloced < freed due to racy
|
||||
// way we update accumulated stats.
|
||||
return (malloced > freed) ? malloced - freed : 1;
|
||||
}
|
||||
|
||||
uptr AsanThreadRegistry::GetHeapSize() {
|
||||
|
@ -123,11 +127,14 @@ uptr AsanThreadRegistry::GetHeapSize() {
|
|||
uptr AsanThreadRegistry::GetFreeBytes() {
|
||||
ScopedLock lock(&mu_);
|
||||
UpdateAccumulatedStatsUnlocked();
|
||||
return accumulated_stats_.mmaped
|
||||
- accumulated_stats_.malloced
|
||||
- accumulated_stats_.malloced_redzones
|
||||
+ accumulated_stats_.really_freed
|
||||
+ accumulated_stats_.really_freed_redzones;
|
||||
uptr total_free = accumulated_stats_.mmaped
|
||||
+ accumulated_stats_.really_freed
|
||||
+ accumulated_stats_.really_freed_redzones;
|
||||
uptr total_used = accumulated_stats_.malloced
|
||||
+ accumulated_stats_.malloced_redzones;
|
||||
// Return sane value if total_free < total_used due to racy
|
||||
// way we update accumulated stats.
|
||||
return (total_free > total_used) ? total_free - total_used : 1;
|
||||
}
|
||||
|
||||
// Return several stats counters with a single call to
|
||||
|
|
|
@ -45,9 +45,9 @@ class AsanThreadRegistry {
|
|||
// Returns stats for GetCurrent(), or stats for
|
||||
// T0 if GetCurrent() returns 0.
|
||||
AsanStats &GetCurrentThreadStats();
|
||||
// Flushes all thread-local stats to accumulated stats, and returns
|
||||
// Flushes all thread-local stats to accumulated stats, and makes
|
||||
// a copy of accumulated stats.
|
||||
AsanStats GetAccumulatedStats();
|
||||
void GetAccumulatedStats(AsanStats *stats);
|
||||
uptr GetCurrentAllocatedBytes();
|
||||
uptr GetHeapSize();
|
||||
uptr GetFreeBytes();
|
||||
|
|
|
@ -137,6 +137,10 @@ void AsanPlatformThreadInit() {
|
|||
// Nothing here for now.
|
||||
}
|
||||
|
||||
void ClearShadowMemoryForContext(void *context) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
// ---------------------- Interface ---------------- {{{1
|
||||
|
|
|
@ -68,6 +68,11 @@ extern "C" {
|
|||
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
|
||||
void __sanitizer_set_report_path(const char *path)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
|
||||
// Tell the tools to write their reports to given file descriptor instead of
|
||||
// stderr.
|
||||
void __sanitizer_set_report_fd(int fd)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
} // extern "C"
|
||||
|
||||
#endif // SANITIZER_COMMON_INTERFACE_DEFS_H
|
||||
|
|
|
@ -44,10 +44,11 @@ merge() {
|
|||
cp -v $upstream_path/$f $local_path
|
||||
elif [ -f $upstream_path/$f ]; then
|
||||
echo "FOUND IN UPSTREAM :" $f
|
||||
echo "UNSUPPORTED YET" && exit 1
|
||||
cp -v $upstream_path/$f $local_path
|
||||
svn add $local_path/$f
|
||||
elif [ -f $local_path/$f ]; then
|
||||
echo "FOUND IN LOCAL :" $f
|
||||
echo "UNSUPPORTED YET" && exit 1
|
||||
svn remove $local_path/$f
|
||||
fi
|
||||
done
|
||||
|
||||
|
@ -65,6 +66,7 @@ CUR_REV=$(get_current_rev)
|
|||
echo Current upstream revision: $CUR_REV
|
||||
merge include/sanitizer include/sanitizer
|
||||
merge lib/asan asan
|
||||
merge lib/tsan/rtl tsan
|
||||
merge lib/sanitizer_common sanitizer_common
|
||||
merge lib/interception interception
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#define SANITIZER_ALLOCATOR_H
|
||||
|
||||
#include "sanitizer_internal_defs.h"
|
||||
#if __WORDSIZE != 64
|
||||
#if SANITIZER_WORDSIZE != 64
|
||||
# error "sanitizer_allocator64.h can only be used on 64-bit platforms"
|
||||
#endif
|
||||
|
||||
|
@ -275,7 +275,12 @@ class SizeClassAllocator64 {
|
|||
} while (idx < end_idx);
|
||||
region->allocated_user += idx - beg_idx;
|
||||
region->allocated_meta += i * kMetadataSize;
|
||||
CHECK_LT(region->allocated_user + region->allocated_meta, kRegionSize);
|
||||
if (region->allocated_user + region->allocated_meta > kRegionSize) {
|
||||
Printf("Out of memory. Dying.\n");
|
||||
Printf("The process has exhausted %zuMB for size class %zu.\n",
|
||||
kRegionSize / 1024 / 1024, size);
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
void *AllocateBySizeClass(uptr class_id) {
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
static fd_t report_fd = 2; // By default, dump to stderr.
|
||||
// By default, dump to stderr. If report_fd is kInvalidFd, try to obtain file
|
||||
// descriptor by opening file in report_path.
|
||||
static fd_t report_fd = kStderrFd;
|
||||
static char report_path[4096]; // Set via __sanitizer_set_report_path.
|
||||
|
||||
static void (*DieCallback)(void);
|
||||
|
@ -44,18 +46,27 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
|||
Die();
|
||||
}
|
||||
|
||||
static void MaybeOpenReportFile() {
|
||||
if (report_fd != kInvalidFd)
|
||||
return;
|
||||
fd_t fd = internal_open(report_path, true);
|
||||
if (fd == kInvalidFd) {
|
||||
report_fd = kStderrFd;
|
||||
Report("ERROR: Can't open file: %s\n", report_path);
|
||||
Die();
|
||||
}
|
||||
report_fd = fd;
|
||||
}
|
||||
|
||||
bool PrintsToTty() {
|
||||
MaybeOpenReportFile();
|
||||
return internal_isatty(report_fd);
|
||||
}
|
||||
|
||||
void RawWrite(const char *buffer) {
|
||||
static const char *kRawWriteError = "RawWrite can't output requested buffer!";
|
||||
uptr length = (uptr)internal_strlen(buffer);
|
||||
if (report_fd == kInvalidFd) {
|
||||
fd_t fd = internal_open(report_path, true);
|
||||
if (fd == kInvalidFd) {
|
||||
report_fd = 2;
|
||||
Report("ERROR: Can't open file: %s\n", report_path);
|
||||
Die();
|
||||
}
|
||||
report_fd = fd;
|
||||
}
|
||||
MaybeOpenReportFile();
|
||||
if (length != internal_write(report_fd, buffer, length)) {
|
||||
internal_write(report_fd, kRawWriteError, internal_strlen(kRawWriteError));
|
||||
Die();
|
||||
|
@ -136,16 +147,27 @@ void SortArray(uptr *array, uptr size) {
|
|||
|
||||
} // namespace __sanitizer
|
||||
|
||||
using namespace __sanitizer; // NOLINT
|
||||
|
||||
extern "C" {
|
||||
void __sanitizer_set_report_path(const char *path) {
|
||||
if (!path) return;
|
||||
uptr len = internal_strlen(path);
|
||||
if (len > sizeof(__sanitizer::report_path) - 100) {
|
||||
if (len > sizeof(report_path) - 100) {
|
||||
Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
|
||||
path[0], path[1], path[2], path[3],
|
||||
path[4], path[5], path[6], path[7]);
|
||||
Die();
|
||||
}
|
||||
internal_snprintf(__sanitizer::report_path,
|
||||
sizeof(__sanitizer::report_path), "%s.%d", path, GetPid());
|
||||
__sanitizer::report_fd = kInvalidFd;
|
||||
internal_snprintf(report_path, sizeof(report_path), "%s.%d", path, GetPid());
|
||||
report_fd = kInvalidFd;
|
||||
}
|
||||
|
||||
void __sanitizer_set_report_fd(int fd) {
|
||||
if (report_fd != kStdoutFd &&
|
||||
report_fd != kStderrFd &&
|
||||
report_fd != kInvalidFd)
|
||||
internal_close(report_fd);
|
||||
report_fd = fd;
|
||||
}
|
||||
} // extern "C"
|
||||
|
|
|
@ -19,14 +19,24 @@
|
|||
namespace __sanitizer {
|
||||
|
||||
// Constants.
|
||||
const uptr kWordSize = __WORDSIZE / 8;
|
||||
const uptr kWordSize = SANITIZER_WORDSIZE / 8;
|
||||
const uptr kWordSizeInBits = 8 * kWordSize;
|
||||
const uptr kPageSizeBits = 12;
|
||||
const uptr kPageSize = 1UL << kPageSizeBits;
|
||||
#if defined(__powerpc__) || defined(__powerpc64__)
|
||||
// Current PPC64 kernels use 64K pages sizes, but they can be
|
||||
// configured with 4K or even other sizes.
|
||||
// We may want to use getpagesize() or sysconf(_SC_PAGESIZE) here rather than
|
||||
// hardcoding the values, but today these values need to be compile-time
|
||||
// constants.
|
||||
const uptr kPageSize = 1UL << 16;
|
||||
const uptr kCacheLineSize = 128;
|
||||
const uptr kMmapGranularity = kPageSize;
|
||||
#elif !defined(_WIN32)
|
||||
const uptr kPageSize = 1UL << 12;
|
||||
const uptr kCacheLineSize = 64;
|
||||
#ifndef _WIN32
|
||||
const uptr kMmapGranularity = kPageSize;
|
||||
#else
|
||||
const uptr kPageSize = 1UL << 12;
|
||||
const uptr kCacheLineSize = 64;
|
||||
const uptr kMmapGranularity = 1UL << 16;
|
||||
#endif
|
||||
|
||||
|
@ -96,6 +106,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
|
|||
|
||||
// IO
|
||||
void RawWrite(const char *buffer);
|
||||
bool PrintsToTty();
|
||||
void Printf(const char *format, ...);
|
||||
void Report(const char *format, ...);
|
||||
void SetPrintfAndReportCallback(void (*callback)(const char *));
|
||||
|
@ -114,6 +125,7 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size);
|
|||
// OS
|
||||
void DisableCoreDumper();
|
||||
void DumpProcessMap();
|
||||
bool FileExists(const char *filename);
|
||||
const char *GetEnv(const char *name);
|
||||
const char *GetPwd();
|
||||
void ReExec();
|
||||
|
@ -170,7 +182,7 @@ INLINE int ToLower(int c) {
|
|||
return (c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c;
|
||||
}
|
||||
|
||||
#if __WORDSIZE == 64
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
# define FIRST_32_SECOND_64(a, b) (b)
|
||||
#else
|
||||
# define FIRST_32_SECOND_64(a, b) (a)
|
||||
|
|
|
@ -22,8 +22,7 @@ using namespace __sanitizer; // NOLINT
|
|||
#define WEAK SANITIZER_WEAK_ATTRIBUTE
|
||||
|
||||
// Platform-specific defs.
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long DWORD; // NOLINT
|
||||
#if defined(_MSC_VER)
|
||||
# define ALWAYS_INLINE __declspec(forceinline)
|
||||
// FIXME(timurrrr): do we need this on Windows?
|
||||
# define ALIAS(x)
|
||||
|
@ -33,7 +32,11 @@ typedef unsigned long DWORD; // NOLINT
|
|||
# define NORETURN __declspec(noreturn)
|
||||
# define THREADLOCAL __declspec(thread)
|
||||
# define NOTHROW
|
||||
#else // _WIN32
|
||||
# define LIKELY(x) (x)
|
||||
# define UNLIKELY(x) (x)
|
||||
# define UNUSED
|
||||
# define USED
|
||||
#else // _MSC_VER
|
||||
# define ALWAYS_INLINE __attribute__((always_inline))
|
||||
# define ALIAS(x) __attribute__((alias(x)))
|
||||
# define ALIGNED(x) __attribute__((aligned(x)))
|
||||
|
@ -41,22 +44,15 @@ typedef unsigned long DWORD; // NOLINT
|
|||
# define NOINLINE __attribute__((noinline))
|
||||
# define NORETURN __attribute__((noreturn))
|
||||
# define THREADLOCAL __thread
|
||||
# ifdef __cplusplus
|
||||
# define NOTHROW throw()
|
||||
# else
|
||||
# define NOTHROW __attribute__((__nothrow__))
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
|
||||
// We have no equivalent of these on Windows.
|
||||
#ifndef _WIN32
|
||||
# define NOTHROW throw()
|
||||
# define LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define UNUSED __attribute__((unused))
|
||||
# define USED __attribute__((used))
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(_WIN32)
|
||||
typedef unsigned long DWORD; // NOLINT
|
||||
typedef DWORD thread_return_t;
|
||||
# define THREAD_CALLING_CONV __stdcall
|
||||
#else // _WIN32
|
||||
|
@ -65,15 +61,11 @@ typedef void* thread_return_t;
|
|||
#endif // _WIN32
|
||||
typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
|
||||
|
||||
// If __WORDSIZE was undefined by the platform, define it in terms of the
|
||||
// compiler built-ins __LP64__ and _WIN64.
|
||||
#ifndef __WORDSIZE
|
||||
# if __LP64__ || defined(_WIN64)
|
||||
# define __WORDSIZE 64
|
||||
# else
|
||||
# define __WORDSIZE 32
|
||||
# endif
|
||||
#endif // __WORDSIZE
|
||||
#if __LP64__ || defined(_WIN64)
|
||||
# define SANITIZER_WORDSIZE 64
|
||||
#else
|
||||
# define SANITIZER_WORDSIZE 32
|
||||
#endif
|
||||
|
||||
// NOTE: Functions below must be defined in each run-time.
|
||||
namespace __sanitizer {
|
||||
|
@ -128,7 +120,12 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
|||
#define DCHECK_GE(a, b)
|
||||
#endif
|
||||
|
||||
#define UNIMPLEMENTED() CHECK("unimplemented" && 0)
|
||||
#define UNREACHABLE(msg) do { \
|
||||
CHECK(0 && msg); \
|
||||
Die(); \
|
||||
} while (0)
|
||||
|
||||
#define UNIMPLEMENTED() UNREACHABLE("unimplemented")
|
||||
|
||||
#define COMPILER_CHECK(pred) IMPL_COMPILER_ASSERT(pred, __LINE__)
|
||||
|
||||
|
@ -142,13 +139,13 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
|
|||
// have stdint.h (like in Visual Studio 9).
|
||||
#undef __INT64_C
|
||||
#undef __UINT64_C
|
||||
#if __WORDSIZE == 64
|
||||
#if SANITIZER_WORDSIZE == 64
|
||||
# define __INT64_C(c) c ## L
|
||||
# define __UINT64_C(c) c ## UL
|
||||
#else
|
||||
# define __INT64_C(c) c ## LL
|
||||
# define __UINT64_C(c) c ## ULL
|
||||
#endif // __WORDSIZE == 64
|
||||
#endif // SANITIZER_WORDSIZE == 64
|
||||
#undef INT32_MIN
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#undef INT32_MAX
|
||||
|
|
|
@ -42,6 +42,23 @@ void *internal_memcpy(void *dest, const void *src, uptr n) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
void *internal_memmove(void *dest, const void *src, uptr n) {
|
||||
char *d = (char*)dest;
|
||||
char *s = (char*)src;
|
||||
sptr i, signed_n = (sptr)n;
|
||||
CHECK_GE(signed_n, 0);
|
||||
if (d < s) {
|
||||
for (i = 0; i < signed_n; ++i)
|
||||
d[i] = s[i];
|
||||
} else {
|
||||
if (d > s && signed_n > 0)
|
||||
for (i = signed_n - 1; i >= 0 ; --i) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *internal_memset(void* s, int c, uptr n) {
|
||||
// The next line prevents Clang from making a call to memset() instead of the
|
||||
// loop below.
|
||||
|
|
|
@ -27,6 +27,7 @@ s64 internal_atoll(const char *nptr);
|
|||
void *internal_memchr(const void *s, int c, uptr n);
|
||||
int internal_memcmp(const void* s1, const void* s2, uptr n);
|
||||
void *internal_memcpy(void *dest, const void *src, uptr n);
|
||||
void *internal_memmove(void *dest, const void *src, uptr n);
|
||||
// Should not be used in performance-critical places.
|
||||
void *internal_memset(void *s, int c, uptr n);
|
||||
char* internal_strchr(const char *s, int c);
|
||||
|
@ -52,7 +53,11 @@ int internal_munmap(void *addr, uptr length);
|
|||
// I/O
|
||||
typedef int fd_t;
|
||||
const fd_t kInvalidFd = -1;
|
||||
const fd_t kStdinFd = 0;
|
||||
const fd_t kStdoutFd = 1;
|
||||
const fd_t kStderrFd = 2;
|
||||
int internal_close(fd_t fd);
|
||||
int internal_isatty(fd_t fd);
|
||||
fd_t internal_open(const char *filename, bool write);
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count);
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count);
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#include <errno.h>
|
||||
|
||||
// Are we using 32-bit or 64-bit syscalls?
|
||||
// x32 (which defines __x86_64__) has __WORDSIZE == 32
|
||||
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
|
||||
// but it still needs to use 64-bit syscalls.
|
||||
#if defined(__x86_64__) || __WORDSIZE == 64
|
||||
#if defined(__x86_64__) || SANITIZER_WORDSIZE == 64
|
||||
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
|
||||
#else
|
||||
# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
|
||||
|
@ -101,6 +101,20 @@ int internal_sched_yield() {
|
|||
}
|
||||
|
||||
// ----------------- sanitizer_common.h
|
||||
bool FileExists(const char *filename) {
|
||||
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
struct stat st;
|
||||
if (syscall(__NR_stat, filename, &st))
|
||||
return false;
|
||||
#else
|
||||
struct stat64 st;
|
||||
if (syscall(__NR_stat64, filename, &st))
|
||||
return false;
|
||||
#endif
|
||||
// Sanity check: filename is a regular file.
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
uptr GetTid() {
|
||||
return syscall(__NR_gettid);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,14 @@ int internal_sched_yield() {
|
|||
}
|
||||
|
||||
// ----------------- sanitizer_common.h
|
||||
bool FileExists(const char *filename) {
|
||||
struct stat st;
|
||||
if (stat(filename, &st))
|
||||
return false;
|
||||
// Sanity check: filename is a regular file.
|
||||
return S_ISREG(st.st_mode);
|
||||
}
|
||||
|
||||
uptr GetTid() {
|
||||
return reinterpret_cast<uptr>(pthread_self());
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "sanitizer_internal_defs.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
#if (__WORDSIZE == 64) || defined(__APPLE__)
|
||||
#if (SANITIZER_WORDSIZE == 64) || defined(__APPLE__)
|
||||
typedef uptr operator_new_ptr_type;
|
||||
#else
|
||||
typedef u32 operator_new_ptr_type;
|
||||
|
|
|
@ -72,10 +72,15 @@ void UnmapOrDie(void *addr, uptr size) {
|
|||
}
|
||||
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
|
||||
return internal_mmap((void*)fixed_addr, size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
void *p = internal_mmap((void*)(fixed_addr & ~(kPageSize - 1)),
|
||||
RoundUpTo(size, kPageSize),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
if (p == (void*)-1)
|
||||
Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
|
||||
size, size, fixed_addr, errno);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mprotect(uptr fixed_addr, uptr size) {
|
||||
|
@ -182,6 +187,10 @@ int Atexit(void (*function)(void)) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int internal_isatty(fd_t fd) {
|
||||
return isatty(fd);
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
||||
#endif // __linux__ || __APPLE_
|
||||
|
|
|
@ -43,7 +43,12 @@ static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
|||
num_buffer[pos++] = num % base;
|
||||
num /= base;
|
||||
} while (num > 0);
|
||||
while (pos < minimal_num_length) num_buffer[pos++] = 0;
|
||||
if (pos < minimal_num_length) {
|
||||
// Make sure compiler doesn't insert call to memset here.
|
||||
internal_memset(&num_buffer[pos], 0,
|
||||
sizeof(num_buffer[0]) * (minimal_num_length - pos));
|
||||
pos = minimal_num_length;
|
||||
}
|
||||
int result = 0;
|
||||
while (pos-- > 0) {
|
||||
uptr digit = num_buffer[pos];
|
||||
|
@ -53,13 +58,16 @@ static int AppendUnsigned(char **buff, const char *buff_end, u64 num,
|
|||
return result;
|
||||
}
|
||||
|
||||
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num) {
|
||||
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
|
||||
u8 minimal_num_length) {
|
||||
int result = 0;
|
||||
if (num < 0) {
|
||||
result += AppendChar(buff, buff_end, '-');
|
||||
num = -num;
|
||||
if (minimal_num_length)
|
||||
--minimal_num_length;
|
||||
}
|
||||
result += AppendUnsigned(buff, buff_end, (u64)num, 10, 0);
|
||||
result += AppendUnsigned(buff, buff_end, (u64)num, 10, minimal_num_length);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -77,14 +85,14 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
|
|||
int result = 0;
|
||||
result += AppendString(buff, buff_end, "0x");
|
||||
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
|
||||
(__WORDSIZE == 64) ? 12 : 8);
|
||||
(SANITIZER_WORDSIZE == 64) ? 12 : 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
int VSNPrintf(char *buff, int buff_length,
|
||||
const char *format, va_list args) {
|
||||
static const char *kPrintfFormatsHelp = "Supported Printf formats: "
|
||||
"%%[z]{d,u,x}; %%p; %%s; %%c\n";
|
||||
static const char *kPrintfFormatsHelp =
|
||||
"Supported Printf formats: %%(0[0-9]*)?(z|ll)?{d,u,x}; %%p; %%s; %%c\n";
|
||||
RAW_CHECK(format);
|
||||
RAW_CHECK(buff_length > 0);
|
||||
const char *buff_end = &buff[buff_length - 1];
|
||||
|
@ -96,42 +104,55 @@ int VSNPrintf(char *buff, int buff_length,
|
|||
continue;
|
||||
}
|
||||
cur++;
|
||||
bool have_width = (*cur == '0');
|
||||
int width = 0;
|
||||
if (have_width) {
|
||||
while (*cur >= '0' && *cur <= '9') {
|
||||
have_width = true;
|
||||
width = width * 10 + *cur++ - '0';
|
||||
}
|
||||
}
|
||||
bool have_z = (*cur == 'z');
|
||||
cur += have_z;
|
||||
bool have_ll = !have_z && (cur[0] == 'l' && cur[1] == 'l');
|
||||
cur += have_ll * 2;
|
||||
s64 dval;
|
||||
u64 uval;
|
||||
bool have_flags = have_width | have_z | have_ll;
|
||||
switch (*cur) {
|
||||
case 'd': {
|
||||
dval = have_z ? va_arg(args, sptr)
|
||||
: va_arg(args, int);
|
||||
result += AppendSignedDecimal(&buff, buff_end, dval);
|
||||
dval = have_ll ? va_arg(args, s64)
|
||||
: have_z ? va_arg(args, sptr)
|
||||
: va_arg(args, int);
|
||||
result += AppendSignedDecimal(&buff, buff_end, dval, width);
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
case 'x': {
|
||||
uval = have_z ? va_arg(args, uptr)
|
||||
: va_arg(args, unsigned);
|
||||
uval = have_ll ? va_arg(args, u64)
|
||||
: have_z ? va_arg(args, uptr)
|
||||
: va_arg(args, unsigned);
|
||||
result += AppendUnsigned(&buff, buff_end, uval,
|
||||
(*cur == 'u') ? 10 : 16, 0);
|
||||
(*cur == 'u') ? 10 : 16, width);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
|
||||
result += AppendPointer(&buff, buff_end, va_arg(args, uptr));
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
|
||||
result += AppendString(&buff, buff_end, va_arg(args, char*));
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
|
||||
result += AppendChar(&buff, buff_end, va_arg(args, int));
|
||||
break;
|
||||
}
|
||||
case '%' : {
|
||||
RAW_CHECK_MSG(!have_z, kPrintfFormatsHelp);
|
||||
RAW_CHECK_MSG(!have_flags, kPrintfFormatsHelp);
|
||||
result += AppendChar(&buff, buff_end, '%');
|
||||
break;
|
||||
}
|
||||
|
@ -151,7 +172,7 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
|
|||
}
|
||||
|
||||
void Printf(const char *format, ...) {
|
||||
const int kLen = 1024 * 4;
|
||||
const int kLen = 16 * 1024;
|
||||
InternalScopedBuffer<char> buffer(kLen);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
@ -177,7 +198,7 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
|
|||
|
||||
// Like Printf, but prints the current PID before the output string.
|
||||
void Report(const char *format, ...) {
|
||||
const int kLen = 1024 * 4;
|
||||
const int kLen = 16 * 1024;
|
||||
InternalScopedBuffer<char> buffer(kLen);
|
||||
int needed_length = internal_snprintf(buffer.data(),
|
||||
kLen, "==%d== ", GetPid());
|
||||
|
|
|
@ -23,7 +23,6 @@ class MemoryMappingLayout {
|
|||
bool GetObjectNameAndOffset(uptr addr, uptr *offset,
|
||||
char filename[], uptr filename_size) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,12 @@ static uptr patch_pc(uptr pc) {
|
|||
// Cancel Thumb bit.
|
||||
pc = pc & (~1);
|
||||
#endif
|
||||
#if defined(__powerpc__) || defined(__powerpc64__)
|
||||
// PCs are always 4 byte aligned.
|
||||
return pc - 4;
|
||||
#else
|
||||
return pc - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
|
||||
|
@ -75,7 +80,8 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
|
|||
Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix));
|
||||
frame_num++;
|
||||
}
|
||||
} else if (symbolize) {
|
||||
}
|
||||
if (symbolize && addr_frames_num == 0) {
|
||||
// Use our own (online) symbolizer, if necessary.
|
||||
addr_frames_num = SymbolizeCode(pc, addr_frames.data(),
|
||||
addr_frames.size());
|
||||
|
@ -135,12 +141,20 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp,
|
|||
}
|
||||
}
|
||||
|
||||
void StackTrace::PopStackFrames(uptr count) {
|
||||
CHECK(size >= count);
|
||||
size -= count;
|
||||
for (uptr i = 0; i < size; i++) {
|
||||
trace[i] = trace[i + count];
|
||||
}
|
||||
}
|
||||
|
||||
// On 32-bits we don't compress stack traces.
|
||||
// On 64-bits we compress stack traces: if a given pc differes slightly from
|
||||
// the previous one, we record a 31-bit offset instead of the full pc.
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
|
||||
#if __WORDSIZE == 32
|
||||
#if SANITIZER_WORDSIZE == 32
|
||||
// Don't compress, just copy.
|
||||
uptr res = 0;
|
||||
for (uptr i = 0; i < stack->size && i < size; i++) {
|
||||
|
@ -181,7 +195,7 @@ uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
|
|||
compressed[c_index] = 0;
|
||||
if (c_index + 1 < size)
|
||||
compressed[c_index + 1] = 0;
|
||||
#endif // __WORDSIZE
|
||||
#endif // SANITIZER_WORDSIZE
|
||||
|
||||
// debug-only code
|
||||
#if 0
|
||||
|
@ -204,7 +218,7 @@ uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void StackTrace::UncompressStack(StackTrace *stack,
|
||||
u32 *compressed, uptr size) {
|
||||
#if __WORDSIZE == 32
|
||||
#if SANITIZER_WORDSIZE == 32
|
||||
// Don't uncompress, just copy.
|
||||
stack->size = 0;
|
||||
for (uptr i = 0; i < size && i < kStackTraceMax; i++) {
|
||||
|
@ -239,7 +253,7 @@ void StackTrace::UncompressStack(StackTrace *stack,
|
|||
stack->trace[stack->size++] = pc;
|
||||
prev_pc = pc;
|
||||
}
|
||||
#endif // __WORDSIZE
|
||||
#endif // SANITIZER_WORDSIZE
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -43,6 +43,8 @@ struct StackTrace {
|
|||
|
||||
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom);
|
||||
|
||||
void PopStackFrames(uptr count);
|
||||
|
||||
static uptr GetCurrentPc();
|
||||
|
||||
static uptr CompressStack(StackTrace *stack,
|
||||
|
|
|
@ -291,7 +291,8 @@ class Symbolizer {
|
|||
}
|
||||
}
|
||||
|
||||
static const uptr kMaxNumberOfModuleContexts = 4096;
|
||||
// 16K loaded modules should be enough for everyone.
|
||||
static const uptr kMaxNumberOfModuleContexts = 1 << 14;
|
||||
LoadedModule *modules_; // Array of module descriptions is leaked.
|
||||
uptr n_modules_;
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class LoadedModule {
|
|||
};
|
||||
char *full_name_;
|
||||
uptr base_address_;
|
||||
static const uptr kMaxNumberOfAddressRanges = 8;
|
||||
static const uptr kMaxNumberOfAddressRanges = 6;
|
||||
AddressRange ranges_[kMaxNumberOfAddressRanges];
|
||||
uptr n_ranges_;
|
||||
};
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(ANDROID)
|
||||
|
@ -29,8 +30,15 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
static const int kSymbolizerStartupTimeMillis = 10;
|
||||
|
||||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
if (!FileExists(path_to_symbolizer)) {
|
||||
Report("WARNING: invalid path to external symbolizer!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
int *infd = NULL;
|
||||
int *outfd = NULL;
|
||||
// The client program may close its stdin and/or stdout and/or stderr
|
||||
|
@ -97,13 +105,23 @@ bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
|||
internal_close(infd[1]);
|
||||
*input_fd = infd[0];
|
||||
*output_fd = outfd[1];
|
||||
|
||||
// Check that symbolizer subprocess started successfully.
|
||||
int pid_status;
|
||||
SleepForMillis(kSymbolizerStartupTimeMillis);
|
||||
int exited_pid = waitpid(pid, &pid_status, WNOHANG);
|
||||
if (exited_pid != 0) {
|
||||
// Either waitpid failed, or child has already exited.
|
||||
Report("WARNING: external symbolizer didn't start up correctly!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
#else // ANDROID
|
||||
typedef ElfW(Phdr) Elf_Phdr;
|
||||
|
|
|
@ -18,12 +18,10 @@ namespace __sanitizer {
|
|||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -20,12 +20,10 @@ namespace __sanitizer {
|
|||
bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
|
||||
int *input_fd, int *output_fd) {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
uptr GetListOfModules(LoadedModule *modules, uptr max_modules) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
};
|
||||
|
||||
} // namespace __sanitizer
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
// sanitizer_libc.h.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOGDI
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "sanitizer_common.h"
|
||||
|
@ -18,6 +21,10 @@
|
|||
namespace __sanitizer {
|
||||
|
||||
// --------------------- sanitizer_common.h
|
||||
bool FileExists(const char *filename) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
int GetPid() {
|
||||
return GetProcessId(GetCurrentProcess());
|
||||
}
|
||||
|
@ -39,7 +46,6 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
|
|||
*stack_bottom = (uptr)mbi.AllocationBase;
|
||||
}
|
||||
|
||||
|
||||
void *MmapOrDie(uptr size, const char *mem_type) {
|
||||
void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (rv == 0) {
|
||||
|
@ -59,8 +65,12 @@ void UnmapOrDie(void *addr, uptr size) {
|
|||
}
|
||||
|
||||
void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
|
||||
return VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
void *p = VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (p == 0)
|
||||
Report("ERROR: Failed to allocate 0x%zx (%zd) bytes at %p (%d)\n",
|
||||
size, size, fixed_addr, GetLastError());
|
||||
return p;
|
||||
}
|
||||
|
||||
void *Mprotect(uptr fixed_addr, uptr size) {
|
||||
|
@ -75,7 +85,6 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
|
|||
|
||||
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *GetEnv(const char *name) {
|
||||
|
@ -96,7 +105,6 @@ const char *GetEnv(const char *name) {
|
|||
|
||||
const char *GetPwd() {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DumpProcessMap() {
|
||||
|
@ -113,7 +121,6 @@ void ReExec() {
|
|||
|
||||
bool StackSizeIsUnlimited() {
|
||||
UNIMPLEMENTED();
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetStackSizeLimitInBytes(uptr limit) {
|
||||
|
@ -137,39 +144,40 @@ void Abort() {
|
|||
_exit(-1); // abort is not NORETURN on Windows.
|
||||
}
|
||||
|
||||
#ifndef SANITIZER_GO
|
||||
int Atexit(void (*function)(void)) {
|
||||
return atexit(function);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------ sanitizer_libc.h
|
||||
void *internal_mmap(void *addr, uptr length, int prot, int flags,
|
||||
int fd, u64 offset) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_munmap(void *addr, uptr length) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_close(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_isatty(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
fd_t internal_open(const char *filename, bool write) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_read(fd_t fd, void *buf, uptr count) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
||||
if (fd != 2)
|
||||
if (fd != kStderrFd)
|
||||
UNIMPLEMENTED();
|
||||
HANDLE err = GetStdHandle(STD_ERROR_HANDLE);
|
||||
if (err == 0)
|
||||
|
@ -182,21 +190,18 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
|
|||
|
||||
uptr internal_filesize(fd_t fd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_dup2(int oldfd, int newfd) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int internal_sched_yield() {
|
||||
UNIMPLEMENTED();
|
||||
Sleep(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ tsan_files = \
|
|||
tsan_suppressions.cc \
|
||||
tsan_interface_ann.cc \
|
||||
tsan_mman.cc \
|
||||
tsan_printf.cc \
|
||||
tsan_rtl_report.cc \
|
||||
tsan_symbolize_addr2line_linux.cc
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ am__objects_1 = tsan_clock.lo tsan_interface_atomic.lo tsan_mutex.lo \
|
|||
tsan_rtl.lo tsan_stat.lo tsan_sync.lo tsan_interceptors.lo \
|
||||
tsan_md5.lo tsan_platform_mac.lo tsan_rtl_mutex.lo \
|
||||
tsan_suppressions.lo tsan_interface_ann.lo tsan_mman.lo \
|
||||
tsan_printf.lo tsan_rtl_report.lo \
|
||||
tsan_rtl_report.lo \
|
||||
tsan_symbolize_addr2line_linux.lo
|
||||
am_libtsan_la_OBJECTS = $(am__objects_1)
|
||||
libtsan_la_OBJECTS = $(am_libtsan_la_OBJECTS)
|
||||
|
@ -261,7 +261,6 @@ tsan_files = \
|
|||
tsan_suppressions.cc \
|
||||
tsan_interface_ann.cc \
|
||||
tsan_mman.cc \
|
||||
tsan_printf.cc \
|
||||
tsan_rtl_report.cc \
|
||||
tsan_symbolize_addr2line_linux.cc
|
||||
|
||||
|
@ -395,7 +394,6 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_mutex.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_platform_mac.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_printf.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_report.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_rtl_mutex.Plo@am__quote@
|
||||
|
|
|
@ -103,13 +103,6 @@ void ThreadClock::acq_rel(SyncClock *dst) {
|
|||
release(dst);
|
||||
}
|
||||
|
||||
void ThreadClock::Disable(unsigned tid) {
|
||||
u64 c0 = clk_[tid];
|
||||
for (uptr i = 0; i < kMaxTidInClock; i++)
|
||||
clk_[i] = (u64)-1;
|
||||
clk_[tid] = c0;
|
||||
}
|
||||
|
||||
SyncClock::SyncClock()
|
||||
: clk_(MBlockClock) {
|
||||
}
|
||||
|
|
|
@ -59,8 +59,6 @@ struct ThreadClock {
|
|||
nclk_ = tid + 1;
|
||||
}
|
||||
|
||||
void Disable(unsigned tid);
|
||||
|
||||
uptr size() const {
|
||||
return nclk_;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
|
||||
namespace __tsan {
|
||||
|
||||
#ifdef TSAN_GO
|
||||
const char *const kTsanOptionsEnv = "GORACE";
|
||||
#else
|
||||
const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
|
||||
#endif
|
||||
|
||||
const int kTidBits = 13;
|
||||
const unsigned kMaxTid = 1 << kTidBits;
|
||||
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
|
||||
|
@ -34,20 +40,23 @@ const int kTraceStackSize = 256;
|
|||
#ifdef TSAN_SHADOW_COUNT
|
||||
# if TSAN_SHADOW_COUNT == 2 \
|
||||
|| TSAN_SHADOW_COUNT == 4 || TSAN_SHADOW_COUNT == 8
|
||||
const unsigned kShadowCnt = TSAN_SHADOW_COUNT;
|
||||
const uptr kShadowCnt = TSAN_SHADOW_COUNT;
|
||||
# else
|
||||
# error "TSAN_SHADOW_COUNT must be one of 2,4,8"
|
||||
# endif
|
||||
#else
|
||||
// Count of shadow values in a shadow cell.
|
||||
const unsigned kShadowCnt = 8;
|
||||
const uptr kShadowCnt = 4;
|
||||
#endif
|
||||
|
||||
// That many user bytes are mapped onto a single shadow cell.
|
||||
const unsigned kShadowCell = 8;
|
||||
const uptr kShadowCell = 8;
|
||||
|
||||
// Size of a single shadow value (u64).
|
||||
const unsigned kShadowSize = 8;
|
||||
const uptr kShadowSize = 8;
|
||||
|
||||
// Shadow memory is kShadowMultiplier times larger than user memory.
|
||||
const uptr kShadowMultiplier = kShadowSize * kShadowCnt / kShadowCell;
|
||||
|
||||
#if defined(TSAN_COLLECT_STATS) && TSAN_COLLECT_STATS
|
||||
const bool kCollectStats = true;
|
||||
|
|
|
@ -38,6 +38,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
f->enable_annotations = true;
|
||||
f->suppress_equal_stacks = true;
|
||||
f->suppress_equal_addresses = true;
|
||||
f->report_bugs = true;
|
||||
f->report_thread_leaks = true;
|
||||
f->report_destroy_locked = true;
|
||||
f->report_signal_unsafe = true;
|
||||
|
@ -45,7 +46,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
f->strip_path_prefix = "";
|
||||
f->suppressions = "";
|
||||
f->exitcode = 66;
|
||||
f->log_fileno = 2;
|
||||
f->log_fileno = kStderrFd;
|
||||
f->atexit_sleep_ms = 1000;
|
||||
f->verbosity = 0;
|
||||
f->profile_memory = "";
|
||||
|
@ -61,6 +62,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
ParseFlag(env, &f->enable_annotations, "enable_annotations");
|
||||
ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks");
|
||||
ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses");
|
||||
ParseFlag(env, &f->report_bugs, "report_bugs");
|
||||
ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
|
||||
ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
|
||||
ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
|
||||
|
@ -75,6 +77,12 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
|
||||
ParseFlag(env, &f->stop_on_start, "stop_on_start");
|
||||
ParseFlag(env, &f->external_symbolizer_path, "external_symbolizer_path");
|
||||
|
||||
if (!f->report_bugs) {
|
||||
f->report_thread_leaks = false;
|
||||
f->report_destroy_locked = false;
|
||||
f->report_signal_unsafe = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
|
|
@ -29,6 +29,8 @@ struct Flags {
|
|||
// Supress a race report if we've already output another race report
|
||||
// on the same address.
|
||||
bool suppress_equal_addresses;
|
||||
// Turns off bug reporting entirely (useful for benchmarking).
|
||||
bool report_bugs;
|
||||
// Report thread leaks at exit?
|
||||
bool report_thread_leaks;
|
||||
// Report destruction of a locked mutex?
|
||||
|
|
|
@ -113,6 +113,7 @@ struct SignalDesc {
|
|||
};
|
||||
|
||||
struct SignalContext {
|
||||
int in_blocking_func;
|
||||
int int_signal_send;
|
||||
int pending_signal_count;
|
||||
SignalDesc pending_signals[kSigCount];
|
||||
|
@ -134,8 +135,6 @@ static SignalContext *SigCtx(ThreadState *thr) {
|
|||
|
||||
static unsigned g_thread_finalize_key;
|
||||
|
||||
static void process_pending_signals(ThreadState *thr);
|
||||
|
||||
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
|
||||
uptr pc)
|
||||
: thr_(thr)
|
||||
|
@ -154,28 +153,43 @@ ScopedInterceptor::~ScopedInterceptor() {
|
|||
thr_->in_rtl--;
|
||||
if (thr_->in_rtl == 0) {
|
||||
FuncExit(thr_);
|
||||
process_pending_signals(thr_);
|
||||
ProcessPendingSignals(thr_);
|
||||
}
|
||||
CHECK_EQ(in_rtl_, thr_->in_rtl);
|
||||
}
|
||||
|
||||
#define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
|
||||
|
||||
struct BlockingCall {
|
||||
explicit BlockingCall(ThreadState *thr)
|
||||
: ctx(SigCtx(thr)) {
|
||||
ctx->in_blocking_func++;
|
||||
}
|
||||
|
||||
~BlockingCall() {
|
||||
ctx->in_blocking_func--;
|
||||
}
|
||||
|
||||
SignalContext *ctx;
|
||||
};
|
||||
|
||||
TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
|
||||
SCOPED_TSAN_INTERCEPTOR(sleep, sec);
|
||||
unsigned res = sleep(sec);
|
||||
unsigned res = BLOCK_REAL(sleep)(sec);
|
||||
AfterSleep(thr, pc);
|
||||
return res;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, usleep, long_t usec) {
|
||||
SCOPED_TSAN_INTERCEPTOR(usleep, usec);
|
||||
int res = usleep(usec);
|
||||
int res = BLOCK_REAL(usleep)(usec);
|
||||
AfterSleep(thr, pc);
|
||||
return res;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
|
||||
SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem);
|
||||
int res = nanosleep(req, rem);
|
||||
int res = BLOCK_REAL(nanosleep)(req, rem);
|
||||
AfterSleep(thr, pc);
|
||||
return res;
|
||||
}
|
||||
|
@ -236,7 +250,6 @@ static void finalize(void *arg) {
|
|||
{
|
||||
ScopedInRtl in_rtl;
|
||||
DestroyAndFree(atexit_ctx);
|
||||
REAL(usleep)(flags()->atexit_sleep_ms * 1000);
|
||||
}
|
||||
int status = Finalize(cur_thread());
|
||||
if (status)
|
||||
|
@ -251,13 +264,13 @@ TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
|
|||
|
||||
TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
|
||||
SCOPED_TSAN_INTERCEPTOR(longjmp, env, val);
|
||||
TsanPrintf("ThreadSanitizer: longjmp() is not supported\n");
|
||||
Printf("ThreadSanitizer: longjmp() is not supported\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, siglongjmp, void *env, int val) {
|
||||
SCOPED_TSAN_INTERCEPTOR(siglongjmp, env, val);
|
||||
TsanPrintf("ThreadSanitizer: siglongjmp() is not supported\n");
|
||||
Printf("ThreadSanitizer: siglongjmp() is not supported\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
|
@ -588,7 +601,7 @@ static void thread_finalize(void *v) {
|
|||
uptr iter = (uptr)v;
|
||||
if (iter > 1) {
|
||||
if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
|
||||
TsanPrintf("ThreadSanitizer: failed to set thread key\n");
|
||||
Printf("ThreadSanitizer: failed to set thread key\n");
|
||||
Die();
|
||||
}
|
||||
return;
|
||||
|
@ -621,7 +634,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
|
|||
ThreadState *thr = cur_thread();
|
||||
ScopedInRtl in_rtl;
|
||||
if (pthread_setspecific(g_thread_finalize_key, (void*)4)) {
|
||||
TsanPrintf("ThreadSanitizer: failed to set thread key\n");
|
||||
Printf("ThreadSanitizer: failed to set thread key\n");
|
||||
Die();
|
||||
}
|
||||
while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0)
|
||||
|
@ -676,7 +689,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
|
|||
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
|
||||
SCOPED_TSAN_INTERCEPTOR(pthread_join, th, ret);
|
||||
int tid = ThreadTid(thr, pc, (uptr)th);
|
||||
int res = REAL(pthread_join)(th, ret);
|
||||
int res = BLOCK_REAL(pthread_join)(th, ret);
|
||||
if (res == 0) {
|
||||
ThreadJoin(thr, pc, tid);
|
||||
}
|
||||
|
@ -979,7 +992,7 @@ TSAN_INTERCEPTOR(int, sem_destroy, void *s) {
|
|||
|
||||
TSAN_INTERCEPTOR(int, sem_wait, void *s) {
|
||||
SCOPED_TSAN_INTERCEPTOR(sem_wait, s);
|
||||
int res = REAL(sem_wait)(s);
|
||||
int res = BLOCK_REAL(sem_wait)(s);
|
||||
if (res == 0) {
|
||||
Acquire(thr, pc, (uptr)s);
|
||||
}
|
||||
|
@ -988,7 +1001,7 @@ TSAN_INTERCEPTOR(int, sem_wait, void *s) {
|
|||
|
||||
TSAN_INTERCEPTOR(int, sem_trywait, void *s) {
|
||||
SCOPED_TSAN_INTERCEPTOR(sem_trywait, s);
|
||||
int res = REAL(sem_trywait)(s);
|
||||
int res = BLOCK_REAL(sem_trywait)(s);
|
||||
if (res == 0) {
|
||||
Acquire(thr, pc, (uptr)s);
|
||||
}
|
||||
|
@ -997,7 +1010,7 @@ TSAN_INTERCEPTOR(int, sem_trywait, void *s) {
|
|||
|
||||
TSAN_INTERCEPTOR(int, sem_timedwait, void *s, void *abstime) {
|
||||
SCOPED_TSAN_INTERCEPTOR(sem_timedwait, s, abstime);
|
||||
int res = REAL(sem_timedwait)(s, abstime);
|
||||
int res = BLOCK_REAL(sem_timedwait)(s, abstime);
|
||||
if (res == 0) {
|
||||
Acquire(thr, pc, (uptr)s);
|
||||
}
|
||||
|
@ -1189,13 +1202,19 @@ TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
|
|||
|
||||
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
|
||||
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
|
||||
int res = REAL(epoll_wait)(epfd, ev, cnt, timeout);
|
||||
int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout);
|
||||
if (res > 0) {
|
||||
Acquire(thr, pc, epollfd2addr(epfd));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, poll, void *fds, long_t nfds, int timeout) {
|
||||
SCOPED_TSAN_INTERCEPTOR(poll, fds, nfds, timeout);
|
||||
int res = BLOCK_REAL(poll)(fds, nfds, timeout);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
|
||||
my_siginfo_t *info, void *ctx) {
|
||||
ThreadState *thr = cur_thread();
|
||||
|
@ -1203,7 +1222,12 @@ static void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
|
|||
// Don't mess with synchronous signals.
|
||||
if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
|
||||
sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE ||
|
||||
(sctx && sig == sctx->int_signal_send)) {
|
||||
// If we are sending signal to ourselves, we must process it now.
|
||||
(sctx && sig == sctx->int_signal_send) ||
|
||||
// If we are in blocking function, we can safely process it now
|
||||
// (but check if we are in a recursive interceptor,
|
||||
// i.e. pthread_join()->munmap()).
|
||||
(sctx && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) {
|
||||
CHECK(thr->in_rtl == 0 || thr->in_rtl == 1);
|
||||
int in_rtl = thr->in_rtl;
|
||||
thr->in_rtl = 0;
|
||||
|
@ -1317,7 +1341,15 @@ TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) {
|
|||
return res;
|
||||
}
|
||||
|
||||
static void process_pending_signals(ThreadState *thr) {
|
||||
TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
|
||||
SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz);
|
||||
// It's intercepted merely to process pending signals.
|
||||
return REAL(gettimeofday)(tv, tz);
|
||||
}
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
void ProcessPendingSignals(ThreadState *thr) {
|
||||
CHECK_EQ(thr->in_rtl, 0);
|
||||
SignalContext *sctx = SigCtx(thr);
|
||||
if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
|
||||
|
@ -1342,7 +1374,7 @@ static void process_pending_signals(ThreadState *thr) {
|
|||
sigactions[sig].sa_sigaction(sig, &signal->siginfo, &signal->ctx);
|
||||
else
|
||||
sigactions[sig].sa_handler(sig);
|
||||
if (errno != 0) {
|
||||
if (flags()->report_bugs && errno != 0) {
|
||||
ScopedInRtl in_rtl;
|
||||
__tsan::StackTrace stack;
|
||||
uptr pc = signal->sigaction ?
|
||||
|
@ -1364,8 +1396,6 @@ static void process_pending_signals(ThreadState *thr) {
|
|||
thr->in_signal_handler = false;
|
||||
}
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
void InitializeInterceptors() {
|
||||
CHECK_GT(cur_thread()->in_rtl, 0);
|
||||
|
||||
|
@ -1482,6 +1512,7 @@ void InitializeInterceptors() {
|
|||
|
||||
TSAN_INTERCEPT(epoll_ctl);
|
||||
TSAN_INTERCEPT(epoll_wait);
|
||||
TSAN_INTERCEPT(poll);
|
||||
|
||||
TSAN_INTERCEPT(sigaction);
|
||||
TSAN_INTERCEPT(signal);
|
||||
|
@ -1491,17 +1522,18 @@ void InitializeInterceptors() {
|
|||
TSAN_INTERCEPT(sleep);
|
||||
TSAN_INTERCEPT(usleep);
|
||||
TSAN_INTERCEPT(nanosleep);
|
||||
TSAN_INTERCEPT(gettimeofday);
|
||||
|
||||
atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
|
||||
AtExitContext();
|
||||
|
||||
if (__cxa_atexit(&finalize, 0, 0)) {
|
||||
TsanPrintf("ThreadSanitizer: failed to setup atexit callback\n");
|
||||
Printf("ThreadSanitizer: failed to setup atexit callback\n");
|
||||
Die();
|
||||
}
|
||||
|
||||
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
|
||||
TsanPrintf("ThreadSanitizer: failed to create thread key\n");
|
||||
Printf("ThreadSanitizer: failed to create thread key\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#ifndef TSAN_INTERFACE_H
|
||||
#define TSAN_INTERFACE_H
|
||||
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
// This header should NOT include any other headers.
|
||||
// All functions in this header are extern "C" and start with __tsan_.
|
||||
|
||||
|
@ -24,24 +23,24 @@ extern "C" {
|
|||
|
||||
// This function should be called at the very beginning of the process,
|
||||
// before any instrumented code is executed and before any call to malloc.
|
||||
void __tsan_init() SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_init();
|
||||
|
||||
void __tsan_read1(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_read2(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_read4(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_read8(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_read16(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_read1(void *addr);
|
||||
void __tsan_read2(void *addr);
|
||||
void __tsan_read4(void *addr);
|
||||
void __tsan_read8(void *addr);
|
||||
void __tsan_read16(void *addr);
|
||||
|
||||
void __tsan_write1(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_write2(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_write4(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_write8(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_write16(void *addr) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_write1(void *addr);
|
||||
void __tsan_write2(void *addr);
|
||||
void __tsan_write4(void *addr);
|
||||
void __tsan_write8(void *addr);
|
||||
void __tsan_write16(void *addr);
|
||||
|
||||
void __tsan_vptr_update(void **vptr_p, void *new_val) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_vptr_update(void **vptr_p, void *new_val);
|
||||
|
||||
void __tsan_func_entry(void *call_pc) SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_func_exit() SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_func_entry(void *call_pc);
|
||||
void __tsan_func_exit();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -157,57 +157,47 @@ bool IsExpectedReport(uptr addr, uptr size) {
|
|||
using namespace __tsan; // NOLINT
|
||||
|
||||
extern "C" {
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateHappensBefore(char *f, int l, uptr addr) {
|
||||
SCOPED_ANNOTATION(AnnotateHappensBefore);
|
||||
Release(cur_thread(), CALLERPC, addr);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateHappensAfter(char *f, int l, uptr addr) {
|
||||
SCOPED_ANNOTATION(AnnotateHappensAfter);
|
||||
Acquire(cur_thread(), CALLERPC, addr);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateCondVarSignal(char *f, int l, uptr cv) {
|
||||
SCOPED_ANNOTATION(AnnotateCondVarSignal);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
|
||||
SCOPED_ANNOTATION(AnnotateCondVarSignalAll);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
|
||||
SCOPED_ANNOTATION(AnnotateMutexIsNotPHB);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateCondVarWait(char *f, int l, uptr cv, uptr lock) {
|
||||
SCOPED_ANNOTATION(AnnotateCondVarWait);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateRWLockCreate(char *f, int l, uptr m) {
|
||||
SCOPED_ANNOTATION(AnnotateRWLockCreate);
|
||||
MutexCreate(thr, pc, m, true, true, false);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateRWLockCreateStatic(char *f, int l, uptr m) {
|
||||
SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);
|
||||
MutexCreate(thr, pc, m, true, true, true);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateRWLockDestroy(char *f, int l, uptr m) {
|
||||
SCOPED_ANNOTATION(AnnotateRWLockDestroy);
|
||||
MutexDestroy(thr, pc, m);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateRWLockAcquired(char *f, int l, uptr m, uptr is_w) {
|
||||
SCOPED_ANNOTATION(AnnotateRWLockAcquired);
|
||||
if (is_w)
|
||||
|
@ -216,7 +206,6 @@ void AnnotateRWLockAcquired(char *f, int l, uptr m, uptr is_w) {
|
|||
MutexReadLock(thr, pc, m);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateRWLockReleased(char *f, int l, uptr m, uptr is_w) {
|
||||
SCOPED_ANNOTATION(AnnotateRWLockReleased);
|
||||
if (is_w)
|
||||
|
@ -225,35 +214,30 @@ void AnnotateRWLockReleased(char *f, int l, uptr m, uptr is_w) {
|
|||
MutexReadUnlock(thr, pc, m);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateTraceMemory(char *f, int l, uptr mem) {
|
||||
SCOPED_ANNOTATION(AnnotateTraceMemory);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateFlushState(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateFlushState);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateNewMemory(char *f, int l, uptr mem, uptr size) {
|
||||
SCOPED_ANNOTATION(AnnotateNewMemory);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateNoOp(char *f, int l, uptr mem) {
|
||||
SCOPED_ANNOTATION(AnnotateNoOp);
|
||||
}
|
||||
|
||||
static void ReportMissedExpectedRace(ExpectRace *race) {
|
||||
TsanPrintf("==================\n");
|
||||
TsanPrintf("WARNING: ThreadSanitizer: missed expected data race\n");
|
||||
TsanPrintf(" %s addr=%zx %s:%d\n",
|
||||
Printf("==================\n");
|
||||
Printf("WARNING: ThreadSanitizer: missed expected data race\n");
|
||||
Printf(" %s addr=%zx %s:%d\n",
|
||||
race->desc, race->addr, race->file, race->line);
|
||||
TsanPrintf("==================\n");
|
||||
Printf("==================\n");
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateFlushExpectedRaces(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
|
||||
Lock lock(&dyn_ann_ctx->mtx);
|
||||
|
@ -269,38 +253,31 @@ void AnnotateFlushExpectedRaces(char *f, int l) {
|
|||
}
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateEnableRaceDetection(char *f, int l, int enable) {
|
||||
SCOPED_ANNOTATION(AnnotateEnableRaceDetection);
|
||||
// FIXME: Reconsider this functionality later. It may be irrelevant.
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateMutexIsUsedAsCondVar(char *f, int l, uptr mu) {
|
||||
SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotatePCQGet(char *f, int l, uptr pcq) {
|
||||
SCOPED_ANNOTATION(AnnotatePCQGet);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotatePCQPut(char *f, int l, uptr pcq) {
|
||||
SCOPED_ANNOTATION(AnnotatePCQPut);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotatePCQDestroy(char *f, int l, uptr pcq) {
|
||||
SCOPED_ANNOTATION(AnnotatePCQDestroy);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotatePCQCreate(char *f, int l, uptr pcq) {
|
||||
SCOPED_ANNOTATION(AnnotatePCQCreate);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateExpectRace(char *f, int l, uptr mem, char *desc) {
|
||||
SCOPED_ANNOTATION(AnnotateExpectRace);
|
||||
Lock lock(&dyn_ann_ctx->mtx);
|
||||
|
@ -317,73 +294,60 @@ static void BenignRaceImpl(char *f, int l, uptr mem, uptr size, char *desc) {
|
|||
}
|
||||
|
||||
// FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
|
||||
// SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateBenignRaceSized(char *f, int l, uptr mem, uptr size, char *desc) {
|
||||
SCOPED_ANNOTATION(AnnotateBenignRaceSized);
|
||||
BenignRaceImpl(f, l, mem, size, desc);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateBenignRace(char *f, int l, uptr mem, char *desc) {
|
||||
SCOPED_ANNOTATION(AnnotateBenignRace);
|
||||
BenignRaceImpl(f, l, mem, 1, desc);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateIgnoreReadsBegin(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
|
||||
IgnoreCtl(cur_thread(), false, true);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateIgnoreReadsEnd(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
|
||||
IgnoreCtl(cur_thread(), false, false);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateIgnoreWritesBegin(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
|
||||
IgnoreCtl(cur_thread(), true, true);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateIgnoreWritesEnd(char *f, int l) {
|
||||
SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
|
||||
IgnoreCtl(cur_thread(), true, false);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotatePublishMemoryRange(char *f, int l, uptr addr, uptr size) {
|
||||
SCOPED_ANNOTATION(AnnotatePublishMemoryRange);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateUnpublishMemoryRange(char *f, int l, uptr addr, uptr size) {
|
||||
SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void AnnotateThreadName(char *f, int l, char *name) {
|
||||
SCOPED_ANNOTATION(AnnotateThreadName);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
|
||||
SCOPED_ANNOTATION(AnnotateHappensBefore);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
|
||||
SCOPED_ANNOTATION(AnnotateHappensAfter);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void WTFAnnotateBenignRaceSized(char *f, int l, uptr mem, uptr sz, char *desc) {
|
||||
SCOPED_ANNOTATION(AnnotateBenignRaceSized);
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
int RunningOnValgrind() {
|
||||
return flags()->running_on_valgrind;
|
||||
}
|
||||
|
@ -392,7 +356,6 @@ double __attribute__((weak)) ValgrindSlowdown(void) {
|
|||
return 10.0;
|
||||
}
|
||||
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
|
||||
const char *ThreadSanitizerQuery(const char *query) {
|
||||
if (internal_strcmp(query, "pure_happens_before") == 0)
|
||||
return "1";
|
||||
|
|
|
@ -37,12 +37,12 @@ typedef __tsan_atomic8 a8;
|
|||
typedef __tsan_atomic16 a16;
|
||||
typedef __tsan_atomic32 a32;
|
||||
typedef __tsan_atomic64 a64;
|
||||
const int mo_relaxed = __tsan_memory_order_relaxed;
|
||||
const int mo_consume = __tsan_memory_order_consume;
|
||||
const int mo_acquire = __tsan_memory_order_acquire;
|
||||
const int mo_release = __tsan_memory_order_release;
|
||||
const int mo_acq_rel = __tsan_memory_order_acq_rel;
|
||||
const int mo_seq_cst = __tsan_memory_order_seq_cst;
|
||||
const morder mo_relaxed = __tsan_memory_order_relaxed;
|
||||
const morder mo_consume = __tsan_memory_order_consume;
|
||||
const morder mo_acquire = __tsan_memory_order_acquire;
|
||||
const morder mo_release = __tsan_memory_order_release;
|
||||
const morder mo_acq_rel = __tsan_memory_order_acq_rel;
|
||||
const morder mo_seq_cst = __tsan_memory_order_seq_cst;
|
||||
|
||||
static void AtomicStatInc(ThreadState *thr, uptr size, morder mo, StatType t) {
|
||||
StatInc(thr, StatAtomic);
|
||||
|
@ -77,10 +77,32 @@ static bool IsAcquireOrder(morder mo) {
|
|||
|| mo == mo_acq_rel || mo == mo_seq_cst;
|
||||
}
|
||||
|
||||
static morder ConvertOrder(morder mo) {
|
||||
if (mo > (morder)100500) {
|
||||
mo = morder(mo - 100500);
|
||||
if (mo == morder(1 << 0))
|
||||
mo = mo_relaxed;
|
||||
else if (mo == morder(1 << 1))
|
||||
mo = mo_consume;
|
||||
else if (mo == morder(1 << 2))
|
||||
mo = mo_acquire;
|
||||
else if (mo == morder(1 << 3))
|
||||
mo = mo_release;
|
||||
else if (mo == morder(1 << 4))
|
||||
mo = mo_acq_rel;
|
||||
else if (mo == morder(1 << 5))
|
||||
mo = mo_seq_cst;
|
||||
}
|
||||
CHECK_GE(mo, mo_relaxed);
|
||||
CHECK_LE(mo, mo_seq_cst);
|
||||
return mo;
|
||||
}
|
||||
|
||||
#define SCOPED_ATOMIC(func, ...) \
|
||||
if ((u32)mo > 100500) mo = (morder)((u32)mo - 100500); \
|
||||
mo = ConvertOrder(mo); \
|
||||
mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
|
||||
ThreadState *const thr = cur_thread(); \
|
||||
ProcessPendingSignals(thr); \
|
||||
const uptr pc = (uptr)__builtin_return_address(0); \
|
||||
AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
|
||||
ScopedAtomic sa(thr, pc, __FUNCTION__); \
|
||||
|
@ -187,6 +209,13 @@ static bool AtomicCAS(ThreadState *thr, uptr pc,
|
|||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T AtomicCAS(ThreadState *thr, uptr pc,
|
||||
volatile T *a, T c, T v, morder mo) {
|
||||
AtomicCAS(thr, pc, a, &c, v, mo);
|
||||
return c;
|
||||
}
|
||||
|
||||
static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
@ -359,6 +388,25 @@ int __tsan_atomic64_compare_exchange_weak(volatile a64 *a, a64 *c, a64 v,
|
|||
SCOPED_ATOMIC(CAS, a, c, v, mo);
|
||||
}
|
||||
|
||||
a8 __tsan_atomic8_compare_exchange_val(volatile a8 *a, a8 c, a8 v,
|
||||
morder mo) {
|
||||
SCOPED_ATOMIC(CAS, a, c, v, mo);
|
||||
}
|
||||
a16 __tsan_atomic16_compare_exchange_val(volatile a16 *a, a16 c, a16 v,
|
||||
morder mo) {
|
||||
SCOPED_ATOMIC(CAS, a, c, v, mo);
|
||||
}
|
||||
|
||||
a32 __tsan_atomic32_compare_exchange_val(volatile a32 *a, a32 c, a32 v,
|
||||
morder mo) {
|
||||
SCOPED_ATOMIC(CAS, a, c, v, mo);
|
||||
}
|
||||
|
||||
a64 __tsan_atomic64_compare_exchange_val(volatile a64 *a, a64 c, a64 v,
|
||||
morder mo) {
|
||||
SCOPED_ATOMIC(CAS, a, c, v, mo);
|
||||
}
|
||||
|
||||
void __tsan_atomic_thread_fence(morder mo) {
|
||||
char* a;
|
||||
SCOPED_ATOMIC(Fence, mo);
|
||||
|
|
|
@ -23,148 +23,119 @@ typedef long __tsan_atomic64; // NOLINT
|
|||
// Part of ABI, do not change.
|
||||
// http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/atomic?view=markup
|
||||
typedef enum {
|
||||
__tsan_memory_order_relaxed = 1 << 0,
|
||||
__tsan_memory_order_consume = 1 << 1,
|
||||
__tsan_memory_order_acquire = 1 << 2,
|
||||
__tsan_memory_order_release = 1 << 3,
|
||||
__tsan_memory_order_acq_rel = 1 << 4,
|
||||
__tsan_memory_order_seq_cst = 1 << 5
|
||||
__tsan_memory_order_relaxed,
|
||||
__tsan_memory_order_consume,
|
||||
__tsan_memory_order_acquire,
|
||||
__tsan_memory_order_release,
|
||||
__tsan_memory_order_acq_rel,
|
||||
__tsan_memory_order_seq_cst
|
||||
} __tsan_memory_order;
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
|
||||
void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_sub(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_sub(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_sub(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_sub(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 v, __tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 v, __tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 v, __tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo);
|
||||
int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo);
|
||||
|
||||
void __tsan_atomic_thread_fence(__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
void __tsan_atomic_signal_fence(__tsan_memory_order mo)
|
||||
SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
|
||||
__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
|
||||
volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
|
||||
volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
|
||||
volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
|
||||
__tsan_memory_order mo);
|
||||
__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
|
||||
volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
|
||||
__tsan_memory_order mo);
|
||||
|
||||
void __tsan_atomic_thread_fence(__tsan_memory_order mo);
|
||||
void __tsan_atomic_signal_fence(__tsan_memory_order mo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -90,25 +90,25 @@ void InitializeMutex() {
|
|||
}
|
||||
}
|
||||
#if 0
|
||||
TsanPrintf("Can lock graph:\n");
|
||||
Printf("Can lock graph:\n");
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
TsanPrintf("%d ", CanLockAdj[i][j]);
|
||||
Printf("%d ", CanLockAdj[i][j]);
|
||||
}
|
||||
TsanPrintf("\n");
|
||||
Printf("\n");
|
||||
}
|
||||
TsanPrintf("Can lock graph closure:\n");
|
||||
Printf("Can lock graph closure:\n");
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++) {
|
||||
TsanPrintf("%d ", CanLockAdj2[i][j]);
|
||||
Printf("%d ", CanLockAdj2[i][j]);
|
||||
}
|
||||
TsanPrintf("\n");
|
||||
Printf("\n");
|
||||
}
|
||||
#endif
|
||||
// Verify that the graph is acyclic.
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (CanLockAdj2[i][i]) {
|
||||
TsanPrintf("Mutex %d participates in a cycle\n", i);
|
||||
Printf("Mutex %d participates in a cycle\n", i);
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ DeadlockDetector::DeadlockDetector() {
|
|||
}
|
||||
|
||||
void DeadlockDetector::Lock(MutexType t) {
|
||||
// TsanPrintf("LOCK %d @%zu\n", t, seq_ + 1);
|
||||
// Printf("LOCK %d @%zu\n", t, seq_ + 1);
|
||||
u64 max_seq = 0;
|
||||
u64 max_idx = MutexTypeInvalid;
|
||||
for (int i = 0; i != MutexTypeCount; i++) {
|
||||
|
@ -134,17 +134,17 @@ void DeadlockDetector::Lock(MutexType t) {
|
|||
locked_[t] = ++seq_;
|
||||
if (max_idx == MutexTypeInvalid)
|
||||
return;
|
||||
// TsanPrintf(" last %d @%zu\n", max_idx, max_seq);
|
||||
// Printf(" last %d @%zu\n", max_idx, max_seq);
|
||||
if (!CanLockAdj[max_idx][t]) {
|
||||
TsanPrintf("ThreadSanitizer: internal deadlock detected\n");
|
||||
TsanPrintf("ThreadSanitizer: can't lock %d while under %zu\n",
|
||||
Printf("ThreadSanitizer: internal deadlock detected\n");
|
||||
Printf("ThreadSanitizer: can't lock %d while under %zu\n",
|
||||
t, (uptr)max_idx);
|
||||
CHECK(0);
|
||||
}
|
||||
}
|
||||
|
||||
void DeadlockDetector::Unlock(MutexType t) {
|
||||
// TsanPrintf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
|
||||
// Printf("UNLO %d @%zu #%zu\n", t, seq_, locked_[t]);
|
||||
CHECK(locked_[t]);
|
||||
locked_[t] = 0;
|
||||
}
|
||||
|
|
|
@ -15,13 +15,17 @@
|
|||
|
||||
#include "tsan_rtl.h"
|
||||
|
||||
#if __LP64__
|
||||
#if defined(__LP64__) || defined(_WIN64)
|
||||
namespace __tsan {
|
||||
|
||||
#if defined(TSAN_GO)
|
||||
static const uptr kLinuxAppMemBeg = 0x000000000000ULL;
|
||||
static const uptr kLinuxAppMemEnd = 0x00fcffffffffULL;
|
||||
# if defined(_WIN32)
|
||||
static const uptr kLinuxShadowMsk = 0x010000000000ULL;
|
||||
# else
|
||||
static const uptr kLinuxShadowMsk = 0x100000000000ULL;
|
||||
# endif
|
||||
// TSAN_COMPAT_SHADOW is intended for COMPAT virtual memory layout,
|
||||
// when memory addresses are of the 0x2axxxxxxxxxx form.
|
||||
// The option is enabled with 'setarch x86_64 -L'.
|
||||
|
@ -93,7 +97,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
|||
|
||||
} // namespace __tsan
|
||||
|
||||
#else // __LP64__
|
||||
#else // defined(__LP64__) || defined(_WIN64)
|
||||
# error "Only 64-bit is supported"
|
||||
#endif
|
||||
|
||||
|
|
|
@ -81,46 +81,42 @@ static void ProtectRange(uptr beg, uptr end) {
|
|||
if (beg == end)
|
||||
return;
|
||||
if (beg != (uptr)Mprotect(beg, end - beg)) {
|
||||
TsanPrintf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
|
||||
TsanPrintf("FATAL: Make sure you are not using unlimited stack\n");
|
||||
Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
|
||||
Printf("FATAL: Make sure you are not using unlimited stack\n");
|
||||
Die();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef TSAN_GO
|
||||
void InitializeShadowMemory() {
|
||||
uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
|
||||
kLinuxShadowEnd - kLinuxShadowBeg);
|
||||
if (shadow != kLinuxShadowBeg) {
|
||||
TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
TsanPrintf("FATAL: Make sure to compile with -fPIE and "
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
|
||||
Die();
|
||||
}
|
||||
#ifndef TSAN_GO
|
||||
const uptr kClosedLowBeg = 0x200000;
|
||||
const uptr kClosedLowEnd = kLinuxShadowBeg - 1;
|
||||
const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
|
||||
const uptr kClosedMidEnd = kLinuxAppMemBeg - 1;
|
||||
ProtectRange(kClosedLowBeg, kClosedLowEnd);
|
||||
ProtectRange(kClosedMidBeg, kClosedMidEnd);
|
||||
#endif
|
||||
#ifndef TSAN_GO
|
||||
DPrintf("kClosedLow %zx-%zx (%zuGB)\n",
|
||||
kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
|
||||
#endif
|
||||
DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
|
||||
kLinuxShadowBeg, kLinuxShadowEnd,
|
||||
(kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
|
||||
#ifndef TSAN_GO
|
||||
DPrintf("kClosedMid %zx-%zx (%zuGB)\n",
|
||||
kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
|
||||
#endif
|
||||
DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
|
||||
kLinuxAppMemBeg, kLinuxAppMemEnd,
|
||||
(kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
|
||||
DPrintf("stack %zx\n", (uptr)&shadow);
|
||||
}
|
||||
#endif
|
||||
|
||||
static uptr g_data_start;
|
||||
static uptr g_data_end;
|
||||
|
@ -133,10 +129,10 @@ static void CheckPIE() {
|
|||
if (proc_maps.Next(&start, &end,
|
||||
/*offset*/0, /*filename*/0, /*filename_size*/0)) {
|
||||
if ((u64)start < kLinuxAppMemBeg) {
|
||||
TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
|
||||
"something is mapped at 0x%zx < 0x%zx)\n",
|
||||
start, kLinuxAppMemBeg);
|
||||
TsanPrintf("FATAL: Make sure to compile with -fPIE"
|
||||
Printf("FATAL: Make sure to compile with -fPIE"
|
||||
" and to link with -pie.\n");
|
||||
Die();
|
||||
}
|
||||
|
@ -221,7 +217,7 @@ const char *InitializePlatform() {
|
|||
g_tls_size = (uptr)InitTlsSize();
|
||||
InitDataSeg();
|
||||
#endif
|
||||
return getenv("TSAN_OPTIONS");
|
||||
return getenv(kTsanOptionsEnv);
|
||||
}
|
||||
|
||||
void FinalizePlatform() {
|
||||
|
|
|
@ -50,13 +50,14 @@ uptr GetShadowMemoryConsumption() {
|
|||
void FlushShadowMemory() {
|
||||
}
|
||||
|
||||
#ifndef TSAN_GO
|
||||
void InitializeShadowMemory() {
|
||||
uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
|
||||
kLinuxShadowEnd - kLinuxShadowBeg);
|
||||
if (shadow != kLinuxShadowBeg) {
|
||||
TsanPrintf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
TsanPrintf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie.\n");
|
||||
Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
|
||||
Printf("FATAL: Make sure to compile with -fPIE and "
|
||||
"to link with -pie.\n");
|
||||
Die();
|
||||
}
|
||||
DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
|
||||
|
@ -66,6 +67,7 @@ void InitializeShadowMemory() {
|
|||
kLinuxAppMemBeg, kLinuxAppMemEnd,
|
||||
(kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *InitializePlatform() {
|
||||
void *p = 0;
|
||||
|
@ -78,7 +80,7 @@ const char *InitializePlatform() {
|
|||
setrlimit(RLIMIT_CORE, (rlimit*)&lim);
|
||||
}
|
||||
|
||||
return getenv("TSAN_OPTIONS");
|
||||
return getenv(kTsanOptionsEnv);
|
||||
}
|
||||
|
||||
void FinalizePlatform() {
|
||||
|
|
56
libsanitizer/tsan/tsan_platform_windows.cc
Normal file
56
libsanitizer/tsan/tsan_platform_windows.cc
Normal file
|
@ -0,0 +1,56 @@
|
|||
//===-- tsan_platform_windows.cc ------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
// Windows-specific code.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "tsan_platform.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
ScopedInRtl::ScopedInRtl() {
|
||||
}
|
||||
|
||||
ScopedInRtl::~ScopedInRtl() {
|
||||
}
|
||||
|
||||
uptr GetShadowMemoryConsumption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FlushShadowMemory() {
|
||||
}
|
||||
|
||||
const char *InitializePlatform() {
|
||||
return getenv(kTsanOptionsEnv);
|
||||
}
|
||||
|
||||
void FinalizePlatform() {
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
uptr GetTlsSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
|
||||
uptr *tls_addr, uptr *tls_size) {
|
||||
*stk_addr = 0;
|
||||
*stk_size = 0;
|
||||
*tls_addr = 0;
|
||||
*tls_size = 0;
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // #ifdef _WIN32
|
|
@ -1,38 +0,0 @@
|
|||
//===-- tsan_printf.cc ----------------------------------------------------===//
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "tsan_defs.h"
|
||||
#include "tsan_mman.h"
|
||||
#include "tsan_platform.h"
|
||||
|
||||
#include <stdarg.h> // va_list
|
||||
|
||||
namespace __sanitizer {
|
||||
int VSNPrintf(char *buff, int buff_length, const char *format, va_list args);
|
||||
} // namespace __sanitizer
|
||||
|
||||
namespace __tsan {
|
||||
|
||||
void TsanPrintf(const char *format, ...) {
|
||||
ScopedInRtl in_rtl;
|
||||
const uptr kMaxLen = 16 * 1024;
|
||||
InternalScopedBuffer<char> buffer(kMaxLen);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
uptr len = VSNPrintf(buffer.data(), buffer.size(), format, args);
|
||||
va_end(args);
|
||||
internal_write(CTX() ? flags()->log_fileno : 2,
|
||||
buffer.data(), len < buffer.size() ? len : buffer.size() - 1);
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
|
@ -29,98 +29,102 @@ ReportDesc::~ReportDesc() {
|
|||
#ifndef TSAN_GO
|
||||
|
||||
static void PrintHeader(ReportType typ) {
|
||||
TsanPrintf("WARNING: ThreadSanitizer: ");
|
||||
Printf("WARNING: ThreadSanitizer: ");
|
||||
|
||||
if (typ == ReportTypeRace)
|
||||
TsanPrintf("data race");
|
||||
Printf("data race");
|
||||
else if (typ == ReportTypeUseAfterFree)
|
||||
TsanPrintf("heap-use-after-free");
|
||||
Printf("heap-use-after-free");
|
||||
else if (typ == ReportTypeThreadLeak)
|
||||
TsanPrintf("thread leak");
|
||||
Printf("thread leak");
|
||||
else if (typ == ReportTypeMutexDestroyLocked)
|
||||
TsanPrintf("destroy of a locked mutex");
|
||||
Printf("destroy of a locked mutex");
|
||||
else if (typ == ReportTypeSignalUnsafe)
|
||||
TsanPrintf("signal-unsafe call inside of a signal");
|
||||
Printf("signal-unsafe call inside of a signal");
|
||||
else if (typ == ReportTypeErrnoInSignal)
|
||||
TsanPrintf("signal handler spoils errno");
|
||||
Printf("signal handler spoils errno");
|
||||
|
||||
TsanPrintf(" (pid=%d)\n", GetPid());
|
||||
Printf(" (pid=%d)\n", GetPid());
|
||||
}
|
||||
|
||||
void PrintStack(const ReportStack *ent) {
|
||||
for (int i = 0; ent; ent = ent->next, i++) {
|
||||
TsanPrintf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line);
|
||||
if (ent->col)
|
||||
TsanPrintf(":%d", ent->col);
|
||||
if (ent->module && ent->offset)
|
||||
TsanPrintf(" (%s+%p)\n", ent->module, (void*)ent->offset);
|
||||
else
|
||||
TsanPrintf(" (%p)\n", (void*)ent->pc);
|
||||
if (ent == 0) {
|
||||
Printf(" [failed to restore the stack]\n\n");
|
||||
return;
|
||||
}
|
||||
TsanPrintf("\n");
|
||||
for (int i = 0; ent; ent = ent->next, i++) {
|
||||
Printf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line);
|
||||
if (ent->col)
|
||||
Printf(":%d", ent->col);
|
||||
if (ent->module && ent->offset)
|
||||
Printf(" (%s+%p)\n", ent->module, (void*)ent->offset);
|
||||
else
|
||||
Printf(" (%p)\n", (void*)ent->pc);
|
||||
}
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
static void PrintMop(const ReportMop *mop, bool first) {
|
||||
TsanPrintf(" %s of size %d at %p",
|
||||
Printf(" %s of size %d at %p",
|
||||
(first ? (mop->write ? "Write" : "Read")
|
||||
: (mop->write ? "Previous write" : "Previous read")),
|
||||
mop->size, (void*)mop->addr);
|
||||
if (mop->tid == 0)
|
||||
TsanPrintf(" by main thread:\n");
|
||||
Printf(" by main thread:\n");
|
||||
else
|
||||
TsanPrintf(" by thread %d:\n", mop->tid);
|
||||
Printf(" by thread %d:\n", mop->tid);
|
||||
PrintStack(mop->stack);
|
||||
}
|
||||
|
||||
static void PrintLocation(const ReportLocation *loc) {
|
||||
if (loc->type == ReportLocationGlobal) {
|
||||
TsanPrintf(" Location is global '%s' of size %zu at %zx %s:%d\n",
|
||||
Printf(" Location is global '%s' of size %zu at %zx %s:%d\n",
|
||||
loc->name, loc->size, loc->addr, loc->file, loc->line);
|
||||
} else if (loc->type == ReportLocationHeap) {
|
||||
TsanPrintf(" Location is heap block of size %zu at %p allocated",
|
||||
Printf(" Location is heap block of size %zu at %p allocated",
|
||||
loc->size, loc->addr);
|
||||
if (loc->tid == 0)
|
||||
TsanPrintf(" by main thread:\n");
|
||||
Printf(" by main thread:\n");
|
||||
else
|
||||
TsanPrintf(" by thread %d:\n", loc->tid);
|
||||
Printf(" by thread %d:\n", loc->tid);
|
||||
PrintStack(loc->stack);
|
||||
} else if (loc->type == ReportLocationStack) {
|
||||
TsanPrintf(" Location is stack of thread %d:\n", loc->tid);
|
||||
Printf(" Location is stack of thread %d:\n", loc->tid);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintMutex(const ReportMutex *rm) {
|
||||
if (rm->stack == 0)
|
||||
return;
|
||||
TsanPrintf(" Mutex %d created at:\n", rm->id);
|
||||
Printf(" Mutex %d created at:\n", rm->id);
|
||||
PrintStack(rm->stack);
|
||||
}
|
||||
|
||||
static void PrintThread(const ReportThread *rt) {
|
||||
if (rt->id == 0) // Little sense in describing the main thread.
|
||||
return;
|
||||
TsanPrintf(" Thread %d", rt->id);
|
||||
Printf(" Thread %d", rt->id);
|
||||
if (rt->name)
|
||||
TsanPrintf(" '%s'", rt->name);
|
||||
TsanPrintf(" (tid=%zu, %s)", rt->pid, rt->running ? "running" : "finished");
|
||||
Printf(" '%s'", rt->name);
|
||||
Printf(" (tid=%zu, %s)", rt->pid, rt->running ? "running" : "finished");
|
||||
if (rt->stack)
|
||||
TsanPrintf(" created at:");
|
||||
TsanPrintf("\n");
|
||||
Printf(" created at:");
|
||||
Printf("\n");
|
||||
PrintStack(rt->stack);
|
||||
}
|
||||
|
||||
static void PrintSleep(const ReportStack *s) {
|
||||
TsanPrintf(" As if synchronized via sleep:\n");
|
||||
Printf(" As if synchronized via sleep:\n");
|
||||
PrintStack(s);
|
||||
}
|
||||
|
||||
void PrintReport(const ReportDesc *rep) {
|
||||
TsanPrintf("==================\n");
|
||||
Printf("==================\n");
|
||||
PrintHeader(rep->typ);
|
||||
|
||||
for (uptr i = 0; i < rep->stacks.Size(); i++) {
|
||||
if (i)
|
||||
TsanPrintf(" and:\n");
|
||||
Printf(" and:\n");
|
||||
PrintStack(rep->stacks[i]);
|
||||
}
|
||||
|
||||
|
@ -139,21 +143,21 @@ void PrintReport(const ReportDesc *rep) {
|
|||
for (uptr i = 0; i < rep->threads.Size(); i++)
|
||||
PrintThread(rep->threads[i]);
|
||||
|
||||
TsanPrintf("==================\n");
|
||||
Printf("==================\n");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void PrintStack(const ReportStack *ent) {
|
||||
for (int i = 0; ent; ent = ent->next, i++) {
|
||||
TsanPrintf(" %s()\n %s:%d +0x%zx\n",
|
||||
Printf(" %s()\n %s:%d +0x%zx\n",
|
||||
ent->func, ent->file, ent->line, (void*)ent->offset);
|
||||
}
|
||||
TsanPrintf("\n");
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
static void PrintMop(const ReportMop *mop, bool first) {
|
||||
TsanPrintf("%s by goroutine %d:\n",
|
||||
Printf("%s by goroutine %d:\n",
|
||||
(first ? (mop->write ? "Write" : "Read")
|
||||
: (mop->write ? "Previous write" : "Previous read")),
|
||||
mop->tid);
|
||||
|
@ -163,19 +167,19 @@ static void PrintMop(const ReportMop *mop, bool first) {
|
|||
static void PrintThread(const ReportThread *rt) {
|
||||
if (rt->id == 0) // Little sense in describing the main thread.
|
||||
return;
|
||||
TsanPrintf("Goroutine %d (%s) created at:\n",
|
||||
Printf("Goroutine %d (%s) created at:\n",
|
||||
rt->id, rt->running ? "running" : "finished");
|
||||
PrintStack(rt->stack);
|
||||
}
|
||||
|
||||
void PrintReport(const ReportDesc *rep) {
|
||||
TsanPrintf("==================\n");
|
||||
TsanPrintf("WARNING: DATA RACE\n");
|
||||
Printf("==================\n");
|
||||
Printf("WARNING: DATA RACE\n");
|
||||
for (uptr i = 0; i < rep->mops.Size(); i++)
|
||||
PrintMop(rep->mops[i], i == 0);
|
||||
for (uptr i = 0; i < rep->threads.Size(); i++)
|
||||
PrintThread(rep->threads[i]);
|
||||
TsanPrintf("==================\n");
|
||||
Printf("==================\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -137,7 +137,7 @@ static void InitializeMemoryProfile() {
|
|||
flags()->profile_memory, GetPid());
|
||||
fd_t fd = internal_open(filename.data(), true);
|
||||
if (fd == kInvalidFd) {
|
||||
TsanPrintf("Failed to open memory profile file '%s'\n", &filename[0]);
|
||||
Printf("Failed to open memory profile file '%s'\n", &filename[0]);
|
||||
Die();
|
||||
}
|
||||
internal_start_thread(&MemoryProfileThread, (void*)(uptr)fd);
|
||||
|
@ -159,6 +159,10 @@ static void InitializeMemoryFlush() {
|
|||
internal_start_thread(&MemoryFlushThread, 0);
|
||||
}
|
||||
|
||||
void MapShadow(uptr addr, uptr size) {
|
||||
MmapFixedNoReserve(MemToShadow(addr), size * kShadowMultiplier);
|
||||
}
|
||||
|
||||
void Initialize(ThreadState *thr) {
|
||||
// Thread safe because done before all threads exist.
|
||||
static bool is_initialized = false;
|
||||
|
@ -177,24 +181,32 @@ void Initialize(ThreadState *thr) {
|
|||
InitializeMutex();
|
||||
InitializeDynamicAnnotations();
|
||||
ctx = new(ctx_placeholder) Context;
|
||||
#ifndef TSAN_GO
|
||||
InitializeShadowMemory();
|
||||
#endif
|
||||
ctx->dead_list_size = 0;
|
||||
ctx->dead_list_head = 0;
|
||||
ctx->dead_list_tail = 0;
|
||||
InitializeFlags(&ctx->flags, env);
|
||||
// Setup correct file descriptor for error reports.
|
||||
__sanitizer_set_report_fd(flags()->log_fileno);
|
||||
InitializeSuppressions();
|
||||
#ifndef TSAN_GO
|
||||
// Initialize external symbolizer before internal threads are started.
|
||||
const char *external_symbolizer = flags()->external_symbolizer_path;
|
||||
if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
|
||||
InitializeExternalSymbolizer(external_symbolizer);
|
||||
if (!InitializeExternalSymbolizer(external_symbolizer)) {
|
||||
Printf("Failed to start external symbolizer: '%s'\n",
|
||||
external_symbolizer);
|
||||
Die();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
InitializeMemoryProfile();
|
||||
InitializeMemoryFlush();
|
||||
|
||||
if (ctx->flags.verbosity)
|
||||
TsanPrintf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
|
||||
Printf("***** Running under ThreadSanitizer v2 (pid %d) *****\n",
|
||||
GetPid());
|
||||
|
||||
// Initialize thread 0.
|
||||
|
@ -206,7 +218,7 @@ void Initialize(ThreadState *thr) {
|
|||
ctx->initialized = true;
|
||||
|
||||
if (flags()->stop_on_start) {
|
||||
TsanPrintf("ThreadSanitizer is suspended at startup (pid %d)."
|
||||
Printf("ThreadSanitizer is suspended at startup (pid %d)."
|
||||
" Call __tsan_resume().\n",
|
||||
GetPid());
|
||||
while (__tsan_resumed == 0);
|
||||
|
@ -218,6 +230,9 @@ int Finalize(ThreadState *thr) {
|
|||
Context *ctx = __tsan::ctx;
|
||||
bool failed = false;
|
||||
|
||||
if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
|
||||
SleepForMillis(flags()->atexit_sleep_ms);
|
||||
|
||||
// Wait for pending reports.
|
||||
ctx->report_mtx.Lock();
|
||||
ctx->report_mtx.Unlock();
|
||||
|
@ -226,15 +241,20 @@ int Finalize(ThreadState *thr) {
|
|||
|
||||
if (ctx->nreported) {
|
||||
failed = true;
|
||||
TsanPrintf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
|
||||
#ifndef TSAN_GO
|
||||
Printf("ThreadSanitizer: reported %d warnings\n", ctx->nreported);
|
||||
#else
|
||||
Printf("Found %d data race(s)\n", ctx->nreported);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->nmissed_expected) {
|
||||
failed = true;
|
||||
TsanPrintf("ThreadSanitizer: missed %d expected races\n",
|
||||
Printf("ThreadSanitizer: missed %d expected races\n",
|
||||
ctx->nmissed_expected);
|
||||
}
|
||||
|
||||
StatAggregate(ctx->stat, thr->stat);
|
||||
StatOutput(ctx->stat);
|
||||
return failed ? flags()->exitcode : 0;
|
||||
}
|
||||
|
@ -298,18 +318,22 @@ static inline void HandleRace(ThreadState *thr, u64 *shadow_mem,
|
|||
thr->racy_state[0] = cur.raw();
|
||||
thr->racy_state[1] = old.raw();
|
||||
thr->racy_shadow_addr = shadow_mem;
|
||||
#ifndef TSAN_GO
|
||||
HACKY_CALL(__tsan_report_race);
|
||||
#else
|
||||
ReportRace(thr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool BothReads(Shadow s, int kAccessIsWrite) {
|
||||
return !kAccessIsWrite && !s.is_write();
|
||||
}
|
||||
|
||||
static inline bool OldIsRWStronger(Shadow old, int kAccessIsWrite) {
|
||||
static inline bool OldIsRWNotWeaker(Shadow old, int kAccessIsWrite) {
|
||||
return old.is_write() || !kAccessIsWrite;
|
||||
}
|
||||
|
||||
static inline bool OldIsRWWeaker(Shadow old, int kAccessIsWrite) {
|
||||
static inline bool OldIsRWWeakerOrEqual(Shadow old, int kAccessIsWrite) {
|
||||
return !old.is_write() || kAccessIsWrite;
|
||||
}
|
||||
|
||||
|
@ -323,7 +347,7 @@ static inline bool HappensBefore(Shadow old, ThreadState *thr) {
|
|||
|
||||
ALWAYS_INLINE
|
||||
void MemoryAccessImpl(ThreadState *thr, uptr addr,
|
||||
int kAccessSizeLog, bool kAccessIsWrite, FastState fast_state,
|
||||
int kAccessSizeLog, bool kAccessIsWrite,
|
||||
u64 *shadow_mem, Shadow cur) {
|
||||
StatInc(thr, StatMop);
|
||||
StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
|
||||
|
@ -407,11 +431,11 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
|
|||
(uptr)shadow_mem[2], (uptr)shadow_mem[3]);
|
||||
#if TSAN_DEBUG
|
||||
if (!IsAppMem(addr)) {
|
||||
TsanPrintf("Access to non app mem %zx\n", addr);
|
||||
Printf("Access to non app mem %zx\n", addr);
|
||||
DCHECK(IsAppMem(addr));
|
||||
}
|
||||
if (!IsShadowMem((uptr)shadow_mem)) {
|
||||
TsanPrintf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||
Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||
DCHECK(IsShadowMem((uptr)shadow_mem));
|
||||
}
|
||||
#endif
|
||||
|
@ -429,7 +453,7 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
|
|||
// That is, this call must be moved somewhere below.
|
||||
TraceAddEvent(thr, fast_state.epoch(), EventTypeMop, pc);
|
||||
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, fast_state,
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite,
|
||||
shadow_mem, cur);
|
||||
}
|
||||
|
||||
|
@ -491,6 +515,7 @@ void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
|
|||
MemoryRangeSet(thr, pc, addr, size, s.raw());
|
||||
}
|
||||
|
||||
ALWAYS_INLINE
|
||||
void FuncEntry(ThreadState *thr, uptr pc) {
|
||||
DCHECK_EQ(thr->in_rtl, 0);
|
||||
StatInc(thr, StatFuncEnter);
|
||||
|
@ -520,6 +545,7 @@ void FuncEntry(ThreadState *thr, uptr pc) {
|
|||
thr->shadow_stack_pos++;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE
|
||||
void FuncExit(ThreadState *thr) {
|
||||
DCHECK_EQ(thr->in_rtl, 0);
|
||||
StatInc(thr, StatFuncExit);
|
||||
|
|
|
@ -25,11 +25,7 @@
|
|||
#define TSAN_RTL_H
|
||||
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#if __WORDSIZE == 64
|
||||
#include "sanitizer_common/sanitizer_allocator64.h"
|
||||
#else
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#endif
|
||||
#include "tsan_clock.h"
|
||||
#include "tsan_defs.h"
|
||||
#include "tsan_flags.h"
|
||||
|
@ -69,7 +65,6 @@ Allocator *allocator();
|
|||
|
||||
void TsanCheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2);
|
||||
void TsanPrintf(const char *format, ...);
|
||||
|
||||
// FastState (from most significant bit):
|
||||
// unused : 1
|
||||
|
@ -234,10 +229,6 @@ class Shadow : public FastState {
|
|||
}
|
||||
};
|
||||
|
||||
// Freed memory.
|
||||
// As if 8-byte write by thread 0xff..f at epoch 0xff..f, races with everything.
|
||||
const u64 kShadowFreed = 0xfffffffffffffff8ull;
|
||||
|
||||
struct SignalContext;
|
||||
|
||||
// This struct is stored in TLS.
|
||||
|
@ -442,6 +433,7 @@ void ALWAYS_INLINE INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
|
|||
thr->stat[typ] += n;
|
||||
}
|
||||
|
||||
void MapShadow(uptr addr, uptr size);
|
||||
void InitializeShadowMemory();
|
||||
void InitializeInterceptors();
|
||||
void InitializeDynamicAnnotations();
|
||||
|
@ -456,13 +448,13 @@ bool IsFiredSuppression(Context *ctx,
|
|||
bool IsExpectedReport(uptr addr, uptr size);
|
||||
|
||||
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
|
||||
# define DPrintf TsanPrintf
|
||||
# define DPrintf Printf
|
||||
#else
|
||||
# define DPrintf(...)
|
||||
#endif
|
||||
|
||||
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 2
|
||||
# define DPrintf2 TsanPrintf
|
||||
# define DPrintf2 Printf
|
||||
#else
|
||||
# define DPrintf2(...)
|
||||
#endif
|
||||
|
@ -476,7 +468,7 @@ int Finalize(ThreadState *thr);
|
|||
void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
|
||||
int kAccessSizeLog, bool kAccessIsWrite);
|
||||
void MemoryAccessImpl(ThreadState *thr, uptr addr,
|
||||
int kAccessSizeLog, bool kAccessIsWrite, FastState fast_state,
|
||||
int kAccessSizeLog, bool kAccessIsWrite,
|
||||
u64 *shadow_mem, Shadow cur);
|
||||
void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr);
|
||||
void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr);
|
||||
|
@ -499,7 +491,8 @@ int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
|
|||
void ThreadJoin(ThreadState *thr, uptr pc, int tid);
|
||||
void ThreadDetach(ThreadState *thr, uptr pc, int tid);
|
||||
void ThreadFinalize(ThreadState *thr);
|
||||
void ThreadFinalizerGoroutine(ThreadState *thr);
|
||||
int ThreadCount(ThreadState *thr);
|
||||
void ProcessPendingSignals(ThreadState *thr);
|
||||
|
||||
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
|
||||
bool rw, bool recursive, bool linker_init);
|
||||
|
@ -511,6 +504,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
|
|||
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
|
||||
|
||||
void Acquire(ThreadState *thr, uptr pc, uptr addr);
|
||||
void AcquireGlobal(ThreadState *thr, uptr pc);
|
||||
void Release(ThreadState *thr, uptr pc, uptr addr);
|
||||
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
|
||||
void AfterSleep(ThreadState *thr, uptr pc);
|
||||
|
@ -521,7 +515,7 @@ void AfterSleep(ThreadState *thr, uptr pc);
|
|||
// The trick is that the call preserves all registers and the compiler
|
||||
// does not treat it as a call.
|
||||
// If it does not work for you, use normal call.
|
||||
#if TSAN_DEBUG == 0
|
||||
#if 0 && TSAN_DEBUG == 0
|
||||
// The caller may not create the stack frame for itself at all,
|
||||
// so we create a reserve stack frame for it (1024b must be enough).
|
||||
#define HACKY_CALL(f) \
|
||||
|
@ -542,7 +536,11 @@ void ALWAYS_INLINE INLINE TraceAddEvent(ThreadState *thr, u64 epoch,
|
|||
EventType typ, uptr addr) {
|
||||
StatInc(thr, StatEvents);
|
||||
if (UNLIKELY((epoch % kTracePartSize) == 0)) {
|
||||
#ifndef TSAN_GO
|
||||
HACKY_CALL(__tsan_trace_switch);
|
||||
#else
|
||||
TraceSwitch(thr);
|
||||
#endif
|
||||
}
|
||||
Event *evp = &thr->trace.events[epoch % kTraceSize];
|
||||
Event ev = (u64)addr | ((u64)typ << 61);
|
||||
|
|
|
@ -82,7 +82,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
} else if (s->owner_tid == thr->tid) {
|
||||
CHECK_GT(s->recursion, 0);
|
||||
} else {
|
||||
TsanPrintf("ThreadSanitizer WARNING: double lock\n");
|
||||
Printf("ThreadSanitizer WARNING: double lock\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
if (s->recursion == 0) {
|
||||
|
@ -110,13 +110,13 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
if (s->recursion == 0) {
|
||||
if (!s->is_broken) {
|
||||
s->is_broken = true;
|
||||
TsanPrintf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
|
||||
Printf("ThreadSanitizer WARNING: unlock of unlocked mutex\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
} else if (s->owner_tid != thr->tid) {
|
||||
if (!s->is_broken) {
|
||||
s->is_broken = true;
|
||||
TsanPrintf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
|
||||
Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
} else {
|
||||
|
@ -145,7 +145,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeRLock, addr);
|
||||
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, false);
|
||||
if (s->owner_tid != SyncVar::kInvalidTid) {
|
||||
TsanPrintf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
|
||||
Printf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
thr->clock.set(thr->tid, thr->fast_state.epoch());
|
||||
|
@ -165,7 +165,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
TraceAddEvent(thr, thr->fast_state.epoch(), EventTypeRUnlock, addr);
|
||||
SyncVar *s = CTX()->synctab.GetAndLock(thr, pc, addr, true);
|
||||
if (s->owner_tid != SyncVar::kInvalidTid) {
|
||||
TsanPrintf("ThreadSanitizer WARNING: read unlock of a write "
|
||||
Printf("ThreadSanitizer WARNING: read unlock of a write "
|
||||
"locked mutex\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
}
|
||||
} else if (!s->is_broken) {
|
||||
s->is_broken = true;
|
||||
TsanPrintf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
|
||||
Printf("ThreadSanitizer WARNING: mutex unlock by another thread\n");
|
||||
PrintCurrentStack(thr, pc);
|
||||
}
|
||||
s->mtx.Unlock();
|
||||
|
@ -229,6 +229,20 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) {
|
|||
s->mtx.ReadUnlock();
|
||||
}
|
||||
|
||||
void AcquireGlobal(ThreadState *thr, uptr pc) {
|
||||
Context *ctx = CTX();
|
||||
Lock l(&ctx->thread_mtx);
|
||||
for (unsigned i = 0; i < kMaxTid; i++) {
|
||||
ThreadContext *tctx = ctx->threads[i];
|
||||
if (tctx == 0)
|
||||
continue;
|
||||
if (tctx->status == ThreadStatusRunning)
|
||||
thr->clock.set(i, tctx->thr->fast_state.epoch());
|
||||
else
|
||||
thr->clock.set(i, tctx->epoch1);
|
||||
}
|
||||
}
|
||||
|
||||
void Release(ThreadState *thr, uptr pc, uptr addr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: Release %zx\n", thr->tid, addr);
|
||||
|
|
|
@ -26,9 +26,9 @@ namespace __tsan {
|
|||
void TsanCheckFailed(const char *file, int line, const char *cond,
|
||||
u64 v1, u64 v2) {
|
||||
ScopedInRtl in_rtl;
|
||||
TsanPrintf("FATAL: ThreadSanitizer CHECK failed: "
|
||||
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||
file, line, cond, (uptr)v1, (uptr)v2);
|
||||
Printf("FATAL: ThreadSanitizer CHECK failed: "
|
||||
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||
file, line, cond, (uptr)v1, (uptr)v2);
|
||||
Die();
|
||||
}
|
||||
|
||||
|
@ -383,6 +383,8 @@ bool IsFiredSuppression(Context *ctx,
|
|||
}
|
||||
|
||||
void ReportRace(ThreadState *thr) {
|
||||
if (!flags()->report_bugs)
|
||||
return;
|
||||
ScopedInRtl in_rtl;
|
||||
|
||||
bool freed = false;
|
||||
|
|
|
@ -50,6 +50,23 @@ void ThreadFinalize(ThreadState *thr) {
|
|||
}
|
||||
}
|
||||
|
||||
int ThreadCount(ThreadState *thr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
Context *ctx = CTX();
|
||||
Lock l(&ctx->thread_mtx);
|
||||
int cnt = 0;
|
||||
for (unsigned i = 0; i < kMaxTid; i++) {
|
||||
ThreadContext *tctx = ctx->threads[i];
|
||||
if (tctx == 0)
|
||||
continue;
|
||||
if (tctx->status != ThreadStatusCreated
|
||||
&& tctx->status != ThreadStatusRunning)
|
||||
continue;
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static void ThreadDead(ThreadState *thr, ThreadContext *tctx) {
|
||||
Context *ctx = CTX();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
|
@ -80,7 +97,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
|
|||
if (ctx->dead_list_size > kThreadQuarantineSize
|
||||
|| ctx->thread_seq >= kMaxTid) {
|
||||
if (ctx->dead_list_size == 0) {
|
||||
TsanPrintf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
|
||||
Printf("ThreadSanitizer: %d thread limit exceeded. Dying.\n",
|
||||
kMaxTid);
|
||||
Die();
|
||||
}
|
||||
|
@ -273,7 +290,7 @@ void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
|
|||
Lock l(&ctx->thread_mtx);
|
||||
ThreadContext *tctx = ctx->threads[tid];
|
||||
if (tctx->status == ThreadStatusInvalid) {
|
||||
TsanPrintf("ThreadSanitizer: join of non-existent thread\n");
|
||||
Printf("ThreadSanitizer: join of non-existent thread\n");
|
||||
return;
|
||||
}
|
||||
CHECK_EQ(tctx->detached, false);
|
||||
|
@ -291,7 +308,7 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
|
|||
Lock l(&ctx->thread_mtx);
|
||||
ThreadContext *tctx = ctx->threads[tid];
|
||||
if (tctx->status == ThreadStatusInvalid) {
|
||||
TsanPrintf("ThreadSanitizer: detach of non-existent thread\n");
|
||||
Printf("ThreadSanitizer: detach of non-existent thread\n");
|
||||
return;
|
||||
}
|
||||
if (tctx->status == ThreadStatusFinished) {
|
||||
|
@ -301,10 +318,6 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
|
|||
}
|
||||
}
|
||||
|
||||
void ThreadFinalizerGoroutine(ThreadState *thr) {
|
||||
thr->clock.Disable(thr->tid);
|
||||
}
|
||||
|
||||
void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
||||
uptr size, bool is_write) {
|
||||
if (size == 0)
|
||||
|
@ -317,19 +330,19 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
|||
|
||||
#if TSAN_DEBUG
|
||||
if (!IsAppMem(addr)) {
|
||||
TsanPrintf("Access to non app mem %zx\n", addr);
|
||||
Printf("Access to non app mem %zx\n", addr);
|
||||
DCHECK(IsAppMem(addr));
|
||||
}
|
||||
if (!IsAppMem(addr + size - 1)) {
|
||||
TsanPrintf("Access to non app mem %zx\n", addr + size - 1);
|
||||
Printf("Access to non app mem %zx\n", addr + size - 1);
|
||||
DCHECK(IsAppMem(addr + size - 1));
|
||||
}
|
||||
if (!IsShadowMem((uptr)shadow_mem)) {
|
||||
TsanPrintf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||
Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
|
||||
DCHECK(IsShadowMem((uptr)shadow_mem));
|
||||
}
|
||||
if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
|
||||
TsanPrintf("Bad shadow addr %p (%zx)\n",
|
||||
Printf("Bad shadow addr %p (%zx)\n",
|
||||
shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
|
||||
DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
|
||||
}
|
||||
|
@ -353,7 +366,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
|||
Shadow cur(fast_state);
|
||||
cur.SetWrite(is_write);
|
||||
cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
|
||||
shadow_mem, cur);
|
||||
}
|
||||
if (unaligned)
|
||||
|
@ -364,7 +377,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
|||
Shadow cur(fast_state);
|
||||
cur.SetWrite(is_write);
|
||||
cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
|
||||
shadow_mem, cur);
|
||||
shadow_mem += kShadowCnt;
|
||||
}
|
||||
|
@ -374,7 +387,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
|
|||
Shadow cur(fast_state);
|
||||
cur.SetWrite(is_write);
|
||||
cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, fast_state,
|
||||
MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write,
|
||||
shadow_mem, cur);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,12 @@ void StatOutput(u64 *stat) {
|
|||
name[StatInt_opendir] = " opendir ";
|
||||
name[StatInt_epoll_ctl] = " epoll_ctl ";
|
||||
name[StatInt_epoll_wait] = " epoll_wait ";
|
||||
name[StatInt_poll] = " poll ";
|
||||
name[StatInt_sigaction] = " sigaction ";
|
||||
name[StatInt_sleep] = " sleep ";
|
||||
name[StatInt_usleep] = " usleep ";
|
||||
name[StatInt_nanosleep] = " nanosleep ";
|
||||
name[StatInt_gettimeofday] = " gettimeofday ";
|
||||
|
||||
name[StatAnnotation] = "Dynamic annotations ";
|
||||
name[StatAnnotateHappensBefore] = " HappensBefore ";
|
||||
|
@ -239,9 +244,9 @@ void StatOutput(u64 *stat) {
|
|||
name[StatMtxAtExit] = " Atexit ";
|
||||
name[StatMtxAnnotations] = " Annotations ";
|
||||
|
||||
TsanPrintf("Statistics:\n");
|
||||
Printf("Statistics:\n");
|
||||
for (int i = 0; i < StatCnt; i++)
|
||||
TsanPrintf("%s: %zu\n", name[i], (uptr)stat[i]);
|
||||
Printf("%s: %zu\n", name[i], (uptr)stat[i]);
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
|
|
@ -193,6 +193,7 @@ enum StatType {
|
|||
StatInt_opendir,
|
||||
StatInt_epoll_ctl,
|
||||
StatInt_epoll_wait,
|
||||
StatInt_poll,
|
||||
StatInt_sigaction,
|
||||
StatInt_signal,
|
||||
StatInt_raise,
|
||||
|
@ -201,6 +202,7 @@ enum StatType {
|
|||
StatInt_sleep,
|
||||
StatInt_usleep,
|
||||
StatInt_nanosleep,
|
||||
StatInt_gettimeofday,
|
||||
|
||||
// Dynamic annotations.
|
||||
StatAnnotation,
|
||||
|
|
|
@ -31,19 +31,19 @@ static char *ReadFile(const char *filename) {
|
|||
internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
|
||||
fd_t fd = internal_open(tmp.data(), false);
|
||||
if (fd == kInvalidFd) {
|
||||
TsanPrintf("ThreadSanitizer: failed to open suppressions file '%s'\n",
|
||||
Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
|
||||
tmp.data());
|
||||
Die();
|
||||
}
|
||||
const uptr fsize = internal_filesize(fd);
|
||||
if (fsize == (uptr)-1) {
|
||||
TsanPrintf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
|
||||
Printf("ThreadSanitizer: failed to stat suppressions file '%s'\n",
|
||||
tmp.data());
|
||||
Die();
|
||||
}
|
||||
char *buf = (char*)internal_alloc(MBlockSuppression, fsize + 1);
|
||||
if (fsize != internal_read(fd, buf, fsize)) {
|
||||
TsanPrintf("ThreadSanitizer: failed to read suppressions file '%s'\n",
|
||||
Printf("ThreadSanitizer: failed to read suppressions file '%s'\n",
|
||||
tmp.data());
|
||||
Die();
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ Suppression *SuppressionParse(const char* supp) {
|
|||
stype = SuppressionSignal;
|
||||
line += sizeof("signal:") - 1;
|
||||
} else {
|
||||
TsanPrintf("ThreadSanitizer: failed to parse suppressions file\n");
|
||||
Printf("ThreadSanitizer: failed to parse suppressions file\n");
|
||||
Die();
|
||||
}
|
||||
Suppression *s = (Suppression*)internal_alloc(MBlockSuppression,
|
||||
|
|
|
@ -48,17 +48,17 @@ struct DlIteratePhdrCtx {
|
|||
static void NOINLINE InitModule(ModuleDesc *m) {
|
||||
int outfd[2] = {};
|
||||
if (pipe(&outfd[0])) {
|
||||
TsanPrintf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno);
|
||||
Printf("ThreadSanitizer: outfd pipe() failed (%d)\n", errno);
|
||||
Die();
|
||||
}
|
||||
int infd[2] = {};
|
||||
if (pipe(&infd[0])) {
|
||||
TsanPrintf("ThreadSanitizer: infd pipe() failed (%d)\n", errno);
|
||||
Printf("ThreadSanitizer: infd pipe() failed (%d)\n", errno);
|
||||
Die();
|
||||
}
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
flags()->log_fileno = STDERR_FILENO;
|
||||
__sanitizer_set_report_fd(STDERR_FILENO);
|
||||
internal_close(STDOUT_FILENO);
|
||||
internal_close(STDIN_FILENO);
|
||||
internal_dup2(outfd[0], STDIN_FILENO);
|
||||
|
@ -72,7 +72,7 @@ static void NOINLINE InitModule(ModuleDesc *m) {
|
|||
execl("/usr/bin/addr2line", "/usr/bin/addr2line", "-Cfe", m->fullname, 0);
|
||||
_exit(0);
|
||||
} else if (pid < 0) {
|
||||
TsanPrintf("ThreadSanitizer: failed to fork symbolizer\n");
|
||||
Printf("ThreadSanitizer: failed to fork symbolizer\n");
|
||||
Die();
|
||||
}
|
||||
internal_close(outfd[0]);
|
||||
|
@ -153,14 +153,14 @@ ReportStack *SymbolizeCodeAddr2Line(uptr addr) {
|
|||
char addrstr[32];
|
||||
internal_snprintf(addrstr, sizeof(addrstr), "%p\n", (void*)offset);
|
||||
if (0 >= internal_write(m->out_fd, addrstr, internal_strlen(addrstr))) {
|
||||
TsanPrintf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
|
||||
Printf("ThreadSanitizer: can't write from symbolizer (%d, %d)\n",
|
||||
m->out_fd, errno);
|
||||
Die();
|
||||
}
|
||||
InternalScopedBuffer<char> func(1024);
|
||||
ssize_t len = internal_read(m->inp_fd, func.data(), func.size() - 1);
|
||||
if (len <= 0) {
|
||||
TsanPrintf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
|
||||
Printf("ThreadSanitizer: can't read from symbolizer (%d, %d)\n",
|
||||
m->inp_fd, errno);
|
||||
Die();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ do {
|
|||
if (Shadow::TidsAreEqual(old, cur)) {
|
||||
StatInc(thr, StatShadowSameThread);
|
||||
if (OldIsInSameSynchEpoch(old, thr)) {
|
||||
if (OldIsRWStronger(old, kAccessIsWrite)) {
|
||||
if (OldIsRWNotWeaker(old, kAccessIsWrite)) {
|
||||
// found a slot that holds effectively the same info
|
||||
// (that is, same tid, same sync epoch and same size)
|
||||
StatInc(thr, StatMopSame);
|
||||
|
@ -41,7 +41,7 @@ do {
|
|||
StoreIfNotYetStored(sp, &store_word);
|
||||
break;
|
||||
}
|
||||
if (OldIsRWWeaker(old, kAccessIsWrite))
|
||||
if (OldIsRWWeakerOrEqual(old, kAccessIsWrite))
|
||||
StoreIfNotYetStored(sp, &store_word);
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue