diff options
72 files changed, 932 insertions, 549 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8021aef4e87..74a120d1c0d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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. diff --git a/gcc/testsuite/c-c++-common/asan/memcmp-1.c b/gcc/testsuite/c-c++-common/asan/memcmp-1.c index 8f45a3f2fcb..a23ff236c0d 100644 --- a/gcc/testsuite/c-c++-common/asan/memcmp-1.c +++ b/gcc/testsuite/c-c++-common/asan/memcmp-1.c @@ -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)" } */ diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog index 7e206f9b96c..0c7e4b753f4 100644 --- a/libsanitizer/ChangeLog +++ b/libsanitizer/ChangeLog @@ -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> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE new file mode 100644 index 00000000000..05b4cf0d9b5 --- /dev/null +++ b/libsanitizer/MERGE @@ -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. diff --git a/libsanitizer/asan/asan_allocator.cc b/libsanitizer/asan/asan_allocator.cc index 3a92802e972..63ff607f858 100644 --- a/libsanitizer/asan/asan_allocator.cc +++ b/libsanitizer/asan/asan_allocator.cc @@ -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 diff --git a/libsanitizer/asan/asan_intercepted_functions.h b/libsanitizer/asan/asan_intercepted_functions.h index ceb596cd48e..62d1994130f 100644 --- a/libsanitizer/asan/asan_intercepted_functions.h +++ b/libsanitizer/asan/asan_intercepted_functions.h @@ -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 diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc index 8e15d341b8c..5b544c87fcb 100644 --- a/libsanitizer/asan/asan_interceptors.cc +++ b/libsanitizer/asan/asan_interceptors.cc @@ -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 diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h index 21368eef7c9..3a70ca44fd5 100644 --- a/libsanitizer/asan/asan_internal.h +++ b/libsanitizer/asan/asan_internal.h @@ -114,6 +114,7 @@ bool AsanInterceptsSignal(int signum); void SetAlternateSignalStack(); void UnsetAlternateSignalStack(); void InstallSignalHandlers(); +void ClearShadowMemoryForContext(void *context); void AsanPlatformThreadInit(); // Wrapper for TLS/TSD. diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc index ea7ee9e7bc8..7295216b85d 100644 --- a/libsanitizer/asan/asan_linux.cc +++ b/libsanitizer/asan/asan_linux.cc @@ -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__ diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc index 81e25e8ef59..ae5edd97165 100644 --- a/libsanitizer/asan/asan_mac.cc +++ b/libsanitizer/asan/asan_mac.cc @@ -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 diff --git a/libsanitizer/asan/asan_mac.h b/libsanitizer/asan/asan_mac.h index 18aca0dd84e..2c162fb0c39 100644 --- a/libsanitizer/asan/asan_mac.h +++ b/libsanitizer/asan/asan_mac.h @@ -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 diff --git a/libsanitizer/asan/asan_malloc_mac.cc b/libsanitizer/asan/asan_malloc_mac.cc index 2df34845f12..3f281c9cc3b 100644 --- a/libsanitizer/asan/asan_malloc_mac.cc +++ b/libsanitizer/asan/asan_malloc_mac.cc @@ -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 diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index 40a38db0544..c93280fdd6c 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -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 diff --git a/libsanitizer/asan/asan_new_delete.cc b/libsanitizer/asan/asan_new_delete.cc index a2180ae9444..8132e58b6e2 100644 --- a/libsanitizer/asan/asan_new_delete.cc +++ b/libsanitizer/asan/asan_new_delete.cc @@ -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 diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc index 7e6381c2beb..c35b4ec14f7 100644 --- a/libsanitizer/asan/asan_report.cc +++ b/libsanitizer/asan/asan_report.cc @@ -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); diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index 442d41c4f23..7731c17a351 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -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; diff --git a/libsanitizer/asan/asan_stats.cc b/libsanitizer/asan/asan_stats.cc index fa4adcb7f9a..ecdf5ffad09 100644 --- a/libsanitizer/asan/asan_stats.cc +++ b/libsanitizer/asan/asan_stats.cc @@ -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(); diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc index 9295c1570ec..4ec98e5ed22 100644 --- a/libsanitizer/asan/asan_thread.cc +++ b/libsanitizer/asan/asan_thread.cc @@ -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]; } diff --git a/libsanitizer/asan/asan_thread_registry.cc b/libsanitizer/asan/asan_thread_registry.cc index 840837e0004..9858cce22b0 100644 --- a/libsanitizer/asan/asan_thread_registry.cc +++ b/libsanitizer/asan/asan_thread_registry.cc @@ -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 diff --git a/libsanitizer/asan/asan_thread_registry.h b/libsanitizer/asan/asan_thread_registry.h index 99d5cb56af0..bb6b2678faa 100644 --- a/libsanitizer/asan/asan_thread_registry.h +++ b/libsanitizer/asan/asan_thread_registry.h @@ -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(); diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc index a5c0441dafa..8b7f9ef0e38 100644 --- a/libsanitizer/asan/asan_win.cc +++ b/libsanitizer/asan/asan_win.cc @@ -137,6 +137,10 @@ void AsanPlatformThreadInit() { // Nothing here for now. } +void ClearShadowMemoryForContext(void *context) { + UNIMPLEMENTED(); +} + } // namespace __asan // ---------------------- Interface ---------------- {{{1 diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h index d78d2802a2b..f6e814df6f5 100644 --- a/libsanitizer/include/sanitizer/common_interface_defs.h +++ b/libsanitizer/include/sanitizer/common_interface_defs.h @@ -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 diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh index 6918ee2475f..297af56e790 100755 --- a/libsanitizer/merge.sh +++ b/libsanitizer/merge.sh @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator64.h b/libsanitizer/sanitizer_common/sanitizer_allocator64.h index 247719876aa..7614aba52ac 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator64.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator64.h @@ -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) { diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc index 43ef980e846..fda67a542d5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.cc +++ b/libsanitizer/sanitizer_common/sanitizer_common.cc @@ -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" diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index cddefd7ea09..e565b93af29 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -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) diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index da4d049e2c6..a6795c6720b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.cc b/libsanitizer/sanitizer_common/sanitizer_libc.cc index 21869bc4846..4d43cd7d013 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libc.cc +++ b/libsanitizer/sanitizer_common/sanitizer_libc.cc @@ -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. diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h index 13528511190..4aa4a279d40 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libc.h +++ b/libsanitizer/sanitizer_common/sanitizer_libc.h @@ -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); diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc index f2a0d39ca99..2145aa04113 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc @@ -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); } diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc index 400cd21842b..aa313baff92 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cc +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc @@ -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()); } diff --git a/libsanitizer/sanitizer_common/sanitizer_placement_new.h b/libsanitizer/sanitizer_common/sanitizer_placement_new.h index d149683b43d..e32d65702df 100644 --- a/libsanitizer/sanitizer_common/sanitizer_placement_new.h +++ b/libsanitizer/sanitizer_common/sanitizer_placement_new.h @@ -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; diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index 8f71cfc049d..bd9270ecaa4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -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_ diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc index da4dc7f53a1..5876fef04f3 100644 --- a/libsanitizer/sanitizer_common/sanitizer_printf.cc +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc @@ -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()); diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h index 5e5e5ce89be..5541cfc0c63 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h @@ -23,7 +23,6 @@ class MemoryMappingLayout { bool GetObjectNameAndOffset(uptr addr, uptr *offset, char filename[], uptr filename_size) { UNIMPLEMENTED(); - return false; } }; diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc index 915c4b8050a..037a7c3f9c0 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h index a7934c65e1e..b36a1a082c5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h @@ -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, diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc index 66ac3c8a246..efd1e816832 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc @@ -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_; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h index 83adf025282..13ec83f2cbf 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h @@ -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_; }; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc index 50e39a75c3a..bb1c40f9613 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_linux.cc @@ -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; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc index c5ca616d89d..a1b931b737e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cc @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc index 7e6ba53e128..3b81e794e59 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc @@ -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 diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index 314852304d8..03a5c204c66 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -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; } diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am index a307502c97a..c4fbad9b74d 100644 --- a/libsanitizer/tsan/Makefile.am +++ b/libsanitizer/tsan/Makefile.am @@ -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 diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in index a893bccd5ef..b919969cf47 100644 --- a/libsanitizer/tsan/Makefile.in +++ b/libsanitizer/tsan/Makefile.in @@ -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@ diff --git a/libsanitizer/tsan/tsan_clock.cc b/libsanitizer/tsan/tsan_clock.cc index 937f861477f..5d45a5d15fb 100644 --- a/libsanitizer/tsan/tsan_clock.cc +++ b/libsanitizer/tsan/tsan_clock.cc @@ -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) { } diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h index d5c17305b31..8e4bf99ca89 100644 --- a/libsanitizer/tsan/tsan_clock.h +++ b/libsanitizer/tsan/tsan_clock.h @@ -59,8 +59,6 @@ struct ThreadClock { nclk_ = tid + 1; } - void Disable(unsigned tid); - uptr size() const { return nclk_; } diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h index 6a6f6b97832..6f3fd21e246 100644 --- a/libsanitizer/tsan/tsan_defs.h +++ b/libsanitizer/tsan/tsan_defs.h @@ -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; diff --git a/libsanitizer/tsan/tsan_flags.cc b/libsanitizer/tsan/tsan_flags.cc index e8563f5f877..a69c6a6b545 100644 --- a/libsanitizer/tsan/tsan_flags.cc +++ b/libsanitizer/tsan/tsan_flags.cc @@ -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 diff --git a/libsanitizer/tsan/tsan_flags.h b/libsanitizer/tsan/tsan_flags.h index a6310e3ce6c..451d3684729 100644 --- a/libsanitizer/tsan/tsan_flags.h +++ b/libsanitizer/tsan/tsan_flags.h @@ -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? diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc index 194e236ece7..191dea7387a 100644 --- a/libsanitizer/tsan/tsan_interceptors.cc +++ b/libsanitizer/tsan/tsan_interceptors.cc @@ -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(); } } diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h index 72bb1e91c3d..dede9be5f06 100644 --- a/libsanitizer/tsan/tsan_interface.h +++ b/libsanitizer/tsan/tsan_interface.h @@ -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" diff --git a/libsanitizer/tsan/tsan_interface_ann.cc b/libsanitizer/tsan/tsan_interface_ann.cc index fd5c1cc6cd4..b9e084b7327 100644 --- a/libsanitizer/tsan/tsan_interface_ann.cc +++ b/libsanitizer/tsan/tsan_interface_ann.cc @@ -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"; diff --git a/libsanitizer/tsan/tsan_interface_atomic.cc b/libsanitizer/tsan/tsan_interface_atomic.cc index 7b459f15d46..037a080da67 100644 --- a/libsanitizer/tsan/tsan_interface_atomic.cc +++ b/libsanitizer/tsan/tsan_interface_atomic.cc @@ -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); diff --git a/libsanitizer/tsan/tsan_interface_atomic.h b/libsanitizer/tsan/tsan_interface_atomic.h index 37532ce4185..fea97b69deb 100644 --- a/libsanitizer/tsan/tsan_interface_atomic.h +++ b/libsanitizer/tsan/tsan_interface_atomic.h @@ -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; - -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_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo); + +__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" diff --git a/libsanitizer/tsan/tsan_mutex.cc b/libsanitizer/tsan/tsan_mutex.cc index 83af02992b4..6a1e0cec53a 100644 --- a/libsanitizer/tsan/tsan_mutex.cc +++ b/libsanitizer/tsan/tsan_mutex.cc @@ -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; } diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h index d7a4cf7b0e9..f849182503c 100644 --- a/libsanitizer/tsan/tsan_platform.h +++ b/libsanitizer/tsan/tsan_platform.h @@ -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 diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc index d7de503c51d..b26065543fe 100644 --- a/libsanitizer/tsan/tsan_platform_linux.cc +++ b/libsanitizer/tsan/tsan_platform_linux.cc @@ -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() { diff --git a/libsanitizer/tsan/tsan_platform_mac.cc b/libsanitizer/tsan/tsan_platform_mac.cc index e22a500cf15..808d99c0207 100644 --- a/libsanitizer/tsan/tsan_platform_mac.cc +++ b/libsanitizer/tsan/tsan_platform_mac.cc @@ -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() { diff --git a/libsanitizer/tsan/tsan_platform_windows.cc b/libsanitizer/tsan/tsan_platform_windows.cc new file mode 100644 index 00000000000..74b9020d077 --- /dev/null +++ b/libsanitizer/tsan/tsan_platform_windows.cc @@ -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 diff --git a/libsanitizer/tsan/tsan_printf.cc b/libsanitizer/tsan/tsan_printf.cc deleted file mode 100644 index 982e2925dc3..00000000000 --- a/libsanitizer/tsan/tsan_printf.cc +++ /dev/null @@ -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 diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc index 716a20f1213..62e0b0c3314 100644 --- a/libsanitizer/tsan/tsan_report.cc +++ b/libsanitizer/tsan/tsan_report.cc @@ -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) { + if (ent == 0) { + Printf(" [failed to restore the stack]\n\n"); + return; + } for (int i = 0; ent; ent = ent->next, i++) { - TsanPrintf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line); + Printf(" #%d %s %s:%d", i, ent->func, ent->file, ent->line); if (ent->col) - TsanPrintf(":%d", ent->col); + Printf(":%d", ent->col); if (ent->module && ent->offset) - TsanPrintf(" (%s+%p)\n", ent->module, (void*)ent->offset); + Printf(" (%s+%p)\n", ent->module, (void*)ent->offset); else - TsanPrintf(" (%p)\n", (void*)ent->pc); + Printf(" (%p)\n", (void*)ent->pc); } - TsanPrintf("\n"); + 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 diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc index 4ff26973ce3..a3e82710d90 100644 --- a/libsanitizer/tsan/tsan_rtl.cc +++ b/libsanitizer/tsan/tsan_rtl.cc @@ -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); diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h index 3df229c8844..de357a5d5a0 100644 --- a/libsanitizer/tsan/tsan_rtl.h +++ b/libsanitizer/tsan/tsan_rtl.h @@ -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); diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc index 098894f5caa..9ace430bc58 100644 --- a/libsanitizer/tsan/tsan_rtl_mutex.cc +++ b/libsanitizer/tsan/tsan_rtl_mutex.cc @@ -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); diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc index 1511913d742..24e29d25400 100644 --- a/libsanitizer/tsan/tsan_rtl_report.cc +++ b/libsanitizer/tsan/tsan_rtl_report.cc @@ -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; diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc index 0ae658c1743..bb7f35c24ed 100644 --- a/libsanitizer/tsan/tsan_rtl_thread.cc +++ b/libsanitizer/tsan/tsan_rtl_thread.cc @@ -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); } } diff --git a/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc index fcbc631e086..68acae81e66 100644 --- a/libsanitizer/tsan/tsan_stat.cc +++ b/libsanitizer/tsan/tsan_stat.cc @@ -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 diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h index b194343a08a..25bff8b7080 100644 --- a/libsanitizer/tsan/tsan_stat.h +++ b/libsanitizer/tsan/tsan_stat.h @@ -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, diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc index 9b087add3c2..3f825a804a1 100644 --- a/libsanitizer/tsan/tsan_suppressions.cc +++ b/libsanitizer/tsan/tsan_suppressions.cc @@ -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, diff --git a/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc b/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc index 9caf091fecf..23540c07ca9 100644 --- a/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc +++ b/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc @@ -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(); } diff --git a/libsanitizer/tsan/tsan_update_shadow_word_inl.h b/libsanitizer/tsan/tsan_update_shadow_word_inl.h index ae4a318f952..e22859c1dde 100644 --- a/libsanitizer/tsan/tsan_update_shadow_word_inl.h +++ b/libsanitizer/tsan/tsan_update_shadow_word_inl.h @@ -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; } |