aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/config/i386/i386.c4
-rw-r--r--gcc/sanitizer.def2
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c2
-rw-r--r--libsanitizer/ChangeLog7
-rw-r--r--libsanitizer/MERGE2
-rw-r--r--libsanitizer/asan/asan_allocator.cc9
-rw-r--r--libsanitizer/asan/asan_allocator.h62
-rw-r--r--libsanitizer/asan/asan_allocator2.cc51
-rw-r--r--libsanitizer/asan/asan_fake_stack.cc1
-rw-r--r--libsanitizer/asan/asan_flags.h8
-rw-r--r--libsanitizer/asan/asan_globals.cc29
-rw-r--r--libsanitizer/asan/asan_intercepted_functions.h26
-rw-r--r--libsanitizer/asan/asan_interceptors.cc54
-rw-r--r--libsanitizer/asan/asan_interceptors.h3
-rw-r--r--libsanitizer/asan/asan_interface_internal.h133
-rw-r--r--libsanitizer/asan/asan_internal.h1
-rw-r--r--libsanitizer/asan/asan_mac.cc81
-rw-r--r--libsanitizer/asan/asan_malloc_linux.cc1
-rw-r--r--libsanitizer/asan/asan_mapping.h27
-rw-r--r--libsanitizer/asan/asan_new_delete.cc4
-rw-r--r--libsanitizer/asan/asan_poisoning.cc1
-rw-r--r--libsanitizer/asan/asan_report.cc104
-rw-r--r--libsanitizer/asan/asan_report.h6
-rw-r--r--libsanitizer/asan/asan_rtl.cc34
-rw-r--r--libsanitizer/asan/asan_stack.cc2
-rw-r--r--libsanitizer/asan/asan_stats.cc1
-rw-r--r--libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc5
-rw-r--r--libsanitizer/include/sanitizer/asan_interface.h137
-rw-r--r--libsanitizer/include/sanitizer/common_interface_defs.h81
-rw-r--r--libsanitizer/interception/Makefile.am5
-rw-r--r--libsanitizer/interception/Makefile.in8
-rw-r--r--libsanitizer/interception/interception.h52
-rw-r--r--libsanitizer/interception/interception_mac.cc11
-rw-r--r--libsanitizer/interception/interception_mac.h24
-rw-r--r--libsanitizer/interception/interception_type_test.cc37
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.cc6
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.h283
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.cc20
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.h63
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc210
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc365
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_internal_defs.h80
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_lfstack.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.cc2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.h14
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.cc49
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.cc34
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix.cc24
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_quarantine.h4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stackdepot.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.cc5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.h4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.cc67
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win.cc37
-rw-r--r--libsanitizer/tsan/tsan_defs.h5
-rw-r--r--libsanitizer/tsan/tsan_fd.cc10
-rw-r--r--libsanitizer/tsan/tsan_flags.cc2
-rw-r--r--libsanitizer/tsan/tsan_flags.h4
-rw-r--r--libsanitizer/tsan/tsan_interceptors.cc190
-rw-r--r--libsanitizer/tsan/tsan_interface.cc8
-rw-r--r--libsanitizer/tsan/tsan_interface.h2
-rw-r--r--libsanitizer/tsan/tsan_interface_ann.h2
-rw-r--r--libsanitizer/tsan/tsan_interface_atomic.cc54
-rw-r--r--libsanitizer/tsan/tsan_interface_inl.h18
-rw-r--r--libsanitizer/tsan/tsan_interface_java.cc2
-rw-r--r--libsanitizer/tsan/tsan_md5.cc2
-rw-r--r--libsanitizer/tsan/tsan_mman.cc58
-rw-r--r--libsanitizer/tsan/tsan_mman.h4
-rw-r--r--libsanitizer/tsan/tsan_platform.h1
-rw-r--r--libsanitizer/tsan/tsan_platform_linux.cc15
-rw-r--r--libsanitizer/tsan/tsan_report.cc63
-rw-r--r--libsanitizer/tsan/tsan_report.h1
-rw-r--r--libsanitizer/tsan/tsan_rtl.cc39
-rw-r--r--libsanitizer/tsan/tsan_rtl.h106
-rw-r--r--libsanitizer/tsan/tsan_rtl_mutex.cc26
-rw-r--r--libsanitizer/tsan/tsan_rtl_report.cc71
-rw-r--r--libsanitizer/tsan/tsan_rtl_thread.cc27
-rw-r--r--libsanitizer/tsan/tsan_stat.cc24
-rw-r--r--libsanitizer/tsan/tsan_stat.h24
-rw-r--r--libsanitizer/tsan/tsan_suppressions.cc23
-rw-r--r--libsanitizer/tsan/tsan_suppressions.h2
-rw-r--r--libsanitizer/tsan/tsan_symbolize.cc64
-rw-r--r--libsanitizer/tsan/tsan_update_shadow_word_inl.h16
-rw-r--r--libsanitizer/tsan/tsan_vector.h2
89 files changed, 2142 insertions, 1027 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 11cad1a..8dff131 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-13 Kostya Serebryany <kcc@google.com>
+
+ * config/i386/i386.c: Use 0x7fff8000 as asan_shadow_offset on x86_64
+ linux.
+ * sanitizer.def: Rename __asan_init to __asan_init_v1.
+
2013-02-12 Dodji Seketeli <dodji@redhat.com>
Avoid instrumenting duplicated memory access in the same basic block
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index caf4894..b8ef1c3 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -5436,7 +5436,9 @@ ix86_legitimate_combined_insn (rtx insn)
static unsigned HOST_WIDE_INT
ix86_asan_shadow_offset (void)
{
- return (unsigned HOST_WIDE_INT) 1 << (TARGET_LP64 ? 44 : 29);
+ return TARGET_LP64 ? (TARGET_MACHO ? (HOST_WIDE_INT_1 << 44)
+ : HOST_WIDE_INT_C (0x7fff8000))
+ : (HOST_WIDE_INT_1 << 29);
}
/* Argument support functions. */
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index ebc0b72..99f87e5 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -27,7 +27,7 @@ along with GCC; see the file COPYING3. If not see
for other FEs by asan.c. */
/* Address Sanitizer */
-DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init",
+DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_INIT, "__asan_init_v1",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
/* Do not reorder the BUILT_IN_ASAN_REPORT* builtins, e.g. cfgcleanup.c
relies on this order. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ee182b0..b9d72a1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-13 Kostya Serebryany <kcc@google.com>
+
+ * c-c++-common/asan/strncpy-overflow-1.c: Update the test
+ to match the fresh asan run-time.
+ * c-c++-common/asan/rlimit-mmap-test-1.c: Ditto.
+
2013-02-12 Dodji Seketeli <dodji@redhat.com>
Avoid instrumenting duplicated memory access in the same basic block
diff --git a/gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c b/gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
index 212db3b..0b3d2ae 100644
--- a/gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
+++ b/gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
@@ -18,4 +18,4 @@ int main(int argc, char **argv) {
return 0;
}
-/* { dg-output "AddressSanitizer is unable to mmap" } */
+/* { dg-output "ERROR: Failed to mmap" } */
diff --git a/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c b/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
index c8c2883..10b3ad7 100644
--- a/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
+++ b/gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
@@ -12,7 +12,7 @@ int main(int argc, char **argv) {
return short_buffer[8];
}
-/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "WRITE of size \[0-9\]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index 891ba01..db1e6e1 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,10 @@
+2013-02-13 Kostya Serebryany <kcc@google.com>
+
+ PR sanitizer/56128
+ * All source files: Merge from upstream r175049.
+ * interception/Makefile.am: added include path.
+ * interception/Makefile.in: Regenerated.
+
2013-02-11 Jack Howarth <howarth@bromo.med.uc.edu>
* configure.tgt: Disable build on darwin9 and earlier.
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index c8e733f..02d2bfc 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-173241
+175049
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 f01d2db..4e97ff5 100644
--- a/libsanitizer/asan/asan_allocator.cc
+++ b/libsanitizer/asan/asan_allocator.cc
@@ -32,7 +32,7 @@
#include "asan_report.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -367,7 +367,7 @@ class MallocInfo {
left_chunk->chunk_state != CHUNK_AVAILABLE)
return left_chunk;
// Choose based on offset.
- uptr l_offset = 0, r_offset = 0;
+ sptr l_offset = 0, r_offset = 0;
CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
if (l_offset < r_offset)
@@ -387,7 +387,7 @@ class MallocInfo {
CHECK(m->chunk_state == CHUNK_ALLOCATED ||
m->chunk_state == CHUNK_AVAILABLE ||
m->chunk_state == CHUNK_QUARANTINE);
- uptr offset = 0;
+ sptr offset = 0;
AsanChunkView m_view(m);
if (m_view.AddrIsInside(addr, 1, &offset))
return m;
@@ -685,6 +685,8 @@ void __asan_free_hook(void *ptr) {
namespace __asan {
+void InitializeAllocator() { }
+
void PrintInternalAllocatorStats() {
}
@@ -710,6 +712,7 @@ void *asan_malloc(uptr size, StackTrace *stack) {
}
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+ if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
void *ptr = (void*)Allocate(0, nmemb * size, stack, FROM_MALLOC);
if (ptr)
REAL(memset)(ptr, 0, nmemb * size);
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index cc16ce8..df2f520 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -22,7 +22,7 @@
// will co-exist in the source base for a while. The actual allocator is chosen
// at build time by redefining this macro.
#ifndef ASAN_ALLOCATOR_VERSION
-# if ASAN_LINUX && !ASAN_ANDROID
+# if (ASAN_LINUX && !ASAN_ANDROID) || ASAN_MAC || ASAN_WINDOWS
# define ASAN_ALLOCATOR_VERSION 2
# else
# define ASAN_ALLOCATOR_VERSION 1
@@ -40,6 +40,8 @@ enum AllocType {
static const uptr kNumberOfSizeClasses = 255;
struct AsanChunk;
+void InitializeAllocator();
+
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
@@ -51,14 +53,14 @@ class AsanChunkView {
uptr FreeTid();
void GetAllocStack(StackTrace *stack);
void GetFreeStack(StackTrace *stack);
- bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) {
+ bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
return true;
}
return false;
}
- bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) {
+ bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
(void)access_size;
if (addr < Beg()) {
*offset = Beg() - addr;
@@ -66,12 +68,9 @@ class AsanChunkView {
}
return false;
}
- bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) {
- if (addr + access_size >= End()) {
- if (addr <= End())
- *offset = 0;
- else
- *offset = addr - End();
+ bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+ if (addr + access_size > End()) {
+ *offset = addr - End();
return true;
}
return false;
@@ -225,50 +224,5 @@ void asan_mz_force_unlock();
void PrintInternalAllocatorStats();
-// Log2 and RoundUpToPowerOfTwo should be inlined for performance.
-#if defined(_WIN32) && !defined(__clang__)
-extern "C" {
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
-#if defined(_WIN64)
-unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT
-unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT
-#endif
-}
-#endif
-
-static inline uptr Log2(uptr x) {
- CHECK(IsPowerOfTwo(x));
-#if !defined(_WIN32) || defined(__clang__)
- return __builtin_ctzl(x);
-#elif defined(_WIN64)
- unsigned long ret; // NOLINT
- _BitScanForward64(&ret, x);
- return ret;
-#else
- unsigned long ret; // NOLINT
- _BitScanForward(&ret, x);
- return ret;
-#endif
-}
-
-static inline uptr RoundUpToPowerOfTwo(uptr size) {
- CHECK(size);
- if (IsPowerOfTwo(size)) return size;
-
- unsigned long up; // NOLINT
-#if !defined(_WIN32) || defined(__clang__)
- up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
-#elif defined(_WIN64)
- _BitScanReverse64(&up, size);
-#else
- _BitScanReverse(&up, size);
-#endif
- CHECK(size < (1ULL << (up + 1)));
- CHECK(size > (1ULL << up));
- return 1UL << (up + 1);
-}
-
-
} // namespace __asan
#endif // ASAN_ALLOCATOR_H
diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc
index 4aa5141..1ff120e 100644
--- a/libsanitizer/asan/asan_allocator2.cc
+++ b/libsanitizer/asan/asan_allocator2.cc
@@ -20,7 +20,6 @@
#include "asan_report.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
@@ -55,7 +54,11 @@ struct AsanMapUnmapCallback {
};
#if SANITIZER_WORDSIZE == 64
+#if defined(__powerpc64__)
+const uptr kAllocatorSpace = 0xa0000000000ULL;
+#else
const uptr kAllocatorSpace = 0x600000000000ULL;
+#endif
const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
typedef DefaultSizeClassMap SizeClassMap;
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, 0 /*metadata*/,
@@ -89,8 +92,6 @@ static const uptr kMaxAllowedMallocSize =
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
-static const uptr kReturnOnZeroMalloc = 2048; // Zero page is protected.
-
// Every chunk of memory allocated by this allocator can be in one of 3 states:
// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
@@ -112,7 +113,7 @@ static u32 RZSize2Log(u32 rz_size) {
CHECK_GE(rz_size, 16);
CHECK_LE(rz_size, 2048);
CHECK(IsPowerOfTwo(rz_size));
- u32 res = __builtin_ctz(rz_size) - 4;
+ u32 res = Log2(rz_size) - 4;
CHECK_EQ(rz_size, RZLog2Size(res));
return res;
}
@@ -289,27 +290,26 @@ struct QuarantineCallback {
AllocatorCache *cache_;
};
-static void Init() {
- static int inited = 0;
- if (inited) return;
- __asan_init();
- inited = true; // this must happen before any threads are created.
+void InitializeAllocator() {
allocator.Init();
quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine);
}
static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
AllocType alloc_type) {
- Init();
+ if (!asan_inited)
+ __asan_init();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
if (alignment < min_alignment)
alignment = min_alignment;
if (size == 0) {
- if (alignment <= kReturnOnZeroMalloc)
- return reinterpret_cast<void *>(kReturnOnZeroMalloc);
- else
- return 0; // 0 bytes with large alignment requested. Just return 0.
+ // We'd be happy to avoid allocating memory for zero-size requests, but
+ // some programs/tests depend on this behavior and assume that malloc would
+ // not return NULL even for zero-size allocations. Moreover, it looks like
+ // operator new should never return NULL, and results of consecutive "new"
+ // calls must be different even if the allocated size is zero.
+ size = 1;
}
CHECK(IsPowerOfTwo(alignment));
uptr rz_log = ComputeRZLog(size);
@@ -415,7 +415,8 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
uptr p = reinterpret_cast<uptr>(ptr);
- if (p == 0 || p == kReturnOnZeroMalloc) return;
+ if (p == 0) return;
+ ASAN_FREE_HOOK(ptr);
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
@@ -465,8 +466,6 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) {
quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac),
m, m->UsedSize());
}
-
- ASAN_FREE_HOOK(ptr);
}
static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) {
@@ -546,7 +545,7 @@ AsanChunk *ChooseChunk(uptr addr,
return right_chunk;
}
// Same chunk_state: choose based on offset.
- uptr l_offset = 0, r_offset = 0;
+ sptr l_offset = 0, r_offset = 0;
CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
if (l_offset < r_offset)
@@ -557,7 +556,7 @@ AsanChunk *ChooseChunk(uptr addr,
AsanChunkView FindHeapChunkByAddress(uptr addr) {
AsanChunk *m1 = GetAsanChunkByAddr(addr);
if (!m1) return AsanChunkView(m1);
- uptr offset = 0;
+ sptr offset = 0;
if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) {
// The address is in the chunk's left redzone, so maybe it is actually
// a right buffer overflow from the other chunk to the left.
@@ -601,6 +600,7 @@ void *asan_malloc(uptr size, StackTrace *stack) {
}
void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
+ if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
if (ptr)
REAL(memset)(ptr, 0, nmemb * size);
@@ -649,16 +649,17 @@ uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
}
uptr asan_mz_size(const void *ptr) {
- UNIMPLEMENTED();
- return 0;
+ return AllocationSize(reinterpret_cast<uptr>(ptr));
}
void asan_mz_force_lock() {
- UNIMPLEMENTED();
+ allocator.ForceLock();
+ fallback_mutex.Lock();
}
void asan_mz_force_unlock() {
- UNIMPLEMENTED();
+ fallback_mutex.Unlock();
+ allocator.ForceUnlock();
}
} // namespace __asan
@@ -674,7 +675,7 @@ uptr __asan_get_estimated_allocated_size(uptr size) {
bool __asan_get_ownership(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
- return (ptr == kReturnOnZeroMalloc) || (AllocationSize(ptr) > 0);
+ return (AllocationSize(ptr) > 0);
}
uptr __asan_get_allocated_size(const void *p) {
@@ -682,7 +683,7 @@ uptr __asan_get_allocated_size(const void *p) {
uptr ptr = reinterpret_cast<uptr>(p);
uptr allocated_size = AllocationSize(ptr);
// Die if p is not malloced or if it is already freed.
- if (allocated_size == 0 && ptr != kReturnOnZeroMalloc) {
+ if (allocated_size == 0) {
GET_STACK_TRACE_FATAL_HERE;
ReportAsanGetAllocatedSizeNotOwned(ptr, &stack);
}
diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc
index e8d1e78..1fc0415 100644
--- a/libsanitizer/asan/asan_fake_stack.cc
+++ b/libsanitizer/asan/asan_fake_stack.cc
@@ -12,7 +12,6 @@
#include "asan_allocator.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
namespace __asan {
diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h
index 49a9073..b05fdc3 100644
--- a/libsanitizer/asan/asan_flags.h
+++ b/libsanitizer/asan/asan_flags.h
@@ -13,7 +13,7 @@
#ifndef ASAN_FLAGS_H
#define ASAN_FLAGS_H
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
// ASan flag values can be defined in three ways:
// 1) initialized with default values at startup.
@@ -50,8 +50,6 @@ struct Flags {
bool replace_str;
// If set, uses custom wrappers for memset/memcpy/memmove intinsics.
bool replace_intrin;
- // Used on Mac only. See comments in asan_mac.cc and asan_malloc_mac.cc.
- bool replace_cfallocator;
// Used on Mac only.
bool mac_ignore_invalid_free;
// ASan allocator flag. See asan_allocator.cc.
@@ -77,6 +75,10 @@ struct Flags {
bool unmap_shadow_on_exit;
// If set, calls abort() instead of _exit() after printing an error report.
bool abort_on_error;
+ // Print various statistics after printing an error message or if atexit=1.
+ bool print_stats;
+ // Print the legend for the shadow bytes.
+ bool print_legend;
// If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
// By default, disable core dumper on 64-bit - it makes little sense
diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc
index 88aeefa..7093c44 100644
--- a/libsanitizer/asan/asan_globals.cc
+++ b/libsanitizer/asan/asan_globals.cc
@@ -16,7 +16,6 @@
#include "asan_stack.h"
#include "asan_stats.h"
#include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_mutex.h"
namespace __asan {
@@ -34,26 +33,20 @@ static ListOfGlobals *list_of_all_globals;
static ListOfGlobals *list_of_dynamic_init_globals;
void PoisonRedZones(const Global &g) {
- uptr shadow_rz_size = kGlobalAndStackRedzone >> SHADOW_SCALE;
- CHECK(shadow_rz_size == 1 || shadow_rz_size == 2 || shadow_rz_size == 4);
- // full right redzone
- uptr g_aligned_size = kGlobalAndStackRedzone *
- ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
- PoisonShadow(g.beg + g_aligned_size,
- kGlobalAndStackRedzone, kAsanGlobalRedzoneMagic);
- if ((g.size % kGlobalAndStackRedzone) != 0) {
+ uptr aligned_size = RoundUpTo(g.size, SHADOW_GRANULARITY);
+ PoisonShadow(g.beg + aligned_size, g.size_with_redzone - aligned_size,
+ kAsanGlobalRedzoneMagic);
+ if (g.size != aligned_size) {
// partial right redzone
- u64 g_aligned_down_size = kGlobalAndStackRedzone *
- (g.size / kGlobalAndStackRedzone);
- CHECK(g_aligned_down_size == g_aligned_size - kGlobalAndStackRedzone);
- PoisonShadowPartialRightRedzone(g.beg + g_aligned_down_size,
- g.size % kGlobalAndStackRedzone,
- kGlobalAndStackRedzone,
- kAsanGlobalRedzoneMagic);
+ PoisonShadowPartialRightRedzone(
+ g.beg + RoundDownTo(g.size, SHADOW_GRANULARITY),
+ g.size % SHADOW_GRANULARITY,
+ SHADOW_GRANULARITY,
+ kAsanGlobalRedzoneMagic);
}
}
-bool DescribeAddressIfGlobal(uptr addr) {
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
if (!flags()->report_globals) return false;
BlockingMutexLock lock(&mu_for_globals);
bool res = false;
@@ -62,7 +55,7 @@ bool DescribeAddressIfGlobal(uptr addr) {
if (flags()->report_globals >= 2)
Report("Search Global: beg=%p size=%zu name=%s\n",
(void*)g.beg, g.size, (char*)g.name);
- res |= DescribeAddressRelativeToGlobal(addr, g);
+ res |= DescribeAddressRelativeToGlobal(addr, size, g);
}
return res;
}
diff --git a/libsanitizer/asan/asan_intercepted_functions.h b/libsanitizer/asan/asan_intercepted_functions.h
index 2d678ab..45c913c 100644
--- a/libsanitizer/asan/asan_intercepted_functions.h
+++ b/libsanitizer/asan/asan_intercepted_functions.h
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_platform_interceptors.h"
#include <stdarg.h>
+#include <stddef.h>
using __sanitizer::uptr;
@@ -64,9 +65,7 @@ using __sanitizer::uptr;
# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
#endif
-// On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
-// there.
-#if !defined(_WIN32) && (!defined(__APPLE__) || MAC_INTERPOSE_FUNCTIONS)
+#if !defined(_WIN32)
# define ASAN_INTERCEPT_SIGLONGJMP 1
#else
# define ASAN_INTERCEPT_SIGLONGJMP 0
@@ -169,7 +168,8 @@ DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pread64, int fd, void *buf,
DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, write, int fd, void *ptr, SIZE_T count);
# endif
# if SANITIZER_INTERCEPT_PWRITE
-DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count);
+DECLARE_FUNCTION_AND_WRAPPER(SSIZE_T, pwrite,
+ int fd, void *ptr, SIZE_T count, OFF_T offset);
# endif
# if ASAN_INTERCEPT_MLOCKX
@@ -193,6 +193,8 @@ DECLARE_FUNCTION_AND_WRAPPER(int, pthread_create,
void *(*start_routine)(void*), void *arg);
# endif
+// stdio.h
+# if SANITIZER_INTERCEPT_SCANF
DECLARE_FUNCTION_AND_WRAPPER(int, vscanf, const char *format, va_list ap);
DECLARE_FUNCTION_AND_WRAPPER(int, vsscanf, const char *str, const char *format,
va_list ap);
@@ -203,6 +205,18 @@ DECLARE_FUNCTION_AND_WRAPPER(int, fscanf,
void* stream, const char *format, ...);
DECLARE_FUNCTION_AND_WRAPPER(int, sscanf, // NOLINT
const char *str, const char *format, ...);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vscanf, const char *format,
+ va_list ap);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vsscanf, const char *str,
+ const char *format, va_list ap);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_vfscanf, void *stream,
+ const char *format, va_list ap);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_scanf, const char *format, ...);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_fscanf,
+ void* stream, const char *format, ...);
+DECLARE_FUNCTION_AND_WRAPPER(int, __isoc99_sscanf, // NOLINT
+ const char *str, const char *format, ...);
+# endif
# if defined(__APPLE__)
typedef void* pthread_workqueue_t;
@@ -231,7 +245,7 @@ DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async_f,
dispatch_group_t group, dispatch_queue_t dq,
void *ctxt, dispatch_function_t func);
-# if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
+# if !defined(MISSING_BLOCKS_SUPPORT)
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_group_async,
dispatch_group_t dg,
dispatch_queue_t dq, void (^work)(void));
@@ -243,7 +257,7 @@ DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_event_handler,
dispatch_source_t ds, void (^work)(void));
DECLARE_FUNCTION_AND_WRAPPER(void, dispatch_source_set_cancel_handler,
dispatch_source_t ds, void (^work)(void));
-# endif // MAC_INTERPOSE_FUNCTIONS
+# endif // MISSING_BLOCKS_SUPPORT
typedef void malloc_zone_t;
typedef size_t vm_size_t;
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index 98329f3..f4c5683 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -20,7 +20,6 @@
#include "asan_stats.h"
#include "asan_thread_registry.h"
#include "interception/interception.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
@@ -30,12 +29,14 @@ namespace __asan {
// that no extra frames are created, and stack trace contains
// relevant information only.
// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
- if (uptr __ptr = __asan_region_is_poisoned((uptr)(offset), size)) { \
- GET_CURRENT_PC_BP_SP; \
- __asan_report_error(pc, bp, sp, __ptr, isWrite, /* access_size */1); \
- } \
-} while (0)
+#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
+ uptr __offset = (uptr)(offset); \
+ uptr __size = (uptr)(size); \
+ if (__asan_region_is_poisoned(__offset, __size)) { \
+ GET_CURRENT_PC_BP_SP; \
+ __asan_report_error(pc, bp, sp, __offset, isWrite, __size); \
+ } \
+ } while (0)
#define ASAN_READ_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, false)
#define ASAN_WRITE_RANGE(offset, size) ACCESS_MEMORY_RANGE(offset, size, true);
@@ -275,13 +276,9 @@ INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
ASAN_READ_RANGE(from, size);
ASAN_WRITE_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) {
@@ -294,13 +291,9 @@ INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
ASAN_READ_RANGE(from, size);
ASAN_WRITE_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) {
@@ -398,7 +391,7 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
}
INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
if (!asan_inited) return REAL(strcpy)(to, from); // NOLINT
#endif
// strcpy is called from malloc_default_purgeable_zone()
@@ -418,7 +411,7 @@ INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
#if ASAN_INTERCEPT_STRDUP
INTERCEPTOR(char*, strdup, const char *s) {
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
// 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
@@ -559,7 +552,7 @@ INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
}
INTERCEPTOR(int, atoi, const char *nptr) {
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
if (!asan_inited) return REAL(atoi)(nptr);
#endif
ENSURE_ASAN_INITED();
@@ -578,7 +571,7 @@ INTERCEPTOR(int, atoi, const char *nptr) {
}
INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
if (!asan_inited) return REAL(atol)(nptr);
#endif
ENSURE_ASAN_INITED();
@@ -659,10 +652,9 @@ void InitializeAsanInterceptors() {
static bool was_called_once;
CHECK(was_called_once == false);
was_called_once = true;
-#if MAC_INTERPOSE_FUNCTIONS
+#if defined(__APPLE__)
return;
-#endif
-
+#else
SANITIZER_COMMON_INTERCEPTORS_INIT;
// Intercept mem* functions.
@@ -671,12 +663,6 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(memset);
if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
ASAN_INTERCEPT_FUNC(memcpy);
- } else {
-#if !MAC_INTERPOSE_FUNCTIONS
- // If we're using dynamic interceptors on Mac, these two are just plain
- // functions.
- internal_memcpy(&REAL(memcpy), &REAL(memmove), sizeof(REAL(memmove)));
-#endif
}
// Intercept str* functions.
@@ -698,12 +684,8 @@ void InitializeAsanInterceptors() {
#if ASAN_INTERCEPT_STRNLEN
ASAN_INTERCEPT_FUNC(strnlen);
#endif
-#if ASAN_INTERCEPT_INDEX
-# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
+#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
ASAN_INTERCEPT_FUNC(index);
-# else
- CHECK(OVERRIDE_FUNCTION(index, WRAP(strchr)));
-# endif
#endif
ASAN_INTERCEPT_FUNC(atoi);
@@ -753,14 +735,10 @@ void InitializeAsanInterceptors() {
InitializeWindowsInterceptors();
#endif
- // Some Mac-specific interceptors.
-#if defined(__APPLE__)
- InitializeMacInterceptors();
-#endif
-
if (flags()->verbosity > 0) {
Report("AddressSanitizer: libc interceptors initialized\n");
}
+#endif // __APPLE__
}
} // namespace __asan
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index a6ab030..cae4c7f 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -30,9 +30,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
namespace __asan {
void InitializeAsanInterceptors();
-#if defined(__APPLE__)
-void InitializeMacInterceptors();
-#endif // __APPLE__
} // namespace __asan
diff --git a/libsanitizer/asan/asan_interface_internal.h b/libsanitizer/asan/asan_interface_internal.h
new file mode 100644
index 0000000..2fd58b8
--- /dev/null
+++ b/libsanitizer/asan/asan_interface_internal.h
@@ -0,0 +1,133 @@
+//===-- asan_interface_internal.h -------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This header can be included by the instrumented program to fetch
+// data (mostly allocator statistics) from ASan runtime library.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_INTERNAL_H
+#define ASAN_INTERFACE_INTERNAL_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using __sanitizer::uptr;
+
+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.
+ // Everytime the asan ABI changes we also change the version number in this
+ // name. Objects build with incompatible asan ABI version
+ // will not link with run-time.
+ void __asan_init_v1() SANITIZER_INTERFACE_ATTRIBUTE;
+ #define __asan_init __asan_init_v1
+
+ // This structure describes an instrumented global variable.
+ struct __asan_global {
+ uptr beg; // The address of the global.
+ uptr size; // The original size of the global.
+ uptr size_with_redzone; // The size with the redzone.
+ const char *name; // Name as a C string.
+ uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
+ };
+
+ // These two functions should be called by the instrumented code.
+ // 'globals' is an array of structures describing 'n' globals.
+ void __asan_register_globals(__asan_global *globals, uptr n)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_unregister_globals(__asan_global *globals, uptr n)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ // These two functions should be called before and after dynamic initializers
+ // run, respectively. They should be called with parameters describing all
+ // dynamically initialized globals defined in the calling TU.
+ void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_after_dynamic_init()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ // These two functions are used by the instrumented code in the
+ // use-after-return mode. __asan_stack_malloc allocates size bytes of
+ // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
+ // the real stack region.
+ uptr __asan_stack_malloc(uptr size, uptr real_stack)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ // These two functions are used by instrumented code in the
+ // use-after-scope mode. They mark memory for local variables as
+ // unaddressable when they leave scope and addressable before the
+ // function exits.
+ void __asan_poison_stack_memory(uptr addr, uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_unpoison_stack_memory(uptr addr, uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ // Performs cleanup before a NoReturn function. Must be called before things
+ // like _exit and execl to avoid false positives on stack.
+ void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+
+ void __asan_poison_memory_region(void const volatile *addr, uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ bool __asan_address_is_poisoned(void const volatile *addr)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ uptr __asan_region_is_poisoned(uptr beg, uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ void __asan_describe_address(uptr addr)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ void __asan_report_error(uptr pc, uptr bp, uptr sp,
+ uptr addr, bool is_write, uptr access_size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ int __asan_set_error_exit_code(int exit_code)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_set_death_callback(void (*callback)(void))
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_set_error_report_callback(void (*callback)(const char*))
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ /* OPTIONAL */ void __asan_on_error()
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+ /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
+ int out_size)
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+ uptr __asan_get_estimated_allocated_size(uptr size)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ bool __asan_get_ownership(const void *p)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr __asan_get_allocated_size(const void *p)
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr __asan_get_current_allocated_bytes()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr __asan_get_heap_size()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr __asan_get_free_bytes()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ uptr __asan_get_unmapped_bytes()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_print_accumulated_stats()
+ SANITIZER_INTERFACE_ATTRIBUTE;
+
+ /* OPTIONAL */ const char* __asan_default_options()
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+ /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ /* OPTIONAL */ void __asan_free_hook(void *ptr)
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+} // extern "C"
+
+#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index a9c6c0f..0fe620e 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -13,6 +13,7 @@
#define ASAN_INTERNAL_H
#include "asan_flags.h"
+#include "asan_interface_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index a49d5c5..c5fc7de 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -89,10 +89,9 @@ static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
void MaybeReexec() {
if (!flags()->allow_reexec) return;
-#if MAC_INTERPOSE_FUNCTIONS
- // If the program is linked with the dynamic ASan runtime library, make sure
- // the library is preloaded so that the wrappers work. If it is not, set
- // DYLD_INSERT_LIBRARIES and re-exec ourselves.
+ // Make sure the dynamic ASan runtime library is preloaded so that the
+ // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec
+ // ourselves.
Dl_info info;
CHECK(dladdr((void*)((uptr)__asan_init), &info));
const char *dyld_insert_libraries = GetEnv(kDyldInsertLibraries);
@@ -114,8 +113,6 @@ void MaybeReexec() {
}
execv(program_name, *_NSGetArgv());
}
-#endif // MAC_INTERPOSE_FUNCTIONS
- // If we're not using the dynamic runtime, do nothing.
}
// No-op. Mac does not support static linkage anyway.
@@ -146,57 +143,6 @@ void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
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.
-// These constants were chosen empirically and may not work if the shadow
-// memory layout changes. Unfortunately they do necessarily depend on
-// kHighMemBeg or kHighMemEnd.
-static void *island_allocator_pos = 0;
-
-#if SANITIZER_WORDSIZE == 32
-# define kIslandEnd (0xffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#else
-# define kIslandEnd (0x7fffffdf0000 - GetPageSizeCached())
-# define kIslandBeg (kIslandEnd - 256 * GetPageSizeCached())
-#endif
-
-extern "C"
-mach_error_t __interception_allocate_island(void **ptr,
- uptr unused_size,
- void *unused_hint) {
- if (!island_allocator_pos) {
- island_allocator_pos =
- internal_mmap((void*)kIslandBeg, kIslandEnd - kIslandBeg,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON | MAP_FIXED,
- -1, 0);
- if (island_allocator_pos != (void*)kIslandBeg) {
- return KERN_NO_SPACE;
- }
- if (flags()->verbosity) {
- Report("Mapped pages %p--%p for branch islands.\n",
- (void*)kIslandBeg, (void*)kIslandEnd);
- }
- // Should not be very performance-critical.
- internal_memset(island_allocator_pos, 0xCC, kIslandEnd - kIslandBeg);
- };
- *ptr = island_allocator_pos;
- island_allocator_pos = (char*)island_allocator_pos + GetPageSizeCached();
- if (flags()->verbosity) {
- Report("Branch island allocated at %p\n", *ptr);
- }
- return err_none;
-}
-
-extern "C"
-mach_error_t __interception_deallocate_island(void *ptr) {
- // Do nothing.
- // TODO(glider): allow to free and reuse the island memory.
- return err_none;
-}
-
// Support for the following functions from libdispatch on Mac OS:
// dispatch_async_f()
// dispatch_async()
@@ -350,14 +296,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
asan_dispatch_call_block_and_release);
}
-#if MAC_INTERPOSE_FUNCTIONS && !defined(MISSING_BLOCKS_SUPPORT)
-// dispatch_async, dispatch_group_async and others tailcall the corresponding
-// dispatch_*_f functions. When wrapping functions with mach_override, those
-// dispatch_*_f are intercepted automatically. But with dylib interposition
-// this does not work, because the calls within the same library are not
-// interposed.
-// Therefore we need to re-implement dispatch_async and friends.
-
+#if !defined(MISSING_BLOCKS_SUPPORT)
extern "C" {
// FIXME: consolidate these declarations with asan_intercepted_functions.h.
void dispatch_async(dispatch_queue_t dq, void(^work)(void));
@@ -410,16 +349,4 @@ INTERCEPTOR(void, dispatch_source_set_event_handler,
}
#endif
-namespace __asan {
-
-void InitializeMacInterceptors() {
- CHECK(INTERCEPT_FUNCTION(dispatch_async_f));
- CHECK(INTERCEPT_FUNCTION(dispatch_sync_f));
- CHECK(INTERCEPT_FUNCTION(dispatch_after_f));
- CHECK(INTERCEPT_FUNCTION(dispatch_barrier_async_f));
- CHECK(INTERCEPT_FUNCTION(dispatch_group_async_f));
-}
-
-} // namespace __asan
-
#endif // __APPLE__
diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc
index e33d0c0..18e6a3b 100644
--- a/libsanitizer/asan/asan_malloc_linux.cc
+++ b/libsanitizer/asan/asan_malloc_linux.cc
@@ -18,7 +18,6 @@
#include "asan_internal.h"
#include "asan_stack.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
#if ASAN_ANDROID
DECLARE_REAL_AND_INTERCEPTOR(void*, malloc, uptr size)
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index be645c4..3e7fc6b 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -1,5 +1,7 @@
//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
//
+// The LLVM Compiler Infrastructure
+//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
@@ -34,27 +36,20 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
# if defined(__powerpc64__)
# define SHADOW_OFFSET (1ULL << 41)
# else
-# define SHADOW_OFFSET (1ULL << 44)
+# if ASAN_MAC
+# define SHADOW_OFFSET (1ULL << 44)
+# else
+# define SHADOW_OFFSET 0x7fff8000ULL
+# endif
# endif
# endif
# endif
#endif // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
-#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
-#if SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__)
- static const uptr kHighMemEnd = 0x00000fffffffffffUL;
-# else
- static const uptr kHighMemEnd = 0x00007fffffffffffUL;
-# endif
-#else // SANITIZER_WORDSIZE == 32
- static const uptr kHighMemEnd = 0xffffffff;
-#endif // SANITIZER_WORDSIZE
-
-
#define kLowMemBeg 0
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
@@ -74,11 +69,11 @@ extern SANITIZER_INTERFACE_ATTRIBUTE uptr __asan_mapping_offset;
: kZeroBaseShadowStart)
#define kShadowGapEnd (kHighShadowBeg - 1)
-#define kGlobalAndStackRedzone \
- (SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
-
namespace __asan {
+SANITIZER_INTERFACE_ATTRIBUTE
+extern uptr kHighMemEnd; // Initialized in __asan_init.
+
static inline bool AddrIsInLowMem(uptr a) {
return a < kLowMemEnd;
}
diff --git a/libsanitizer/asan/asan_new_delete.cc b/libsanitizer/asan/asan_new_delete.cc
index e41135d..fd47eee 100644
--- a/libsanitizer/asan/asan_new_delete.cc
+++ b/libsanitizer/asan/asan_new_delete.cc
@@ -25,9 +25,9 @@ void ReplaceOperatorsNewAndDelete() { }
using namespace __asan; // NOLINT
-// On Mac and Android new() goes through malloc interceptors.
+// On Android new() goes through malloc interceptors.
// See also https://code.google.com/p/address-sanitizer/issues/detail?id=131.
-#if !ASAN_ANDROID && !ASAN_MAC
+#if !ASAN_ANDROID
// Fake std::nothrow_t to avoid including <new>.
namespace std {
diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc
index 11edca5..7e93003 100644
--- a/libsanitizer/asan/asan_poisoning.cc
+++ b/libsanitizer/asan/asan_poisoning.cc
@@ -13,7 +13,6 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
#include "asan_mapping.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_libc.h"
namespace __asan {
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index ed18ab2..663e8f3 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -118,19 +118,7 @@ static void PrintShadowBytes(const char *before, u8 *bytes,
Printf("\n");
}
-static void PrintShadowMemoryForAddress(uptr addr) {
- if (!AddrIsInMem(addr))
- return;
- uptr shadow_addr = MemToShadow(addr);
- const uptr n_bytes_per_row = 16;
- uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
- Printf("Shadow bytes around the buggy address:\n");
- for (int i = -5; i <= 5; i++) {
- const char *prefix = (i == 0) ? "=>" : " ";
- PrintShadowBytes(prefix,
- (u8*)(aligned_shadow + i * n_bytes_per_row),
- (u8*)shadow_addr, n_bytes_per_row);
- }
+static void PrintLegend() {
Printf("Shadow byte legend (one shadow byte represents %d "
"application bytes):\n", (int)SHADOW_GRANULARITY);
PrintShadowByte(" Addressable: ", 0);
@@ -153,6 +141,23 @@ static void PrintShadowMemoryForAddress(uptr addr) {
PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
}
+static void PrintShadowMemoryForAddress(uptr addr) {
+ if (!AddrIsInMem(addr))
+ return;
+ uptr shadow_addr = MemToShadow(addr);
+ const uptr n_bytes_per_row = 16;
+ uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
+ Printf("Shadow bytes around the buggy address:\n");
+ for (int i = -5; i <= 5; i++) {
+ const char *prefix = (i == 0) ? "=>" : " ";
+ PrintShadowBytes(prefix,
+ (u8*)(aligned_shadow + i * n_bytes_per_row),
+ (u8*)shadow_addr, n_bytes_per_row);
+ }
+ if (flags()->print_legend)
+ PrintLegend();
+}
+
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
const char *zone_name) {
if (zone_ptr) {
@@ -183,18 +188,23 @@ static void PrintGlobalNameIfASCII(const __asan_global &g) {
Printf(" '%s' is ascii string '%s'\n", g.name, (char*)g.beg);
}
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g) {
- if (addr < g.beg - kGlobalAndStackRedzone) return false;
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+ const __asan_global &g) {
+ static const uptr kMinimalDistanceFromAnotherGlobal = 64;
+ if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
if (addr >= g.beg + g.size_with_redzone) return false;
Decorator d;
Printf("%s", d.Location());
- Printf("%p is located ", (void*)addr);
if (addr < g.beg) {
- Printf("%zd bytes to the left", g.beg - addr);
- } else if (addr >= g.beg + g.size) {
- Printf("%zd bytes to the right", addr - (g.beg + g.size));
+ Printf("%p is located %zd bytes to the left", (void*)addr, g.beg - addr);
+ } else if (addr + size > g.beg + g.size) {
+ if (addr < g.beg + g.size)
+ addr = g.beg + g.size;
+ Printf("%p is located %zd bytes to the right", (void*)addr,
+ addr - (g.beg + g.size));
} else {
- Printf("%zd bytes inside", addr - g.beg); // Can it happen?
+ // Can it happen?
+ Printf("%p is located %zd bytes inside", (void*)addr, addr - g.beg);
}
Printf(" of global variable '%s' (0x%zx) of size %zu\n",
g.name, g.beg, g.size);
@@ -280,18 +290,22 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
uptr access_size) {
- uptr offset;
+ sptr offset;
Decorator d;
Printf("%s", d.Location());
- Printf("%p is located ", (void*)addr);
- if (chunk.AddrIsInside(addr, access_size, &offset)) {
- Printf("%zu bytes inside of", offset);
- } else if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
- Printf("%zu bytes to the left of", offset);
+ if (chunk.AddrIsAtLeft(addr, access_size, &offset)) {
+ Printf("%p is located %zd bytes to the left of", (void*)addr, offset);
} else if (chunk.AddrIsAtRight(addr, access_size, &offset)) {
- Printf("%zu bytes to the right of", offset);
+ if (offset < 0) {
+ addr -= offset;
+ offset = 0;
+ }
+ Printf("%p is located %zd bytes to the right of", (void*)addr, offset);
+ } else if (chunk.AddrIsInside(addr, access_size, &offset)) {
+ Printf("%p is located %zd bytes inside of", (void*)addr, offset);
} else {
- Printf(" somewhere around (this is AddressSanitizer bug!)");
+ Printf("%p is located somewhere around (this is AddressSanitizer bug!)",
+ (void*)addr);
}
Printf(" %zu-byte region [%p,%p)\n", chunk.UsedSize(),
(void*)(chunk.Beg()), (void*)(chunk.End()));
@@ -364,7 +378,7 @@ void DescribeAddress(uptr addr, uptr access_size) {
if (DescribeAddressIfShadow(addr))
return;
CHECK(AddrIsInMem(addr));
- if (DescribeAddressIfGlobal(addr))
+ if (DescribeAddressIfGlobal(addr, access_size))
return;
if (DescribeAddressIfStack(addr, access_size))
return;
@@ -443,7 +457,8 @@ class ScopedInErrorReport {
DescribeThread(curr_thread->summary());
}
// Print memory stats.
- __asan_print_accumulated_stats();
+ if (flags()->print_stats)
+ __asan_print_accumulated_stats();
if (error_report_callback) {
error_report_callback(error_message_buffer);
}
@@ -452,6 +467,20 @@ class ScopedInErrorReport {
}
};
+static void ReportSummary(const char *error_type, StackTrace *stack) {
+ if (!stack->size) return;
+ if (IsSymbolizerAvailable()) {
+ AddressInfo ai;
+ // Currently, we include the first stack frame into the report summary.
+ // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+ SymbolizeCode(stack->trace[0], &ai, 1);
+ ReportErrorSummary(error_type,
+ StripPathPrefix(ai.file, flags()->strip_path_prefix),
+ ai.line, ai.function);
+ }
+ // FIXME: do we need to print anything at all if there is no symbolizer?
+}
+
void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
ScopedInErrorReport in_report;
Decorator d;
@@ -464,6 +493,7 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
Printf("AddressSanitizer can not provide additional info.\n");
GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
+ ReportSummary("SEGV", &stack);
}
void ReportDoubleFree(uptr addr, StackTrace *stack) {
@@ -474,6 +504,7 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
+ ReportSummary("double-free", stack);
}
void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
@@ -485,6 +516,7 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
+ ReportSummary("bad-free", stack);
}
void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
@@ -503,6 +535,7 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
+ ReportSummary("alloc-dealloc-mismatch", stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
@@ -517,6 +550,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
+ ReportSummary("bad-malloc_usable_size", stack);
}
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -529,6 +563,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
+ ReportSummary("bad-__asan_get_allocated_size", stack);
}
void ReportStringFunctionMemoryRangesOverlap(
@@ -536,14 +571,17 @@ void ReportStringFunctionMemoryRangesOverlap(
const char *offset2, uptr length2, StackTrace *stack) {
ScopedInErrorReport in_report;
Decorator d;
+ char bug_type[100];
+ internal_snprintf(bug_type, sizeof(bug_type), "%s-param-overlap", function);
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: %s-param-overlap: "
+ Report("ERROR: AddressSanitizer: %s: "
"memory ranges [%p,%p) and [%p, %p) overlap\n", \
- function, offset1, offset1 + length1, offset2, offset2 + length2);
+ bug_type, offset1, offset1 + length1, offset2, offset2 + length2);
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
+ ReportSummary(bug_type, stack);
}
// ----------------------- Mac-specific reports ----------------- {{{1
@@ -653,7 +691,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
PrintStack(&stack);
DescribeAddress(addr, access_size);
-
+ ReportSummary(bug_descr, &stack);
PrintShadowMemoryForAddress(addr);
}
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index a7e0e58..13724da 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -13,15 +13,15 @@
#include "asan_allocator.h"
#include "asan_internal.h"
#include "asan_thread.h"
-#include "sanitizer/asan_interface.h"
namespace __asan {
// The following functions prints address description depending
// on the memory type (shadow/heap/stack/global).
void DescribeHeapAddress(uptr addr, uptr access_size);
-bool DescribeAddressIfGlobal(uptr addr);
-bool DescribeAddressRelativeToGlobal(uptr addr, const __asan_global &g);
+bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
+ const __asan_global &g);
bool DescribeAddressIfShadow(uptr addr);
bool DescribeAddressIfStack(uptr addr, uptr access_size);
// Determines memory type on its own.
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 04d2d7a..175d377 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -18,7 +18,6 @@
#include "asan_stats.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_libc.h"
@@ -83,7 +82,6 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->replace_str, "replace_str");
ParseFlag(str, &f->replace_intrin, "replace_intrin");
- ParseFlag(str, &f->replace_cfallocator, "replace_cfallocator");
ParseFlag(str, &f->mac_ignore_invalid_free, "mac_ignore_invalid_free");
ParseFlag(str, &f->use_fake_stack, "use_fake_stack");
ParseFlag(str, &f->max_malloc_fill_size, "max_malloc_fill_size");
@@ -95,6 +93,8 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->check_malloc_usable_size, "check_malloc_usable_size");
ParseFlag(str, &f->unmap_shadow_on_exit, "unmap_shadow_on_exit");
ParseFlag(str, &f->abort_on_error, "abort_on_error");
+ ParseFlag(str, &f->print_stats, "print_stats");
+ ParseFlag(str, &f->print_legend, "print_legend");
ParseFlag(str, &f->atexit, "atexit");
ParseFlag(str, &f->disable_core, "disable_core");
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
@@ -121,7 +121,6 @@ void InitializeFlags(Flags *f, const char *env) {
f->malloc_context_size = kDeafultMallocContextSize;
f->replace_str = true;
f->replace_intrin = true;
- f->replace_cfallocator = true;
f->mac_ignore_invalid_free = false;
f->use_fake_stack = true;
f->max_malloc_fill_size = 0;
@@ -133,6 +132,8 @@ void InitializeFlags(Flags *f, const char *env) {
f->check_malloc_usable_size = true;
f->unmap_shadow_on_exit = false;
f->abort_on_error = false;
+ f->print_stats = false;
+ f->print_legend = true;
f->atexit = false;
f->disable_core = (SANITIZER_WORDSIZE == 64);
f->strip_path_prefix = "";
@@ -142,9 +143,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->fast_unwind_on_fatal = false;
f->fast_unwind_on_malloc = true;
f->poison_heap = true;
- // Turn off alloc/dealloc mismatch checker on Mac for now.
- // TODO(glider): Fix known issues and enable this back.
- f->alloc_dealloc_mismatch = (ASAN_MAC == 0);
+ f->alloc_dealloc_mismatch = true;
f->use_stack_depot = true; // Only affects allocator2.
// Override from user-specified string.
@@ -162,6 +161,7 @@ void InitializeFlags(Flags *f, const char *env) {
int asan_inited;
bool asan_init_is_running;
void (*death_callback)(void);
+uptr kHighMemEnd;
// -------------------------- Misc ---------------- {{{1
void ShowStatsAndAbort() {
@@ -261,6 +261,24 @@ static void asan_atexit() {
__asan_print_accumulated_stats();
}
+static void InitializeHighMemEnd() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__)
+ // FIXME:
+ // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+ // We somehow need to figure our which one we are using now and choose
+ // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
+ // Note that with 'ulimit -s unlimited' the stack is moved away from the top
+ // of the address space, so simply checking the stack address is not enough.
+ kHighMemEnd = (1ULL << 44) - 1; // 0x00000fffffffffffUL
+# else
+ kHighMemEnd = (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+ kHighMemEnd = (1ULL << 32) - 1; // 0xffffffff;
+#endif // SANITIZER_WORDSIZE
+}
+
} // namespace __asan
// ---------------------- Interface ---------------- {{{1
@@ -295,8 +313,10 @@ void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
void __asan_init() {
if (asan_inited) return;
+ SanitizerToolName = "AddressSanitizer";
CHECK(!asan_init_is_running && "ASan init calls itself!");
asan_init_is_running = true;
+ InitializeHighMemEnd();
// Make sure we are not statically linked.
AsanDoesNotSupportStaticLinkage();
@@ -400,6 +420,8 @@ void __asan_init() {
asanThreadRegistry().GetMain()->ThreadStart();
force_interface_symbols(); // no-op.
+ InitializeAllocator();
+
if (flags()->verbosity) {
Report("AddressSanitizer Init done\n");
}
diff --git a/libsanitizer/asan/asan_stack.cc b/libsanitizer/asan/asan_stack.cc
index 9b6a28e..999cbfba 100644
--- a/libsanitizer/asan/asan_stack.cc
+++ b/libsanitizer/asan/asan_stack.cc
@@ -9,9 +9,9 @@
//
// Code for ASan stack trace.
//===----------------------------------------------------------------------===//
+#include "asan_internal.h"
#include "asan_flags.h"
#include "asan_stack.h"
-#include "sanitizer/asan_interface.h"
namespace __asan {
diff --git a/libsanitizer/asan/asan_stats.cc b/libsanitizer/asan/asan_stats.cc
index 1187bd9..935b33e 100644
--- a/libsanitizer/asan/asan_stats.cc
+++ b/libsanitizer/asan/asan_stats.cc
@@ -13,7 +13,6 @@
#include "asan_internal.h"
#include "asan_stats.h"
#include "asan_thread_registry.h"
-#include "sanitizer/asan_interface.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
namespace __asan {
diff --git a/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc b/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
index 757c704..727edf2 100644
--- a/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
+++ b/libsanitizer/asan/dynamic/asan_interceptors_dynamic.cc
@@ -17,11 +17,6 @@
namespace __asan {
-#if !MAC_INTERPOSE_FUNCTIONS
-# error \
- Dynamic interposing library should be built with -DMAC_INTERPOSE_FUNCTIONS
-#endif
-
#define INTERPOSE_FUNCTION(function) \
{ reinterpret_cast<const uptr>(WRAP(function)), \
reinterpret_cast<const uptr>(function) }
diff --git a/libsanitizer/include/sanitizer/asan_interface.h b/libsanitizer/include/sanitizer/asan_interface.h
index 9f9f12c..18696a6 100644
--- a/libsanitizer/include/sanitizer/asan_interface.h
+++ b/libsanitizer/include/sanitizer/asan_interface.h
@@ -5,69 +5,18 @@
//
//===----------------------------------------------------------------------===//
//
-// This file is a part of AddressSanitizer, an address sanity checker.
+// This file is a part of AddressSanitizer.
//
-// This header can be included by the instrumented program to fetch
-// data (mostly allocator statistics) from ASan runtime library.
+// Public interface header.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_ASAN_INTERFACE_H
#define SANITIZER_ASAN_INTERFACE_H
#include <sanitizer/common_interface_defs.h>
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers from ASan runtime.
-// All functions in this header are extern "C" and start with __asan_.
-
-using __sanitizer::uptr;
-
+#ifdef __cplusplus
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 __asan_init() SANITIZER_INTERFACE_ATTRIBUTE;
-
- // This structure describes an instrumented global variable.
- struct __asan_global {
- uptr beg; // The address of the global.
- uptr size; // The original size of the global.
- uptr size_with_redzone; // The size with the redzone.
- const char *name; // Name as a C string.
- uptr has_dynamic_init; // Non-zero if the global has dynamic initializer.
- };
-
- // These two functions should be called by the instrumented code.
- // 'globals' is an array of structures describing 'n' globals.
- void __asan_register_globals(__asan_global *globals, uptr n)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_unregister_globals(__asan_global *globals, uptr n)
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // These two functions should be called before and after dynamic initializers
- // run, respectively. They should be called with parameters describing all
- // dynamically initialized globals defined in the calling TU.
- void __asan_before_dynamic_init(uptr first_addr, uptr last_addr)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_after_dynamic_init()
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // These two functions are used by the instrumented code in the
- // use-after-return mode. __asan_stack_malloc allocates size bytes of
- // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
- // the real stack region.
- uptr __asan_stack_malloc(uptr size, uptr real_stack)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_stack_free(uptr ptr, uptr size, uptr real_stack)
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // These two functions are used by instrumented code in the
- // use-after-scope mode. They mark memory for local variables as
- // unaddressable when they leave scope and addressable before the
- // function exits.
- void __asan_poison_stack_memory(uptr addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
- void __asan_unpoison_stack_memory(uptr addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
-
+#endif
// Marks memory region [addr, addr+size) as unaddressable.
// This memory must be previously allocated by the user program. Accessing
// addresses in this region from instrumented code is forbidden until
@@ -76,8 +25,7 @@ extern "C" {
// to ASan alignment restrictions.
// Method is NOT thread-safe in the sense that no two threads can
// (un)poison memory in the same memory region simultaneously.
- void __asan_poison_memory_region(void const volatile *addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_poison_memory_region(void const volatile *addr, size_t size);
// Marks memory region [addr, addr+size) as addressable.
// This memory must be previously allocated by the user program. Accessing
// addresses in this region is allowed until this region is poisoned again.
@@ -85,14 +33,9 @@ extern "C" {
// ASan alignment restrictions.
// Method is NOT thread-safe in the sense that no two threads can
// (un)poison memory in the same memory region simultaneously.
- void __asan_unpoison_memory_region(void const volatile *addr, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
-
- // Performs cleanup before a NoReturn function. Must be called before things
- // like _exit and execl to avoid false positives on stack.
- void __asan_handle_no_return() SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
-// User code should use macro instead of functions.
+ // User code should use macro instead of functions.
#if __has_feature(address_sanitizer)
#define ASAN_POISON_MEMORY_REGION(addr, size) \
__asan_poison_memory_region((addr), (size))
@@ -107,104 +50,86 @@ extern "C" {
// Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
// address will result in error report from AddressSanitizer).
- bool __asan_address_is_poisoned(void const volatile *addr)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ bool __asan_address_is_poisoned(void const volatile *addr);
// If at least on byte in [beg, beg+size) is poisoned, return the address
// of the first such byte. Otherwise return 0.
- uptr __asan_region_is_poisoned(uptr beg, uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void *__asan_region_is_poisoned(void *beg, size_t size);
// Print the description of addr (useful when debugging in gdb).
- void __asan_describe_address(uptr addr)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_describe_address(void *addr);
// This is an internal function that is called to report an error.
// However it is still a part of the interface because users may want to
// set a breakpoint on this function in a debugger.
- void __asan_report_error(uptr pc, uptr bp, uptr sp,
- uptr addr, bool is_write, uptr access_size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_report_error(void *pc, void *bp, void *sp,
+ void *addr, bool is_write, size_t access_size);
// Sets the exit code to use when reporting an error.
// Returns the old value.
- int __asan_set_error_exit_code(int exit_code)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ int __asan_set_error_exit_code(int exit_code);
// Sets the callback to be called right before death on error.
// Passing 0 will unset the callback.
- void __asan_set_death_callback(void (*callback)(void))
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_set_death_callback(void (*callback)(void));
- void __asan_set_error_report_callback(void (*callback)(const char*))
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_set_error_report_callback(void (*callback)(const char*));
// User may provide function that would be called right when ASan detects
// an error. This can be used to notice cases when ASan detects an error, but
// the program crashes before ASan report is printed.
- /* OPTIONAL */ void __asan_on_error()
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_on_error();
// User may provide its own implementation for symbolization function.
// It should print the description of instruction at address "pc" to
// "out_buffer". Description should be at most "out_size" bytes long.
// User-specified function should return true if symbolization was
// successful.
- /* OPTIONAL */ bool __asan_symbolize(const void *pc, char *out_buffer,
- int out_size)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ bool __asan_symbolize(const void *pc, char *out_buffer,
+ int out_size);
// Returns the estimated number of bytes that will be reserved by allocator
// for request of "size" bytes. If ASan allocator can't allocate that much
// memory, returns the maximal possible allocation size, otherwise returns
// "size".
- uptr __asan_get_estimated_allocated_size(uptr size)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_estimated_allocated_size(size_t size);
// Returns true if p was returned by the ASan allocator and
// is not yet freed.
- bool __asan_get_ownership(const void *p)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ bool __asan_get_ownership(const void *p);
// Returns the number of bytes reserved for the pointer p.
// Requires (get_ownership(p) == true) or (p == 0).
- uptr __asan_get_allocated_size(const void *p)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_allocated_size(const void *p);
// Number of bytes, allocated and not yet freed by the application.
- uptr __asan_get_current_allocated_bytes()
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_current_allocated_bytes();
// Number of bytes, mmaped by asan allocator to fulfill allocation requests.
// Generally, for request of X bytes, allocator can reserve and add to free
// lists a large number of chunks of size X to use them for future requests.
// All these chunks count toward the heap size. Currently, allocator never
// releases memory to OS (instead, it just puts freed chunks to free lists).
- uptr __asan_get_heap_size()
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_heap_size();
// Number of bytes, mmaped by asan allocator, which can be used to fulfill
// allocation requests. When a user program frees memory chunk, it can first
// fall into quarantine and will count toward __asan_get_free_bytes() later.
- uptr __asan_get_free_bytes()
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_free_bytes();
// Number of bytes in unmapped pages, that are released to OS. Currently,
// always returns 0.
- uptr __asan_get_unmapped_bytes()
- SANITIZER_INTERFACE_ATTRIBUTE;
+ size_t __asan_get_unmapped_bytes();
// Prints accumulated stats to stderr. Used for debugging.
- void __asan_print_accumulated_stats()
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_print_accumulated_stats();
// This function may be optionally provided by user and should return
// a string containing ASan runtime options. See asan_flags.h for details.
- /* OPTIONAL */ const char* __asan_default_options()
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ const char* __asan_default_options();
// Malloc hooks that may be optionally provided by user.
// __asan_malloc_hook(ptr, size) is called immediately after
// allocation of "size" bytes, which returned "ptr".
// __asan_free_hook(ptr) is called immediately before
// deallocation of "ptr".
- /* OPTIONAL */ void __asan_malloc_hook(void *ptr, uptr size)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
- /* OPTIONAL */ void __asan_free_hook(void *ptr)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ void __asan_malloc_hook(void *ptr, size_t size);
+ void __asan_free_hook(void *ptr);
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // SANITIZER_ASAN_INTERFACE_H
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index 9fba976..b61b8a1 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -5,86 +5,37 @@
//
//===----------------------------------------------------------------------===//
//
-// This file is shared between AddressSanitizer and ThreadSanitizer.
-// It contains basic macro and types.
-// NOTE: This file may be included into user code.
+// Common part of the public sanitizer interface.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_COMMON_INTERFACE_DEFS_H
#define SANITIZER_COMMON_INTERFACE_DEFS_H
-// ----------- ATTENTION -------------
-// This header should NOT include any other headers to avoid portability issues.
-
-#if defined(_WIN32)
-// FIXME find out what we need on Windows. __declspec(dllexport) ?
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#elif defined(SANITIZER_GO)
-# define SANITIZER_INTERFACE_ATTRIBUTE
-# define SANITIZER_WEAK_ATTRIBUTE
-#else
-# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
-# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
-#endif
-
-#ifdef __linux__
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
-#else
-# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
-#endif
-
-// __has_feature
-#if !defined(__has_feature)
-# define __has_feature(x) 0
-#endif
-
-// For portability reasons we do not include stddef.h, stdint.h or any other
-// system header, but we do need some basic types that are not defined
-// in a portable way by the language itself.
-namespace __sanitizer {
-
-#if defined(_WIN64)
-// 64-bit Windows uses LLP64 data model.
-typedef unsigned long long uptr; // NOLINT
-typedef signed long long sptr; // NOLINT
-#else
-typedef unsigned long uptr; // NOLINT
-typedef signed long sptr; // NOLINT
-#endif // defined(_WIN64)
-#if defined(__x86_64__)
-// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
-// 64-bit pointer to unwind stack frame.
-typedef unsigned long long uhwptr; // NOLINT
-#else
-typedef uptr uhwptr; // NOLINT
-#endif
-typedef unsigned char u8;
-typedef unsigned short u16; // NOLINT
-typedef unsigned int u32;
-typedef unsigned long long u64; // NOLINT
-typedef signed char s8;
-typedef signed short s16; // NOLINT
-typedef signed int s32;
-typedef signed long long s64; // NOLINT
-
-} // namespace __sanitizer
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
extern "C" {
+#endif
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
- void __sanitizer_set_report_path(const char *path)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __sanitizer_set_report_path(const char *path);
// Tell the tools to write their reports to given file descriptor instead of
// stderr.
- void __sanitizer_set_report_fd(int fd)
- SANITIZER_INTERFACE_ATTRIBUTE;
+ void __sanitizer_set_report_fd(int fd);
// Notify the tools that the sandbox is going to be turned on. The reserved
// parameter will be used in the future to hold a structure with functions
// that the tools may call to bypass the sandbox.
- void __sanitizer_sandbox_on_notify(void *reserved)
- SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+ void __sanitizer_sandbox_on_notify(void *reserved);
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ void __sanitizer_report_error_summary(const char *error_summary);
+
+#ifdef __cplusplus
} // extern "C"
+#endif
#endif // SANITIZER_COMMON_INTERFACE_DEFS_H
diff --git a/libsanitizer/interception/Makefile.am b/libsanitizer/interception/Makefile.am
index 8c6fbbf..4218983 100644
--- a/libsanitizer/interception/Makefile.am
+++ b/libsanitizer/interception/Makefile.am
@@ -1,4 +1,4 @@
-AM_CPPFLAGS = -I $(top_srcdir)/include
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
# May be used by toolexeclibdir.
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -13,7 +13,8 @@ noinst_LTLIBRARIES = libinterception.la
interception_files = \
interception_linux.cc \
interception_mac.cc \
- interception_win.cc
+ interception_win.cc \
+ interception_type_test.cc
libinterception_la_SOURCES = $(interception_files)
diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in
index cc07bd1..f7c715b 100644
--- a/libsanitizer/interception/Makefile.in
+++ b/libsanitizer/interception/Makefile.in
@@ -56,7 +56,7 @@ CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libinterception_la_LIBADD =
am__objects_1 = interception_linux.lo interception_mac.lo \
- interception_win.lo
+ interception_win.lo interception_type_test.lo
am_libinterception_la_OBJECTS = $(am__objects_1)
libinterception_la_OBJECTS = $(am_libinterception_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@
@@ -208,7 +208,7 @@ toolexeclibdir = @toolexeclibdir@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I $(top_srcdir)/include
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
# May be used by toolexeclibdir.
gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER)
@@ -221,7 +221,8 @@ noinst_LTLIBRARIES = libinterception.la
interception_files = \
interception_linux.cc \
interception_mac.cc \
- interception_win.cc
+ interception_win.cc \
+ interception_type_test.cc
libinterception_la_SOURCES = $(interception_files)
@@ -318,6 +319,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_type_test.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interception_win.Plo@am__quote@
.cc.o:
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index ccf5e1b..b4c4137 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -17,7 +17,7 @@
# error "Interception doesn't work on this operating system."
#endif
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
// These typedefs should be used only in the interceptor definitions to replace
// the standard system types (e.g. SSIZE_T instead of ssize_t)
@@ -25,21 +25,17 @@ typedef __sanitizer::uptr SIZE_T;
typedef __sanitizer::sptr SSIZE_T;
typedef __sanitizer::sptr PTRDIFF_T;
typedef __sanitizer::s64 INTMAX_T;
-typedef __sanitizer::u64 OFF_T;
+// WARNING: OFF_T may be different from OS type off_t, depending on the value of
+// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
+// like pread and mmap, as opposed to pread64 and mmap64.
+// Mac is special.
+#ifdef __APPLE__
+typedef __sanitizer::u64 OFF_T;
+#else
+typedef __sanitizer::uptr OFF_T;
+#endif
typedef __sanitizer::u64 OFF64_T;
-// How to use this library:
-// 1) Include this header to define your own interceptors
-// (see details below).
-// 2) Build all *.cc files and link against them.
-// On Mac you will also need to:
-// 3) Provide your own implementation for the following functions:
-// mach_error_t __interception::allocate_island(void **ptr,
-// size_t size,
-// void *hint);
-// mach_error_t __interception::deallocate_island(void *ptr);
-// See "interception_mac.h" for more details.
-
// How to add an interceptor:
// Suppose you need to wrap/replace system function (generally, from libc):
// int foo(const char *bar, double baz);
@@ -80,20 +76,12 @@ typedef __sanitizer::u64 OFF64_T;
// This is not so on Mac OS, where the two-level namespace makes
// our replacement functions invisible to other libraries. This may be overcomed
// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
-// libraries in Chromium were noticed when doing so. Instead we use
-// mach_override, a handy framework for patching functions at runtime.
-// To avoid possible name clashes, our replacement functions have
-// the "wrap_" prefix on Mac.
-// An alternative to function patching is to create a dylib containing a
-// __DATA,__interpose section that associates library functions with their
-// wrappers. When this dylib is preloaded before an executable using
-// DYLD_INSERT_LIBRARIES, it routes all the calls to interposed functions done
-// through stubs to the wrapper functions. Such a library is built with
-// -DMAC_INTERPOSE_FUNCTIONS=1.
-
-#if !defined(MAC_INTERPOSE_FUNCTIONS) || !defined(__APPLE__)
-# define MAC_INTERPOSE_FUNCTIONS 0
-#endif
+// libraries in Chromium were noticed when doing so.
+// Instead we create a dylib containing a __DATA,__interpose section that
+// associates library functions with their wrappers. When this dylib is
+// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all
+// the calls to interposed functions done through stubs to the wrapper
+// functions.
#if defined(__APPLE__)
# define WRAP(x) wrap_##x
@@ -120,7 +108,7 @@ typedef __sanitizer::u64 OFF64_T;
__attribute__((weak, alias("__interceptor_" #func), visibility("default")));
#endif
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
# define PTR_TO_REAL(x) real_##x
# define REAL(x) __interception::PTR_TO_REAL(x)
# define FUNC_TYPE(x) x##_f
@@ -130,11 +118,11 @@ typedef __sanitizer::u64 OFF64_T;
namespace __interception { \
extern FUNC_TYPE(func) PTR_TO_REAL(func); \
}
-#else // MAC_INTERPOSE_FUNCTIONS
+#else // __APPLE__
# define REAL(x) x
# define DECLARE_REAL(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__);
-#endif // MAC_INTERPOSE_FUNCTIONS
+#endif // __APPLE__
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
DECLARE_REAL(ret_type, func, __VA_ARGS__) \
@@ -144,7 +132,7 @@ typedef __sanitizer::u64 OFF64_T;
// macros does its job. In exceptional cases you may need to call REAL(foo)
// without defining INTERCEPTOR(..., foo, ...). For example, if you override
// foo with an interceptor for other function.
-#if !MAC_INTERPOSE_FUNCTIONS
+#if !defined(__APPLE__)
# define DEFINE_REAL(ret_type, func, ...) \
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
namespace __interception { \
diff --git a/libsanitizer/interception/interception_mac.cc b/libsanitizer/interception/interception_mac.cc
index c9b7dd3..801dcba 100644
--- a/libsanitizer/interception/interception_mac.cc
+++ b/libsanitizer/interception/interception_mac.cc
@@ -13,17 +13,6 @@
#ifdef __APPLE__
#include "interception.h"
-#include "mach_override/mach_override.h"
-namespace __interception {
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) {
- *orig_old_func = 0;
- int res = __asan_mach_override_ptr_custom((void*)old_func, (void*)new_func,
- (void**)orig_old_func,
- __interception_allocate_island,
- __interception_deallocate_island);
- return (res == 0) && (*orig_old_func != 0);
-}
-} // namespace __interception
#endif // __APPLE__
diff --git a/libsanitizer/interception/interception_mac.h b/libsanitizer/interception/interception_mac.h
index 244b457..1b11182 100644
--- a/libsanitizer/interception/interception_mac.h
+++ b/libsanitizer/interception/interception_mac.h
@@ -19,29 +19,7 @@
#ifndef INTERCEPTION_MAC_H
#define INTERCEPTION_MAC_H
-#include <mach/mach_error.h>
-#include <stddef.h>
-
-// Allocate memory for the escape island. This cannot be moved to
-// mach_override, because each user of interceptors may specify its
-// own memory range for escape islands.
-extern "C" {
-mach_error_t __interception_allocate_island(void **ptr, size_t unused_size,
- void *unused_hint);
-mach_error_t __interception_deallocate_island(void *ptr);
-} // extern "C"
-
-namespace __interception {
-// returns true if the old function existed.
-bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
-} // namespace __interception
-
-# define OVERRIDE_FUNCTION_MAC(old_func, new_func) \
- ::__interception::OverrideFunction( \
- (::__interception::uptr)old_func, \
- (::__interception::uptr)new_func, \
- (::__interception::uptr*)((::__interception::uptr)&REAL(old_func)))
-# define INTERCEPT_FUNCTION_MAC(func) OVERRIDE_FUNCTION_MAC(func, WRAP(func))
+#define INTERCEPT_FUNCTION_MAC(func)
#endif // INTERCEPTION_MAC_H
#endif // __APPLE__
diff --git a/libsanitizer/interception/interception_type_test.cc b/libsanitizer/interception/interception_type_test.cc
new file mode 100644
index 0000000..f664eee
--- /dev/null
+++ b/libsanitizer/interception/interception_type_test.cc
@@ -0,0 +1,37 @@
+//===-- interception_type_test.cc -------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Compile-time tests of the internal type definitions.
+//===----------------------------------------------------------------------===//
+
+#if defined(__linux__) || defined(__APPLE__)
+
+#include "interception.h"
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdint.h>
+
+COMPILER_CHECK(sizeof(SIZE_T) == sizeof(size_t));
+COMPILER_CHECK(sizeof(SSIZE_T) == sizeof(ssize_t));
+COMPILER_CHECK(sizeof(PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK(sizeof(INTMAX_T) == sizeof(intmax_t));
+
+#ifndef __APPLE__
+COMPILER_CHECK(sizeof(OFF64_T) == sizeof(off64_t));
+#endif
+
+// The following are the cases when pread (and friends) is used instead of
+// pread64. In those cases we need OFF_T to match off_t. We don't care about the
+// rest (they depend on _FILE_OFFSET_BITS setting when building an application).
+# if defined(__ANDROID__) || !defined _FILE_OFFSET_BITS || \
+ _FILE_OFFSET_BITS != 64
+COMPILER_CHECK(sizeof(OFF_T) == sizeof(off_t));
+# endif
+
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cc b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
index d091127..a54de9d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
@@ -73,4 +73,10 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
low_level_alloc_callback = callback;
}
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
+ if (!size) return false;
+ uptr max = (uptr)-1L;
+ return (max / size) < n;
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h
index 1c9852e..8892812 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h
@@ -23,9 +23,9 @@ namespace __sanitizer {
// SizeClassMap maps allocation sizes into size classes and back.
// Class 0 corresponds to size 0.
-// Classes 1 - 16 correspond to sizes 8 - 128 (size = class_id * 8).
-// Next 8 classes: 128 + i * 16 (i = 1 to 8).
+// Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
// Next 8 classes: 256 + i * 32 (i = 1 to 8).
+// Next 8 classes: 512 + i * 64 (i = 1 to 8).
// ...
// Next 8 classes: 2^k + i * 2^(k-3) (i = 1 to 8).
// Last class corresponds to kMaxSize = 1 << kMaxSizeLog.
@@ -40,33 +40,48 @@ namespace __sanitizer {
// - (1 << kMaxBytesCachedLog) is the maximal number of bytes per size class.
//
// Part of output of SizeClassMap::Print():
-// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
-// c01 => s: 8 diff: +8 00% l 3 cached: 256 2048; id 1
-// c02 => s: 16 diff: +8 100% l 4 cached: 256 4096; id 2
-// ...
-// c07 => s: 56 diff: +8 16% l 5 cached: 256 14336; id 7
+// c00 => s: 0 diff: +0 00% l 0 cached: 0 0; id 0
+// c01 => s: 16 diff: +16 00% l 4 cached: 256 4096; id 1
+// c02 => s: 32 diff: +16 100% l 5 cached: 256 8192; id 2
+// c03 => s: 48 diff: +16 50% l 5 cached: 256 12288; id 3
+// c04 => s: 64 diff: +16 33% l 6 cached: 256 16384; id 4
+// c05 => s: 80 diff: +16 25% l 6 cached: 256 20480; id 5
+// c06 => s: 96 diff: +16 20% l 6 cached: 256 24576; id 6
+// c07 => s: 112 diff: +16 16% l 6 cached: 256 28672; id 7
//
-// c08 => s: 64 diff: +8 14% l 6 cached: 256 16384; id 8
-// ...
-// c15 => s: 120 diff: +8 07% l 6 cached: 256 30720; id 15
+// c08 => s: 128 diff: +16 14% l 7 cached: 256 32768; id 8
+// c09 => s: 144 diff: +16 12% l 7 cached: 256 36864; id 9
+// c10 => s: 160 diff: +16 11% l 7 cached: 256 40960; id 10
+// c11 => s: 176 diff: +16 10% l 7 cached: 256 45056; id 11
+// c12 => s: 192 diff: +16 09% l 7 cached: 256 49152; id 12
+// c13 => s: 208 diff: +16 08% l 7 cached: 256 53248; id 13
+// c14 => s: 224 diff: +16 07% l 7 cached: 256 57344; id 14
+// c15 => s: 240 diff: +16 07% l 7 cached: 256 61440; id 15
//
-// c16 => s: 128 diff: +8 06% l 7 cached: 256 32768; id 16
-// c17 => s: 144 diff: +16 12% l 7 cached: 227 32688; id 17
-// ...
-// c23 => s: 240 diff: +16 07% l 7 cached: 136 32640; id 23
+// c16 => s: 256 diff: +16 06% l 8 cached: 256 65536; id 16
+// c17 => s: 288 diff: +32 12% l 8 cached: 227 65376; id 17
+// c18 => s: 320 diff: +32 11% l 8 cached: 204 65280; id 18
+// c19 => s: 352 diff: +32 10% l 8 cached: 186 65472; id 19
+// c20 => s: 384 diff: +32 09% l 8 cached: 170 65280; id 20
+// c21 => s: 416 diff: +32 08% l 8 cached: 157 65312; id 21
+// c22 => s: 448 diff: +32 07% l 8 cached: 146 65408; id 22
+// c23 => s: 480 diff: +32 07% l 8 cached: 136 65280; id 23
//
-// c24 => s: 256 diff: +16 06% l 8 cached: 128 32768; id 24
-// c25 => s: 288 diff: +32 12% l 8 cached: 113 32544; id 25
-// ...
-// c31 => s: 480 diff: +32 07% l 8 cached: 68 32640; id 31
+// c24 => s: 512 diff: +32 06% l 9 cached: 128 65536; id 24
+// c25 => s: 576 diff: +64 12% l 9 cached: 113 65088; id 25
+// c26 => s: 640 diff: +64 11% l 9 cached: 102 65280; id 26
+// c27 => s: 704 diff: +64 10% l 9 cached: 93 65472; id 27
+// c28 => s: 768 diff: +64 09% l 9 cached: 85 65280; id 28
+// c29 => s: 832 diff: +64 08% l 9 cached: 78 64896; id 29
+// c30 => s: 896 diff: +64 07% l 9 cached: 73 65408; id 30
+// c31 => s: 960 diff: +64 07% l 9 cached: 68 65280; id 31
//
-// c32 => s: 512 diff: +32 06% l 9 cached: 64 32768; id 32
-
+// c32 => s: 1024 diff: +64 06% l 10 cached: 64 65536; id 32
template <uptr kMaxSizeLog, uptr kMaxNumCachedT, uptr kMaxBytesCachedLog,
uptr kMinBatchClassT>
class SizeClassMap {
- static const uptr kMinSizeLog = 3;
+ static const uptr kMinSizeLog = 4;
static const uptr kMidSizeLog = kMinSizeLog + 4;
static const uptr kMinSize = 1 << kMinSizeLog;
static const uptr kMidSize = 1 << kMidSizeLog;
@@ -104,7 +119,7 @@ class SizeClassMap {
if (size <= kMidSize)
return (size + kMinSize - 1) >> kMinSizeLog;
if (size > kMaxSize) return 0;
- uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size);
+ uptr l = MostSignificantSetBitIndex(size);
uptr hbits = (size >> (l - S)) & M;
uptr lbits = size & ((1 << (l - S)) - 1);
uptr l1 = l - kMidSizeLog;
@@ -114,7 +129,7 @@ class SizeClassMap {
static uptr MaxCached(uptr class_id) {
if (class_id == 0) return 0;
uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
- return Max(1UL, Min(kMaxNumCached, n));
+ return Max<uptr>(1, Min(kMaxNumCached, n));
}
static void Print() {
@@ -126,7 +141,7 @@ class SizeClassMap {
Printf("\n");
uptr d = s - prev_s;
uptr p = prev_s ? (d * 100 / prev_s) : 0;
- uptr l = SANITIZER_WORDSIZE - 1 - __builtin_clzl(s);
+ uptr l = MostSignificantSetBitIndex(s);
uptr cached = MaxCached(i) * s;
Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
"cached: %zd %zd; id %zd\n",
@@ -172,12 +187,92 @@ class SizeClassMap {
}
};
-typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(33, 36)>
+typedef SizeClassMap<17, 256, 16, FIRST_32_SECOND_64(25, 28)>
DefaultSizeClassMap;
-typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(25, 28)>
+typedef SizeClassMap<17, 64, 14, FIRST_32_SECOND_64(17, 20)>
CompactSizeClassMap;
template<class SizeClassAllocator> struct SizeClassAllocatorLocalCache;
+// Memory allocator statistics
+enum AllocatorStat {
+ AllocatorStatMalloced,
+ AllocatorStatFreed,
+ AllocatorStatMmapped,
+ AllocatorStatUnmapped,
+ AllocatorStatCount
+};
+
+typedef u64 AllocatorStatCounters[AllocatorStatCount];
+
+// Per-thread stats, live in per-thread cache.
+class AllocatorStats {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ }
+
+ void Add(AllocatorStat i, u64 v) {
+ v += atomic_load(&stats_[i], memory_order_relaxed);
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ void Set(AllocatorStat i, u64 v) {
+ atomic_store(&stats_[i], v, memory_order_relaxed);
+ }
+
+ u64 Get(AllocatorStat i) const {
+ return atomic_load(&stats_[i], memory_order_relaxed);
+ }
+
+ private:
+ friend class AllocatorGlobalStats;
+ AllocatorStats *next_;
+ AllocatorStats *prev_;
+ atomic_uint64_t stats_[AllocatorStatCount];
+};
+
+// Global stats, used for aggregation and querying.
+class AllocatorGlobalStats : public AllocatorStats {
+ public:
+ void Init() {
+ internal_memset(this, 0, sizeof(*this));
+ next_ = this;
+ prev_ = this;
+ }
+
+ void Register(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->next_ = next_;
+ s->prev_ = this;
+ next_->prev_ = s;
+ next_ = s;
+ }
+
+ void Unregister(AllocatorStats *s) {
+ SpinMutexLock l(&mu_);
+ s->prev_->next_ = s->next_;
+ s->next_->prev_ = s->prev_;
+ for (int i = 0; i < AllocatorStatCount; i++)
+ Add(AllocatorStat(i), s->Get(AllocatorStat(i)));
+ }
+
+ void Get(AllocatorStatCounters s) const {
+ internal_memset(s, 0, AllocatorStatCount * sizeof(u64));
+ SpinMutexLock l(&mu_);
+ const AllocatorStats *stats = this;
+ for (;;) {
+ for (int i = 0; i < AllocatorStatCount; i++)
+ s[i] += stats->Get(AllocatorStat(i));
+ stats = stats->next_;
+ if (stats == this)
+ break;
+ }
+ }
+
+ private:
+ mutable SpinMutex mu_;
+};
+
// Allocators call these callbacks on mmap/munmap.
struct NoOpMapUnmapCallback {
void OnMap(uptr p, uptr size) const { }
@@ -231,17 +326,18 @@ class SizeClassAllocator64 {
alignment <= SizeClassMap::kMaxSize;
}
- Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
CHECK_LT(class_id, kNumClasses);
RegionInfo *region = GetRegionInfo(class_id);
Batch *b = region->free_list.Pop();
if (b == 0)
- b = PopulateFreeList(c, class_id, region);
+ b = PopulateFreeList(stat, c, class_id, region);
region->n_allocated += b->count;
return b;
}
- void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
RegionInfo *region = GetRegionInfo(class_id);
region->free_list.Push(b);
region->n_freed += b->count;
@@ -320,6 +416,20 @@ class SizeClassAllocator64 {
}
}
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetRegionInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = (int)kNumClasses - 1; i >= 0; i--) {
+ GetRegionInfo(i)->mutex.Unlock();
+ }
+ }
+
typedef SizeClassMap SizeClassMapT;
static const uptr kNumClasses = SizeClassMap::kNumClasses;
static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
@@ -334,7 +444,7 @@ class SizeClassAllocator64 {
// or with one element if its size is greater.
static const uptr kPopulateSize = 1 << 14;
// Call mmap for user memory with at least this size.
- static const uptr kUserMapSize = 1 << 15;
+ static const uptr kUserMapSize = 1 << 16;
// Call mmap for metadata memory with at least this size.
static const uptr kMetaMapSize = 1 << 16;
@@ -368,8 +478,8 @@ class SizeClassAllocator64 {
return offset / (u32)size;
}
- Batch *NOINLINE PopulateFreeList(AllocatorCache *c, uptr class_id,
- RegionInfo *region) {
+ NOINLINE Batch* PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id, RegionInfo *region) {
BlockingMutexLock l(&region->mutex);
Batch *b = region->free_list.Pop();
if (b)
@@ -386,6 +496,7 @@ class SizeClassAllocator64 {
map_size += kUserMapSize;
CHECK_GE(region->mapped_user + map_size, end_idx);
MapWithCallback(region_beg + region->mapped_user, map_size);
+ stat->Add(AllocatorStatMmapped, map_size);
region->mapped_user += map_size;
}
uptr total_count = (region->mapped_user - beg_idx - size)
@@ -467,6 +578,7 @@ class SizeClassAllocator32 {
MapUnmapCallback().OnMap((uptr)res, size);
return res;
}
+
void UnmapWithCallback(uptr beg, uptr size) {
MapUnmapCallback().OnUnmap(beg, size);
UnmapOrDie(reinterpret_cast<void *>(beg), size);
@@ -488,19 +600,20 @@ class SizeClassAllocator32 {
return reinterpret_cast<void*>(meta);
}
- Batch *NOINLINE AllocateBatch(AllocatorCache *c, uptr class_id) {
+ NOINLINE Batch* AllocateBatch(AllocatorStats *stat, AllocatorCache *c,
+ uptr class_id) {
CHECK_LT(class_id, kNumClasses);
SizeClassInfo *sci = GetSizeClassInfo(class_id);
SpinMutexLock l(&sci->mutex);
if (sci->free_list.empty())
- PopulateFreeList(c, sci, class_id);
+ PopulateFreeList(stat, c, sci, class_id);
CHECK(!sci->free_list.empty());
Batch *b = sci->free_list.front();
sci->free_list.pop_front();
return b;
}
- void NOINLINE DeallocateBatch(uptr class_id, Batch *b) {
+ NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id, Batch *b) {
CHECK_LT(class_id, kNumClasses);
SizeClassInfo *sci = GetSizeClassInfo(class_id);
SpinMutexLock l(&sci->mutex);
@@ -549,6 +662,20 @@ class SizeClassAllocator32 {
UnmapWithCallback(reinterpret_cast<uptr>(state_), sizeof(State));
}
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ for (uptr i = 0; i < kNumClasses; i++) {
+ GetSizeClassInfo(i)->mutex.Lock();
+ }
+ }
+
+ void ForceUnlock() {
+ for (int i = kNumClasses - 1; i >= 0; i--) {
+ GetSizeClassInfo(i)->mutex.Unlock();
+ }
+ }
+
void PrintStats() {
}
@@ -577,11 +704,12 @@ class SizeClassAllocator32 {
return mem & ~(kRegionSize - 1);
}
- uptr AllocateRegion(uptr class_id) {
+ uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
CHECK_LT(class_id, kNumClasses);
uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
"SizeClassAllocator32"));
MapUnmapCallback().OnMap(res, kRegionSize);
+ stat->Add(AllocatorStatMmapped, kRegionSize);
CHECK_EQ(0U, (res & (kRegionSize - 1)));
CHECK_EQ(0U, state_->possible_regions[ComputeRegionId(res)]);
state_->possible_regions[ComputeRegionId(res)] = class_id;
@@ -593,9 +721,10 @@ class SizeClassAllocator32 {
return &state_->size_class_info_array[class_id];
}
- void PopulateFreeList(AllocatorCache *c, SizeClassInfo *sci, uptr class_id) {
+ void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ SizeClassInfo *sci, uptr class_id) {
uptr size = SizeClassMap::Size(class_id);
- uptr reg = AllocateRegion(class_id);
+ uptr reg = AllocateRegion(stat, class_id);
uptr n_chunks = kRegionSize / (size + kMetadataSize);
uptr max_count = SizeClassMap::MaxCached(class_id);
Batch *b = 0;
@@ -632,14 +761,22 @@ struct SizeClassAllocatorLocalCache {
typedef SizeClassAllocator Allocator;
static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
- // Don't need to call Init if the object is a global (i.e. zero-initialized).
- void Init() {
- internal_memset(this, 0, sizeof(*this));
+ void Init(AllocatorGlobalStats *s) {
+ stats_.Init();
+ if (s)
+ s->Register(&stats_);
+ }
+
+ void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
+ Drain(allocator);
+ if (s)
+ s->Unregister(&stats_);
}
void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
CHECK_NE(class_id, 0UL);
CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatMalloced, SizeClassMap::Size(class_id));
PerClass *c = &per_class_[class_id];
if (UNLIKELY(c->count == 0))
Refill(allocator, class_id);
@@ -651,6 +788,7 @@ struct SizeClassAllocatorLocalCache {
void Deallocate(SizeClassAllocator *allocator, uptr class_id, void *p) {
CHECK_NE(class_id, 0UL);
CHECK_LT(class_id, kNumClasses);
+ stats_.Add(AllocatorStatFreed, SizeClassMap::Size(class_id));
PerClass *c = &per_class_[class_id];
if (UNLIKELY(c->count == c->max_count))
Drain(allocator, class_id);
@@ -674,6 +812,7 @@ struct SizeClassAllocatorLocalCache {
void *batch[2 * SizeClassMap::kMaxNumCached];
};
PerClass per_class_[kNumClasses];
+ AllocatorStats stats_;
void InitCache() {
if (per_class_[0].max_count)
@@ -684,10 +823,11 @@ struct SizeClassAllocatorLocalCache {
}
}
- void NOINLINE Refill(SizeClassAllocator *allocator, uptr class_id) {
+ NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
InitCache();
PerClass *c = &per_class_[class_id];
- Batch *b = allocator->AllocateBatch(this, class_id);
+ Batch *b = allocator->AllocateBatch(&stats_, this, class_id);
+ CHECK_GT(b->count, 0);
for (uptr i = 0; i < b->count; i++)
c->batch[i] = b->batch[i];
c->count = b->count;
@@ -695,7 +835,7 @@ struct SizeClassAllocatorLocalCache {
Deallocate(allocator, SizeClassMap::ClassID(sizeof(Batch)), b);
}
- void NOINLINE Drain(SizeClassAllocator *allocator, uptr class_id) {
+ NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
InitCache();
PerClass *c = &per_class_[class_id];
Batch *b;
@@ -710,7 +850,7 @@ struct SizeClassAllocatorLocalCache {
}
b->count = cnt;
c->count -= cnt;
- allocator->DeallocateBatch(class_id, b);
+ allocator->DeallocateBatch(&stats_, class_id, b);
}
};
@@ -725,7 +865,7 @@ class LargeMmapAllocator {
page_size_ = GetPageSizeCached();
}
- void *Allocate(uptr size, uptr alignment) {
+ void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
CHECK(IsPowerOfTwo(alignment));
uptr map_size = RoundUpMapSize(size);
if (alignment > page_size_)
@@ -744,7 +884,7 @@ class LargeMmapAllocator {
h->size = size;
h->map_beg = map_beg;
h->map_size = map_size;
- uptr size_log = SANITIZER_WORDSIZE - __builtin_clzl(map_size) - 1;
+ uptr size_log = MostSignificantSetBitIndex(map_size);
CHECK_LT(size_log, ARRAY_SIZE(stats.by_size_log));
{
SpinMutexLock l(&mutex_);
@@ -756,11 +896,13 @@ class LargeMmapAllocator {
stats.currently_allocated += map_size;
stats.max_allocated = Max(stats.max_allocated, stats.currently_allocated);
stats.by_size_log[size_log]++;
+ stat->Add(AllocatorStatMalloced, map_size);
+ stat->Add(AllocatorStatMmapped, map_size);
}
return reinterpret_cast<void*>(res);
}
- void Deallocate(void *p) {
+ void Deallocate(AllocatorStats *stat, void *p) {
Header *h = GetHeader(p);
{
SpinMutexLock l(&mutex_);
@@ -772,6 +914,8 @@ class LargeMmapAllocator {
n_chunks_--;
stats.n_frees++;
stats.currently_allocated -= h->map_size;
+ stat->Add(AllocatorStatFreed, h->map_size);
+ stat->Add(AllocatorStatUnmapped, h->map_size);
}
MapUnmapCallback().OnUnmap(h->map_beg, h->map_size);
UnmapOrDie(reinterpret_cast<void*>(h->map_beg), h->map_size);
@@ -838,6 +982,16 @@ class LargeMmapAllocator {
Printf("\n");
}
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ mutex_.Lock();
+ }
+
+ void ForceUnlock() {
+ mutex_.Unlock();
+ }
+
private:
static const int kMaxNumChunks = 1 << FIRST_32_SECOND_64(15, 18);
struct Header {
@@ -884,6 +1038,7 @@ class CombinedAllocator {
void Init() {
primary_.Init();
secondary_.Init();
+ stats_.Init();
}
void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
@@ -899,7 +1054,7 @@ class CombinedAllocator {
if (primary_.CanAllocate(size, alignment))
res = cache->Allocate(&primary_, primary_.ClassID(size));
else
- res = secondary_.Allocate(size, alignment);
+ res = secondary_.Allocate(&stats_, size, alignment);
if (alignment > 8)
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
if (cleared && res)
@@ -912,7 +1067,7 @@ class CombinedAllocator {
if (primary_.PointerIsMine(p))
cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
else
- secondary_.Deallocate(p);
+ secondary_.Deallocate(&stats_, p);
}
void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
@@ -967,20 +1122,48 @@ class CombinedAllocator {
void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
+ void InitCache(AllocatorCache *cache) {
+ cache->Init(&stats_);
+ }
+
+ void DestroyCache(AllocatorCache *cache) {
+ cache->Destroy(&primary_, &stats_);
+ }
+
void SwallowCache(AllocatorCache *cache) {
cache->Drain(&primary_);
}
+ void GetStats(AllocatorStatCounters s) const {
+ stats_.Get(s);
+ }
+
void PrintStats() {
primary_.PrintStats();
secondary_.PrintStats();
}
+ // ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
+ // introspection API.
+ void ForceLock() {
+ primary_.ForceLock();
+ secondary_.ForceLock();
+ }
+
+ void ForceUnlock() {
+ secondary_.ForceUnlock();
+ primary_.ForceUnlock();
+ }
+
private:
PrimaryAllocator primary_;
SecondaryAllocator secondary_;
+ AllocatorGlobalStats stats_;
};
+// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
+bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
+
} // namespace __sanitizer
#endif // SANITIZER_ALLOCATOR_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc
index 9b70ee0..4447c34 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cc
@@ -14,6 +14,8 @@
namespace __sanitizer {
+const char *SanitizerToolName = "SanitizerTool";
+
uptr GetPageSizeCached() {
static uptr PageSize;
if (!PageSize)
@@ -64,7 +66,7 @@ static void MaybeOpenReportFile() {
InternalScopedBuffer<char> report_path_full(4096);
internal_snprintf(report_path_full.data(), report_path_full.size(),
"%s.%d", report_path_prefix, GetPid());
- fd_t fd = internal_open(report_path_full.data(), true);
+ fd_t fd = OpenFile(report_path_full.data(), true);
if (fd == kInvalidFd) {
report_fd = kStderrFd;
log_to_file = false;
@@ -103,7 +105,7 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
*buff_size = 0;
// The files we usually open are not seekable, so try different buffer sizes.
for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
- fd_t fd = internal_open(file_name, /*write*/ false);
+ fd_t fd = OpenFile(file_name, /*write*/ false);
if (fd == kInvalidFd) return 0;
UnmapOrDie(*buff, *buff_size);
*buff = (char*)MmapOrDie(size, __FUNCTION__);
@@ -188,6 +190,16 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
return (void*)res;
}
+void ReportErrorSummary(const char *error_type, const char *file,
+ int line, const char *function) {
+ const int kMaxSize = 1024; // We don't want a summary too long.
+ InternalScopedBuffer<char> buff(kMaxSize);
+ internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s",
+ SanitizerToolName, error_type,
+ file ? file : "??", line, function ? function : "??");
+ __sanitizer_report_error_summary(buff.data());
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
@@ -220,4 +232,8 @@ void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
(void)reserved;
PrepareForSandboxing();
}
+
+void __sanitizer_report_error_summary(const char *error_summary) {
+ Printf("SUMMARY: %s\n", error_summary);
+}
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 6b10488..109966b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -17,6 +17,7 @@
#include "sanitizer_internal_defs.h"
namespace __sanitizer {
+struct StackTrace;
// Constants.
const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -28,6 +29,8 @@ const uptr kCacheLineSize = 128;
const uptr kCacheLineSize = 64;
#endif
+extern const char *SanitizerToolName; // Can be changed by the tool.
+
uptr GetPageSize();
uptr GetPageSizeCached();
uptr GetMmapGranularity();
@@ -103,6 +106,7 @@ void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
+fd_t OpenFile(const char *filename, bool write);
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// The size of the mmaped region is stored in '*buff_size',
@@ -152,20 +156,79 @@ typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
u64, u64);
void SetCheckFailedCallback(CheckFailedCallbackType callback);
+// Construct a one-line string like
+// SanitizerToolName: error_type file:line function
+// and call __sanitizer_report_error_summary on it.
+void ReportErrorSummary(const char *error_type, const char *file,
+ int line, const char *function);
+
// Math
+#if defined(_WIN32) && !defined(__clang__)
+extern "C" {
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT
+#if defined(_WIN64)
+unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT
+unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT
+#endif
+}
+#endif
+
+INLINE uptr MostSignificantSetBitIndex(uptr x) {
+ CHECK(x != 0);
+ unsigned long up; // NOLINT
+#if !defined(_WIN32) || defined(__clang__)
+ up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(x);
+#elif defined(_WIN64)
+ _BitScanReverse64(&up, x);
+#else
+ _BitScanReverse(&up, x);
+#endif
+ return up;
+}
+
INLINE bool IsPowerOfTwo(uptr x) {
return (x & (x - 1)) == 0;
}
+
+INLINE uptr RoundUpToPowerOfTwo(uptr size) {
+ CHECK(size);
+ if (IsPowerOfTwo(size)) return size;
+
+ uptr up = MostSignificantSetBitIndex(size);
+ CHECK(size < (1ULL << (up + 1)));
+ CHECK(size > (1ULL << up));
+ return 1UL << (up + 1);
+}
+
INLINE uptr RoundUpTo(uptr size, uptr boundary) {
CHECK(IsPowerOfTwo(boundary));
return (size + boundary - 1) & ~(boundary - 1);
}
+
INLINE uptr RoundDownTo(uptr x, uptr boundary) {
return x & ~(boundary - 1);
}
+
INLINE bool IsAligned(uptr a, uptr alignment) {
return (a & (alignment - 1)) == 0;
}
+
+INLINE uptr Log2(uptr x) {
+ CHECK(IsPowerOfTwo(x));
+#if !defined(_WIN32) || defined(__clang__)
+ return __builtin_ctzl(x);
+#elif defined(_WIN64)
+ unsigned long ret; // NOLINT
+ _BitScanForward64(&ret, x);
+ return ret;
+#else
+ unsigned long ret; // NOLINT
+ _BitScanForward(&ret, x);
+ return ret;
+#endif
+}
+
// Don't use std::min, std::max or std::swap, to minimize dependency
// on libstdc++.
template<class T> T Min(T a, T b) { return a < b ? a : b; }
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 724a326..4ba7b8f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -22,9 +22,13 @@
#include <stdarg.h>
+#ifdef _WIN32
+#define va_copy(dst, src) ((dst) = (src))
+#endif // _WIN32
+
#if SANITIZER_INTERCEPT_READ
INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
- void* ctx;
+ void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
SSIZE_T res = REAL(read)(fd, ptr, count);
if (res > 0)
@@ -33,14 +37,14 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-# define INIT_READ INTERCEPT_FUNCTION(read)
+#define INIT_READ INTERCEPT_FUNCTION(read)
#else
-# define INIT_READ
+#define INIT_READ
#endif
#if SANITIZER_INTERCEPT_PREAD
INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
- void* ctx;
+ void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
if (res > 0)
@@ -49,14 +53,14 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-# define INIT_PREAD INTERCEPT_FUNCTION(pread)
+#define INIT_PREAD INTERCEPT_FUNCTION(pread)
#else
-# define INIT_PREAD
+#define INIT_PREAD
#endif
#if SANITIZER_INTERCEPT_PREAD64
INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
- void* ctx;
+ void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
if (res > 0)
@@ -65,14 +69,14 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-# define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
#else
-# define INIT_PREAD64
+#define INIT_PREAD64
#endif
#if SANITIZER_INTERCEPT_WRITE
INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
- void* ctx;
+ void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
if (fd >= 0)
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
@@ -81,142 +85,154 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-# define INIT_WRITE INTERCEPT_FUNCTION(write)
+#define INIT_WRITE INTERCEPT_FUNCTION(write)
#else
-# define INIT_WRITE
+#define INIT_WRITE
#endif
#if SANITIZER_INTERCEPT_PWRITE
-INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count) {
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
if (fd >= 0)
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
- SSIZE_T res = REAL(pwrite)(fd, ptr, count);
+ SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
if (res > 0)
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-# define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
+#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
#else
-# define INIT_PWRITE
+#define INIT_PWRITE
#endif
#if SANITIZER_INTERCEPT_PWRITE64
-INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count) {
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count);
+INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
+ OFF64_T offset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
if (fd >= 0)
COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
- SSIZE_T res = REAL(pwrite64)(fd, ptr, count);
+ SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
if (res > 0)
COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-# define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
#else
-# define INIT_PWRITE64
+#define INIT_PWRITE64
#endif
#if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option,
- unsigned long arg2, unsigned long arg3, // NOLINT
- unsigned long arg4, unsigned long arg5) { // NOLINT
- void* ctx;
+INTERCEPTOR(int, prctl, int option, unsigned long arg2,
+ unsigned long arg3, // NOLINT
+ unsigned long arg4, unsigned long arg5) { // NOLINT
+ void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
static const int PR_SET_NAME = 15;
int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
if (option == PR_SET_NAME) {
char buff[16];
- internal_strncpy(buff, (char*)arg2, 15);
+ internal_strncpy(buff, (char *)arg2, 15);
buff[15] = 0;
COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
}
return res;
}
-# define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
+#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
#else
-# define INIT_PRCTL
-#endif // SANITIZER_INTERCEPT_PRCTL
-
+#define INIT_PRCTL
+#endif // SANITIZER_INTERCEPT_PRCTL
#if SANITIZER_INTERCEPT_SCANF
#include "sanitizer_common_interceptors_scanf.inc"
-INTERCEPTOR(int, vscanf, const char *format, va_list ap) { // NOLINT
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, vscanf, format, ap);
- scanf_common(ctx, format, ap);
- int res = REAL(vscanf)(format, ap); // NOLINT
- return res;
-}
+#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
+ va_list aq; \
+ va_copy(aq, ap); \
+ int res = REAL(vname)(__VA_ARGS__); \
+ if (res > 0) \
+ scanf_common(ctx, res, allowGnuMalloc, format, aq); \
+ va_end(aq); \
+ return res; \
+ }
-INTERCEPTOR(int, vsscanf, const char *str, const char *format, // NOLINT
- va_list ap) {
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, vsscanf, str, format, ap);
- scanf_common(ctx, format, ap);
- int res = REAL(vsscanf)(str, format, ap); // NOLINT
- // FIXME: read of str
- return res;
-}
+INTERCEPTOR(int, vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vscanf, true, format, ap)
-INTERCEPTOR(int, vfscanf, void *stream, const char *format, // NOLINT
- va_list ap) {
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, vfscanf, stream, format, ap);
- scanf_common(ctx, format, ap);
- int res = REAL(vfscanf)(stream, format, ap); // NOLINT
- return res;
-}
+INTERCEPTOR(int, vsscanf, const char *str, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vsscanf, true, str, format, ap)
-INTERCEPTOR(int, scanf, const char *format, ...) { // NOLINT
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, scanf, format);
- va_list ap;
- va_start(ap, format);
- int res = vscanf(format, ap); // NOLINT
- va_end(ap);
- return res;
-}
+INTERCEPTOR(int, vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(vfscanf, true, stream, format, ap)
-INTERCEPTOR(int, fscanf, void* stream, const char *format, ...) { // NOLINT
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, fscanf, stream, format);
- va_list ap;
- va_start(ap, format);
- int res = vfscanf(stream, format, ap); // NOLINT
- va_end(ap);
- return res;
-}
+INTERCEPTOR(int, __isoc99_vscanf, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vscanf, false, format, ap)
-INTERCEPTOR(int, sscanf, const char *str, const char *format, ...) { // NOLINT
- void* ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, sscanf, str, format); // NOLINT
- va_list ap;
- va_start(ap, format);
- int res = vsscanf(str, format, ap); // NOLINT
- va_end(ap);
- return res;
-}
+INTERCEPTOR(int, __isoc99_vsscanf, const char *str, const char *format,
+ va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vsscanf, false, str, format, ap)
+
+INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
+VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
+
+#define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \
+ { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, name, __VA_ARGS__); \
+ va_list ap; \
+ va_start(ap, format); \
+ int res = vname(__VA_ARGS__, ap); \
+ va_end(ap); \
+ return res; \
+ }
+
+INTERCEPTOR(int, scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
+
+INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
+
+INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
+
+INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
+
+INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
+
+INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
+SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
-#define INIT_SCANF \
- INTERCEPT_FUNCTION(scanf); \
- INTERCEPT_FUNCTION(sscanf); /* NOLINT */ \
- INTERCEPT_FUNCTION(fscanf); \
- INTERCEPT_FUNCTION(vscanf); \
- INTERCEPT_FUNCTION(vsscanf); \
- INTERCEPT_FUNCTION(vfscanf)
+#define INIT_SCANF \
+ INTERCEPT_FUNCTION(scanf); \
+ INTERCEPT_FUNCTION(sscanf); \
+ INTERCEPT_FUNCTION(fscanf); \
+ INTERCEPT_FUNCTION(vscanf); \
+ INTERCEPT_FUNCTION(vsscanf); \
+ INTERCEPT_FUNCTION(vfscanf); \
+ INTERCEPT_FUNCTION(__isoc99_scanf); \
+ INTERCEPT_FUNCTION(__isoc99_sscanf); \
+ INTERCEPT_FUNCTION(__isoc99_fscanf); \
+ INTERCEPT_FUNCTION(__isoc99_vscanf); \
+ INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+ INTERCEPT_FUNCTION(__isoc99_vfscanf);
#else
#define INIT_SCANF
#endif
-#define SANITIZER_COMMON_INTERCEPTORS_INIT \
- INIT_READ; \
- INIT_PREAD; \
- INIT_PREAD64; \
- INIT_PRCTL; \
- INIT_WRITE; \
+#define SANITIZER_COMMON_INTERCEPTORS_INIT \
+ INIT_READ; \
+ INIT_PREAD; \
+ INIT_PREAD64; \
+ INIT_PRCTL; \
+ INIT_WRITE; \
+ INIT_PWRITE; \
+ INIT_PWRITE64; \
INIT_SCANF;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
index f7cab5f..5b76138 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_scanf.inc
@@ -6,87 +6,41 @@
//===----------------------------------------------------------------------===//
//
// Scanf implementation for use in *Sanitizer interceptors.
+// Follows http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html
+// with a few common GNU extensions.
//
//===----------------------------------------------------------------------===//
#include <stdarg.h>
-#ifdef _WIN32
-#define va_copy(dst, src) ((dst) = (src))
-#endif // _WIN32
-
-struct ScanfSpec {
- char c;
- unsigned size;
-};
-
-// One-letter specs.
-static const ScanfSpec scanf_specs[] = {
- {'p', sizeof(void *)},
- {'e', sizeof(float)},
- {'E', sizeof(float)},
- {'a', sizeof(float)},
- {'f', sizeof(float)},
- {'g', sizeof(float)},
- {'d', sizeof(int)},
- {'i', sizeof(int)},
- {'o', sizeof(int)},
- {'u', sizeof(int)},
- {'x', sizeof(int)},
- {'X', sizeof(int)},
- {'n', sizeof(int)},
- {'t', sizeof(PTRDIFF_T)},
- {'z', sizeof(SIZE_T)},
- {'j', sizeof(INTMAX_T)},
- {'h', sizeof(short)}
-};
-
-static const unsigned scanf_specs_cnt =
- sizeof(scanf_specs) / sizeof(scanf_specs[0]);
-
-// %ll?, %L?, %q? specs
-static const ScanfSpec scanf_llspecs[] = {
- {'e', sizeof(long double)},
- {'f', sizeof(long double)},
- {'g', sizeof(long double)},
- {'d', sizeof(long long)},
- {'i', sizeof(long long)},
- {'o', sizeof(long long)},
- {'u', sizeof(long long)},
- {'x', sizeof(long long)}
+struct ScanfDirective {
+ int argIdx; // argument index, or -1 of not specified ("%n$")
+ int fieldWidth;
+ bool suppressed; // suppress assignment ("*")
+ bool allocate; // allocate space ("m")
+ char lengthModifier[2];
+ char convSpecifier;
+ bool maybeGnuMalloc;
};
-static const unsigned scanf_llspecs_cnt =
- sizeof(scanf_llspecs) / sizeof(scanf_llspecs[0]);
-
-// %l? specs
-static const ScanfSpec scanf_lspecs[] = {
- {'e', sizeof(double)},
- {'f', sizeof(double)},
- {'g', sizeof(double)},
- {'d', sizeof(long)},
- {'i', sizeof(long)},
- {'o', sizeof(long)},
- {'u', sizeof(long)},
- {'x', sizeof(long)},
- {'X', sizeof(long)},
-};
-
-static const unsigned scanf_lspecs_cnt =
- sizeof(scanf_lspecs) / sizeof(scanf_lspecs[0]);
-
-static unsigned match_spec(const struct ScanfSpec *spec, unsigned n, char c) {
- for (unsigned i = 0; i < n; ++i)
- if (spec[i].c == c)
- return spec[i].size;
- return 0;
+static const char *parse_number(const char *p, int *out) {
+ *out = internal_atoll(p);
+ while (*p >= '0' && *p <= '9')
+ ++p;
+ return p;
}
-static void scanf_common(void *ctx, const char *format, va_list ap_const) {
- va_list aq;
- va_copy(aq, ap_const);
+static bool char_is_one_of(char c, const char *s) {
+ return !!internal_strchr(s, c);
+}
- const char *p = format;
- unsigned size;
+// Parse scanf format string. If a valid directive in encountered, it is
+// returned in dir. This function returns the pointer to the first
+// unprocessed character, or 0 in case of error.
+// In case of the end-of-string, a pointer to the closing \0 is returned.
+static const char *scanf_parse_next(const char *p, bool allowGnuMalloc,
+ ScanfDirective *dir) {
+ internal_memset(dir, 0, sizeof(*dir));
+ dir->argIdx = -1;
while (*p) {
if (*p != '%') {
@@ -94,51 +48,260 @@ static void scanf_common(void *ctx, const char *format, va_list ap_const) {
continue;
}
++p;
- if (*p == '*' || *p == '%' || *p == 0) {
+ // %%
+ if (*p == '%') {
++p;
continue;
}
- if (*p == '0' || (*p >= '1' && *p <= '9')) {
- size = internal_atoll(p);
- // +1 for the \0 at the end
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size + 1);
+ if (*p == '\0') {
+ return 0;
+ }
+ // %n$
+ if (*p >= '0' && *p <= '9') {
+ int number;
+ const char *q = parse_number(p, &number);
+ if (*q == '$') {
+ dir->argIdx = number;
+ p = q + 1;
+ }
+ // Otherwise, do not change p. This will be re-parsed later as the field
+ // width.
+ }
+ // *
+ if (*p == '*') {
+ dir->suppressed = true;
++p;
- continue;
}
-
- if (*p == 'L' || *p == 'q') {
+ // Field width.
+ if (*p >= '0' && *p <= '9') {
+ p = parse_number(p, &dir->fieldWidth);
+ if (dir->fieldWidth <= 0)
+ return 0;
+ }
+ // m
+ if (*p == 'm') {
+ dir->allocate = true;
++p;
- size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
- continue;
}
-
- if (*p == 'l') {
+ // Length modifier.
+ if (char_is_one_of(*p, "jztLq")) {
+ dir->lengthModifier[0] = *p;
+ ++p;
+ } else if (*p == 'h') {
+ dir->lengthModifier[0] = 'h';
+ ++p;
+ if (*p == 'h') {
+ dir->lengthModifier[1] = 'h';
+ ++p;
+ }
+ } else if (*p == 'l') {
+ dir->lengthModifier[0] = 'l';
++p;
if (*p == 'l') {
+ dir->lengthModifier[1] = 'l';
++p;
- size = match_spec(scanf_llspecs, scanf_llspecs_cnt, *p);
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
- continue;
- } else {
- size = match_spec(scanf_lspecs, scanf_lspecs_cnt, *p);
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
- continue;
}
}
+ // Conversion specifier.
+ dir->convSpecifier = *p++;
+ // Consume %[...] expression.
+ if (dir->convSpecifier == '[') {
+ if (*p == '^')
+ ++p;
+ if (*p == ']')
+ ++p;
+ while (*p && *p != ']')
+ ++p;
+ if (*p == 0)
+ return 0; // unexpected end of string
+ // Consume the closing ']'.
+ ++p;
+ }
+ // This is unfortunately ambiguous between old GNU extension
+ // of %as, %aS and %a[...] and newer POSIX %a followed by
+ // letters s, S or [.
+ if (allowGnuMalloc && dir->convSpecifier == 'a' &&
+ !dir->lengthModifier[0]) {
+ if (*p == 's' || *p == 'S') {
+ dir->maybeGnuMalloc = true;
+ ++p;
+ } else if (*p == '[') {
+ // Watch for %a[h-j%d], if % appears in the
+ // [...] range, then we need to give up, we don't know
+ // if scanf will parse it as POSIX %a [h-j %d ] or
+ // GNU allocation of string with range dh-j plus %.
+ const char *q = p + 1;
+ if (*q == '^')
+ ++q;
+ if (*q == ']')
+ ++q;
+ while (*q && *q != ']' && *q != '%')
+ ++q;
+ if (*q == 0 || *q == '%')
+ return 0;
+ p = q + 1; // Consume the closing ']'.
+ dir->maybeGnuMalloc = true;
+ }
+ }
+ break;
+ }
+ return p;
+}
- if (*p == 'h' && *(p + 1) == 'h') {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), sizeof(char));
- p += 2;
- continue;
+// Returns true if the character is an integer conversion specifier.
+static bool scanf_is_integer_conv(char c) {
+ return char_is_one_of(c, "diouxXn");
+}
+
+// Returns true if the character is an floating point conversion specifier.
+static bool scanf_is_float_conv(char c) {
+ return char_is_one_of(c, "aAeEfFgG");
+}
+
+// Returns string output character size for string-like conversions,
+// or 0 if the conversion is invalid.
+static int scanf_get_char_size(ScanfDirective *dir) {
+ if (char_is_one_of(dir->convSpecifier, "CS")) {
+ // wchar_t
+ return 0;
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cs[")) {
+ if (dir->lengthModifier[0] == 'l')
+ // wchar_t
+ return 0;
+ else if (dir->lengthModifier[0] == 0)
+ return sizeof(char);
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+enum ScanfStoreSize {
+ // Store size not known in advance; can be calculated as strlen() of the
+ // destination buffer.
+ SSS_STRLEN = -1,
+ // Invalid conversion specifier.
+ SSS_INVALID = 0
+};
+
+// Returns the store size of a scanf directive (if >0), or a value of
+// ScanfStoreSize.
+static int scanf_get_store_size(ScanfDirective *dir) {
+ if (dir->allocate) {
+ if (!char_is_one_of(dir->convSpecifier, "cCsS["))
+ return SSS_INVALID;
+ return sizeof(char *);
+ }
+
+ if (dir->maybeGnuMalloc) {
+ if (dir->convSpecifier != 'a' || dir->lengthModifier[0])
+ return SSS_INVALID;
+ // This is ambiguous, so check the smaller size of char * (if it is
+ // a GNU extension of %as, %aS or %a[...]) and float (if it is
+ // POSIX %a followed by s, S or [ letters).
+ return sizeof(char *) < sizeof(float) ? sizeof(char *) : sizeof(float);
+ }
+
+ if (scanf_is_integer_conv(dir->convSpecifier)) {
+ switch (dir->lengthModifier[0]) {
+ case 'h':
+ return dir->lengthModifier[1] == 'h' ? sizeof(char) : sizeof(short);
+ case 'l':
+ return dir->lengthModifier[1] == 'l' ? sizeof(long long) : sizeof(long);
+ case 'L':
+ return sizeof(long long);
+ case 'j':
+ return sizeof(INTMAX_T);
+ case 'z':
+ return sizeof(SIZE_T);
+ case 't':
+ return sizeof(PTRDIFF_T);
+ case 0:
+ return sizeof(int);
+ default:
+ return SSS_INVALID;
}
+ }
- size = match_spec(scanf_specs, scanf_specs_cnt, *p);
- if (size) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, va_arg(aq, void *), size);
- ++p;
+ if (scanf_is_float_conv(dir->convSpecifier)) {
+ switch (dir->lengthModifier[0]) {
+ case 'L':
+ case 'q':
+ return sizeof(long double);
+ case 'l':
+ return dir->lengthModifier[1] == 'l' ? sizeof(long double)
+ : sizeof(double);
+ case 0:
+ return sizeof(float);
+ default:
+ return SSS_INVALID;
+ }
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "sS[")) {
+ unsigned charSize = scanf_get_char_size(dir);
+ if (charSize == 0)
+ return SSS_INVALID;
+ if (dir->fieldWidth == 0)
+ return SSS_STRLEN;
+ return (dir->fieldWidth + 1) * charSize;
+ }
+
+ if (char_is_one_of(dir->convSpecifier, "cC")) {
+ unsigned charSize = scanf_get_char_size(dir);
+ if (charSize == 0)
+ return SSS_INVALID;
+ if (dir->fieldWidth == 0)
+ return charSize;
+ return dir->fieldWidth * charSize;
+ }
+
+ if (dir->convSpecifier == 'p') {
+ if (dir->lengthModifier[1] != 0)
+ return SSS_INVALID;
+ return sizeof(void *);
+ }
+
+ return SSS_INVALID;
+}
+
+// Common part of *scanf interceptors.
+// Process format string and va_list, and report all store ranges.
+// Stops when "consuming" n_inputs input items.
+static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
+ const char *format, va_list aq) {
+ CHECK_GT(n_inputs, 0);
+ const char *p = format;
+
+ while (*p && n_inputs) {
+ ScanfDirective dir;
+ p = scanf_parse_next(p, allowGnuMalloc, &dir);
+ if (!p)
+ break;
+ if (dir.convSpecifier == 0) {
+ // This can only happen at the end of the format string.
+ CHECK_EQ(*p, 0);
+ break;
+ }
+ // Here the directive is valid. Do what it says.
+ if (dir.argIdx != -1) {
+ // Unsupported.
+ break;
+ }
+ if (dir.suppressed)
continue;
+ int size = scanf_get_store_size(&dir);
+ if (size == SSS_INVALID)
+ break;
+ void *argp = va_arg(aq, void *);
+ if (dir.convSpecifier != 'n')
+ --n_inputs;
+ if (size == SSS_STRLEN) {
+ size = internal_strlen((const char *)argp) + 1;
}
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, argp, size);
}
- va_end(aq);
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 01f08f5..1a25b70 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -11,7 +11,85 @@
#ifndef SANITIZER_DEFS_H
#define SANITIZER_DEFS_H
-#include "sanitizer/common_interface_defs.h"
+#if defined(_WIN32)
+// FIXME find out what we need on Windows. __declspec(dllexport) ?
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#elif defined(SANITIZER_GO)
+# define SANITIZER_INTERFACE_ATTRIBUTE
+# define SANITIZER_WEAK_ATTRIBUTE
+#else
+# define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
+# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
+#endif
+
+#ifdef __linux__
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
+#else
+# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
+#endif
+
+// __has_feature
+#if !defined(__has_feature)
+# define __has_feature(x) 0
+#endif
+
+// For portability reasons we do not include stddef.h, stdint.h or any other
+// system header, but we do need some basic types that are not defined
+// in a portable way by the language itself.
+namespace __sanitizer {
+
+#if defined(_WIN64)
+// 64-bit Windows uses LLP64 data model.
+typedef unsigned long long uptr; // NOLINT
+typedef signed long long sptr; // NOLINT
+#else
+typedef unsigned long uptr; // NOLINT
+typedef signed long sptr; // NOLINT
+#endif // defined(_WIN64)
+#if defined(__x86_64__)
+// Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
+// 64-bit pointer to unwind stack frame.
+typedef unsigned long long uhwptr; // NOLINT
+#else
+typedef uptr uhwptr; // NOLINT
+#endif
+typedef unsigned char u8;
+typedef unsigned short u16; // NOLINT
+typedef unsigned int u32;
+typedef unsigned long long u64; // NOLINT
+typedef signed char s8;
+typedef signed short s16; // NOLINT
+typedef signed int s32;
+typedef signed long long s64; // NOLINT
+typedef int fd_t;
+
+} // namespace __sanitizer
+
+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;
+
+ // Notify the tools that the sandbox is going to be turned on. The reserved
+ // parameter will be used in the future to hold a structure with functions
+ // that the tools may call to bypass the sandbox.
+ void __sanitizer_sandbox_on_notify(void *reserved)
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ void __sanitizer_report_error_summary(const char *error_summary)
+ SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE;
+} // extern "C"
+
+
using namespace __sanitizer; // NOLINT
// ----------- ATTENTION -------------
// This header should NOT include any other headers to avoid portability issues.
diff --git a/libsanitizer/sanitizer_common/sanitizer_lfstack.h b/libsanitizer/sanitizer_common/sanitizer_lfstack.h
index 63fbf06..8033b9a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_lfstack.h
+++ b/libsanitizer/sanitizer_common/sanitizer_lfstack.h
@@ -66,6 +66,6 @@ struct LFStack {
atomic_uint64_t head_;
};
-}
+} // namespace __sanitizer
#endif // #ifndef SANITIZER_LFSTACK_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.cc b/libsanitizer/sanitizer_common/sanitizer_libc.cc
index b02cbd4a..c57128a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.cc
@@ -204,7 +204,7 @@ s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) {
}
bool mem_is_zero(const char *beg, uptr size) {
- CHECK_LE(size, 1UL << FIRST_32_SECOND_64(30, 40)); // Sanity check.
+ CHECK_LE(size, 1ULL << FIRST_32_SECOND_64(30, 40)); // Sanity check.
const char *end = beg + size;
uptr *aligned_beg = (uptr *)RoundUpTo((uptr)beg, sizeof(uptr));
uptr *aligned_end = (uptr *)RoundDownTo((uptr)end, sizeof(uptr));
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
index f193017..7a97744 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
@@ -9,14 +9,13 @@
// run-time libraries.
// These tools can not use some of the libc functions directly because those
// functions are intercepted. Instead, we implement a tiny subset of libc here.
-// NOTE: This file may be included into user code.
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LIBC_H
#define SANITIZER_LIBC_H
// ----------- ATTENTION -------------
// This header should NOT include any other headers from sanitizer runtime.
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
namespace __sanitizer {
@@ -56,17 +55,24 @@ void *internal_mmap(void *addr, uptr length, int prot, int flags,
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);
+
+// Use __sanitizer::OpenFile() instead.
+fd_t internal_open(const char *filename, int flags);
+fd_t internal_open(const char *filename, int flags, u32 mode);
+
uptr internal_read(fd_t fd, void *buf, uptr count);
uptr internal_write(fd_t fd, const void *buf, uptr count);
uptr internal_filesize(fd_t fd); // -1 on error.
+int internal_stat(const char *path, void *buf);
+int internal_lstat(const char *path, void *buf);
+int internal_fstat(fd_t fd, void *buf);
+
int internal_dup2(int oldfd, int newfd);
uptr internal_readlink(const char *path, char *buf, uptr bufsize);
int internal_snprintf(char *buffer, uptr length, const char *format, ...);
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc
index dc2148f..3d3aa0b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc
@@ -28,11 +28,14 @@
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/prctl.h>
#include <unistd.h>
#include <unwind.h>
#include <errno.h>
-#include <sys/prctl.h>
-#include <linux/futex.h>
+
+// <linux/futex.h> is broken on some linux distributions.
+const int FUTEX_WAIT = 0;
+const int FUTEX_WAKE = 1;
// Are we using 32-bit or 64-bit syscalls?
// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
@@ -63,8 +66,16 @@ int internal_close(fd_t fd) {
return syscall(__NR_close, fd);
}
-fd_t internal_open(const char *filename, bool write) {
- return syscall(__NR_open, filename,
+fd_t internal_open(const char *filename, int flags) {
+ return syscall(__NR_open, filename, flags);
+}
+
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+ return syscall(__NR_open, filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+ return internal_open(filename,
write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
}
@@ -80,16 +91,38 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return res;
}
+int internal_stat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return syscall(__NR_stat, path, buf);
+#else
+ return syscall(__NR_stat64, path, buf);
+#endif
+}
+
+int internal_lstat(const char *path, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return syscall(__NR_lstat, path, buf);
+#else
+ return syscall(__NR_lstat64, path, buf);
+#endif
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
+ return syscall(__NR_fstat, fd, buf);
+#else
+ return syscall(__NR_fstat64, fd, buf);
+#endif
+}
+
uptr internal_filesize(fd_t fd) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
struct stat st;
- if (syscall(__NR_fstat, fd, &st))
- return -1;
#else
struct stat64 st;
- if (syscall(__NR_fstat64, fd, &st))
- return -1;
#endif
+ if (internal_fstat(fd, &st))
+ return -1;
return (uptr)st.st_size;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc
index 76bf867..309b5a9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc
@@ -11,6 +11,12 @@
//===----------------------------------------------------------------------===//
#ifdef __APPLE__
+// Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
+// the clients will most certainly use 64-bit ones as well.
+#ifndef _DARWIN_USE_64_BIT_INODE
+#define _DARWIN_USE_64_BIT_INODE 1
+#endif
+#include <stdio.h>
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
@@ -46,9 +52,17 @@ int internal_close(fd_t fd) {
return close(fd);
}
-fd_t internal_open(const char *filename, bool write) {
- return open(filename,
- write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
+fd_t internal_open(const char *filename, int flags) {
+ return open(filename, flags);
+}
+
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+ return open(filename, flags, mode);
+}
+
+fd_t OpenFile(const char *filename, bool write) {
+ return internal_open(filename,
+ write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
}
uptr internal_read(fd_t fd, void *buf, uptr count) {
@@ -59,9 +73,21 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return write(fd, buf, count);
}
+int internal_stat(const char *path, void *buf) {
+ return stat(path, (struct stat *)buf);
+}
+
+int internal_lstat(const char *path, void *buf) {
+ return lstat(path, (struct stat *)buf);
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+ return fstat(fd, (struct stat *)buf);
+}
+
uptr internal_filesize(fd_t fd) {
struct stat st;
- if (fstat(fd, &st))
+ if (internal_fstat(fd, &st))
return -1;
return (uptr)st.st_size;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 0ca9444..2c60253 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -33,4 +33,4 @@
# define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
# define SANITIZER_INTERCEPT_PRCTL SI_LINUX_NOT_ANDROID
-# define SANITIZER_INTERCEPT_SCANF 0
+# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc
index 17287cd..48c5eba 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc
@@ -56,12 +56,12 @@ void *MmapOrDie(uptr size, const char *mem_type) {
if (recursion_count) {
// The Report() and CHECK calls below may call mmap recursively and fail.
// If we went into recursion, just die.
- RawWrite("AddressSanitizer is unable to mmap\n");
+ RawWrite("ERROR: Failed to mmap\n");
Die();
}
recursion_count++;
- Report("ERROR: Failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
- size, size, mem_type, strerror(errno));
+ Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %s\n",
+ SanitizerToolName, size, size, mem_type, strerror(errno));
DumpProcessMap();
CHECK("unable to mmap" && 0);
}
@@ -72,8 +72,8 @@ void UnmapOrDie(void *addr, uptr size) {
if (!addr || !size) return;
int res = internal_munmap(addr, size);
if (res != 0) {
- Report("ERROR: Failed to deallocate 0x%zx (%zd) bytes at address %p\n",
- size, size, addr);
+ Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+ SanitizerToolName, size, size, addr);
CHECK("unable to unmap" && 0);
}
}
@@ -86,8 +86,9 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
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);
+ Report("ERROR: "
+ "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+ SanitizerToolName, size, size, fixed_addr, errno);
return p;
}
@@ -99,8 +100,9 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-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);
+ Report("ERROR:"
+ " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
+ SanitizerToolName, size, size, fixed_addr, errno);
CHECK("unable to mmap" && 0);
}
return p;
@@ -118,7 +120,7 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) {
}
void *MapFileToMemory(const char *file_name, uptr *buff_size) {
- fd_t fd = internal_open(file_name, false);
+ fd_t fd = OpenFile(file_name, false);
CHECK_NE(fd, kInvalidFd);
uptr fsize = internal_filesize(fd);
CHECK_NE(fsize, (uptr)-1);
@@ -187,7 +189,7 @@ void SetStackSizeLimitInBytes(uptr limit) {
rlim.rlim_cur = limit;
rlim.rlim_max = limit;
if (setrlimit(RLIMIT_STACK, &rlim)) {
- Report("setrlimit() failed %d\n", errno);
+ Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
Die();
}
CHECK(!StackSizeIsUnlimited());
diff --git a/libsanitizer/sanitizer_common/sanitizer_quarantine.h b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
index 042fba7..f3ad91a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_quarantine.h
+++ b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
@@ -157,7 +157,7 @@ class QuarantineCache {
atomic_store(&size_, Size() + add, memory_order_relaxed);
}
- QuarantineBatch *NOINLINE AllocBatch(Callback cb) {
+ NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
b->count = 0;
b->size = 0;
@@ -165,6 +165,6 @@ class QuarantineCache {
return b;
}
};
-}
+} // namespace __sanitizer
#endif // #ifndef SANITIZER_QUARANTINE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
index 1e917eb..bf73cf1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
@@ -11,7 +11,7 @@
#ifndef SANITIZER_STACKDEPOT_H
#define SANITIZER_STACKDEPOT_H
-#include "sanitizer/common_interface_defs.h"
+#include "sanitizer_internal_defs.h"
namespace __sanitizer {
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
index 59af1c3..259da00 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
@@ -15,8 +15,9 @@
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-static const char *StripPathPrefix(const char *filepath,
- const char *strip_file_prefix) {
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_file_prefix) {
+ if (filepath == 0) return 0;
if (filepath == internal_strstr(filepath, strip_file_prefix))
return filepath + internal_strlen(strip_file_prefix);
return filepath;
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index c939644..fd0c467 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -55,6 +55,10 @@ struct StackTrace {
u32 *compressed, uptr size);
};
+
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_file_prefix);
+
} // namespace __sanitizer
// Use this macro if you want to print stack trace with the caller
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
index f62acf3..2c9cb2b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
@@ -174,6 +174,53 @@ class ExternalSymbolizer {
static LowLevelAllocator symbolizer_allocator; // Linker initialized.
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_code(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+bool __sanitizer_symbolize_data(const char *ModuleName, u64 ModuleOffset,
+ char *Buffer, int MaxLength);
+} // extern "C"
+
+class InternalSymbolizer {
+ public:
+ typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
+ static InternalSymbolizer *get() {
+ if (__sanitizer_symbolize_code != 0 &&
+ __sanitizer_symbolize_data != 0) {
+ void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
+ return new(mem) InternalSymbolizer();
+ }
+ return 0;
+ }
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ SanitizerSymbolizeFn symbolize_fn = is_data ? __sanitizer_symbolize_data
+ : __sanitizer_symbolize_code;
+ if (symbolize_fn(module_name, module_offset, buffer_, kBufferSize))
+ return buffer_;
+ return 0;
+ }
+
+ private:
+ InternalSymbolizer() { }
+
+ static const int kBufferSize = 16 * 1024;
+ char buffer_[kBufferSize];
+};
+#else // SANITIZER_SUPPORTS_WEAK_HOOKS
+
+class InternalSymbolizer {
+ public:
+ static InternalSymbolizer *get() { return 0; }
+ char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ return 0;
+ }
+};
+
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+
class Symbolizer {
public:
uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
@@ -266,8 +313,23 @@ class Symbolizer {
return true;
}
+ bool IsSymbolizerAvailable() {
+ if (internal_symbolizer_ == 0)
+ internal_symbolizer_ = InternalSymbolizer::get();
+ return internal_symbolizer_ || external_symbolizer_;
+ }
+
private:
char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ // First, try to use internal symbolizer.
+ if (internal_symbolizer_ == 0) {
+ internal_symbolizer_ = InternalSymbolizer::get();
+ }
+ if (internal_symbolizer_) {
+ return internal_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
+ }
+ // Otherwise, fall back to external symbolizer.
if (external_symbolizer_ == 0) {
ReportExternalSymbolizerError(
"WARNING: Trying to symbolize code, but external "
@@ -322,6 +384,7 @@ class Symbolizer {
uptr n_modules_;
ExternalSymbolizer *external_symbolizer_; // Leaked.
+ InternalSymbolizer *internal_symbolizer_; // Leaked.
};
static Symbolizer symbolizer; // Linker initialized.
@@ -338,4 +401,8 @@ bool InitializeExternalSymbolizer(const char *path_to_symbolizer) {
return symbolizer.InitializeExternalSymbolizer(path_to_symbolizer);
}
+bool IsSymbolizerAvailable() {
+ return symbolizer.IsSymbolizerAvailable();
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index b88fa3f..751806e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -67,6 +67,8 @@ struct DataInfo {
uptr SymbolizeCode(uptr address, AddressInfo *frames, uptr max_frames);
bool SymbolizeData(uptr address, DataInfo *info);
+bool IsSymbolizerAvailable();
+
// Attempts to demangle the provided C++ mangled name.
const char *Demangle(const char *Name);
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc
index 242b442..3d5cde1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cc
@@ -95,6 +95,11 @@ void *Mprotect(uptr fixed_addr, uptr size) {
MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
}
+void FlushUnneededShadowMemory(uptr addr, uptr size) {
+ // This is almost useless on 32-bits.
+ // FIXME: add madvice-analog when we move to 64-bits.
+}
+
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
// FIXME: shall we do anything here on Windows?
return true;
@@ -189,7 +194,15 @@ int internal_isatty(fd_t fd) {
return _isatty(fd);
}
-fd_t internal_open(const char *filename, bool write) {
+fd_t internal_open(const char *filename, int flags) {
+ UNIMPLEMENTED();
+}
+
+fd_t internal_open(const char *filename, int flags, u32 mode) {
+ UNIMPLEMENTED();
+}
+
+fd_t OpenFile(const char *filename, bool write) {
UNIMPLEMENTED();
}
@@ -209,6 +222,18 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) {
return ret;
}
+int internal_stat(const char *path, void *buf) {
+ UNIMPLEMENTED();
+}
+
+int internal_lstat(const char *path, void *buf) {
+ UNIMPLEMENTED();
+}
+
+int internal_fstat(fd_t fd, void *buf) {
+ UNIMPLEMENTED();
+}
+
uptr internal_filesize(fd_t fd) {
UNIMPLEMENTED();
}
@@ -227,10 +252,8 @@ int internal_sched_yield() {
}
// ---------------------- BlockingMutex ---------------- {{{1
-enum LockState {
- LOCK_UNINITIALIZED = 0,
- LOCK_READY = -1,
-};
+const uptr LOCK_UNINITIALIZED = 0;
+const uptr LOCK_READY = (uptr)-1;
BlockingMutex::BlockingMutex(LinkerInitialized li) {
// FIXME: see comments in BlockingMutex::Lock() for the details.
@@ -252,12 +275,12 @@ void BlockingMutex::Lock() {
// locks while we're starting in one thread to avoid double-init races.
}
EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- CHECK(owner_ == LOCK_READY);
+ CHECK_EQ(owner_, LOCK_READY);
owner_ = GetThreadSelf();
}
void BlockingMutex::Unlock() {
- CHECK(owner_ == GetThreadSelf());
+ CHECK_EQ(owner_, GetThreadSelf());
owner_ = LOCK_READY;
LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
}
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index 6683a4e..b2937a4 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -26,16 +26,19 @@ namespace __tsan {
const bool kGoMode = true;
const bool kCppMode = false;
const char *const kTsanOptionsEnv = "GORACE";
+// Go linker does not support weak symbols.
+#define CPP_WEAK
#else
const bool kGoMode = false;
const bool kCppMode = true;
const char *const kTsanOptionsEnv = "TSAN_OPTIONS";
+#define CPP_WEAK WEAK
#endif
const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
-const int kClkBits = 43;
+const int kClkBits = 42;
#ifndef TSAN_GO
const int kShadowStackSize = 4 * 1024;
const int kTraceStackSize = 256;
diff --git a/libsanitizer/tsan/tsan_fd.cc b/libsanitizer/tsan/tsan_fd.cc
index f640c4f8..a75d9bd 100644
--- a/libsanitizer/tsan/tsan_fd.cc
+++ b/libsanitizer/tsan/tsan_fd.cc
@@ -148,7 +148,7 @@ void FdAcquire(ThreadState *thr, uptr pc, int fd) {
FdDesc *d = fddesc(thr, pc, fd);
FdSync *s = d->sync;
DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
- MemoryRead8Byte(thr, pc, (uptr)d);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
if (s)
Acquire(thr, pc, (uptr)s);
}
@@ -159,20 +159,20 @@ void FdRelease(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
if (s)
Release(thr, pc, (uptr)s);
- MemoryRead8Byte(thr, pc, (uptr)d);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
}
void FdAccess(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
FdDesc *d = fddesc(thr, pc, fd);
- MemoryRead8Byte(thr, pc, (uptr)d);
+ MemoryRead(thr, pc, (uptr)d, kSizeLog8);
}
void FdClose(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
FdDesc *d = fddesc(thr, pc, fd);
// To catch races between fd usage and close.
- MemoryWrite8Byte(thr, pc, (uptr)d);
+ MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
// We need to clear it, because if we do not intercept any call out there
// that creates fd, we will hit false postives.
MemoryResetRange(thr, pc, (uptr)d, 8);
@@ -191,7 +191,7 @@ void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
// Ignore the case when user dups not yet connected socket.
FdDesc *od = fddesc(thr, pc, oldfd);
- MemoryRead8Byte(thr, pc, (uptr)od);
+ MemoryRead(thr, pc, (uptr)od, kSizeLog8);
FdClose(thr, pc, newfd);
init(thr, pc, newfd, ref(od->sync));
}
diff --git a/libsanitizer/tsan/tsan_flags.cc b/libsanitizer/tsan/tsan_flags.cc
index 630bd75..ae748a1 100644
--- a/libsanitizer/tsan/tsan_flags.cc
+++ b/libsanitizer/tsan/tsan_flags.cc
@@ -43,6 +43,7 @@ void InitializeFlags(Flags *f, const char *env) {
f->report_thread_leaks = true;
f->report_destroy_locked = true;
f->report_signal_unsafe = true;
+ f->report_atomic_races = true;
f->force_seq_cst_atomics = false;
f->strip_path_prefix = "";
f->suppressions = "";
@@ -70,6 +71,7 @@ void InitializeFlags(Flags *f, const char *env) {
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");
+ ParseFlag(env, &f->report_atomic_races, "report_atomic_races");
ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
ParseFlag(env, &f->strip_path_prefix, "strip_path_prefix");
ParseFlag(env, &f->suppressions, "suppressions");
diff --git a/libsanitizer/tsan/tsan_flags.h b/libsanitizer/tsan/tsan_flags.h
index ed27363..480b415 100644
--- a/libsanitizer/tsan/tsan_flags.h
+++ b/libsanitizer/tsan/tsan_flags.h
@@ -41,6 +41,8 @@ struct Flags {
// Report violations of async signal-safety
// (e.g. malloc() call from a signal handler).
bool report_signal_unsafe;
+ // Report races between atomic and plain memory accesses.
+ bool report_atomic_races;
// If set, all atomics are effectively sequentially consistent (seq_cst),
// regardless of what user actually specified.
bool force_seq_cst_atomics;
@@ -84,6 +86,6 @@ struct Flags {
Flags *flags();
void InitializeFlags(Flags *flags, const char *env);
-}
+} // namespace __tsan
#endif // TSAN_FLAGS_H
diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc
index d8f66de..8a54511 100644
--- a/libsanitizer/tsan/tsan_interceptors.cc
+++ b/libsanitizer/tsan/tsan_interceptors.cc
@@ -51,9 +51,12 @@ extern "C" int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
extern "C" int sigfillset(sigset_t *set);
extern "C" void *pthread_self();
extern "C" void _exit(int status);
-extern "C" int __cxa_atexit(void (*func)(void *arg), void *arg, void *dso);
extern "C" int *__errno_location();
extern "C" int fileno_unlocked(void *stream);
+extern "C" void *__libc_malloc(uptr size);
+extern "C" void *__libc_calloc(uptr size, uptr n);
+extern "C" void *__libc_realloc(void *ptr, uptr size);
+extern "C" void __libc_free(void *ptr);
const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
const int kPthreadAttrSize = 56;
@@ -122,7 +125,7 @@ struct SignalContext {
int pending_signal_count;
SignalDesc pending_signals[kSigCount];
};
-}
+} // namespace __tsan
static SignalContext *SigCtx(ThreadState *thr) {
SignalContext *ctx = (SignalContext*)thr->signal_ctx;
@@ -238,12 +241,15 @@ class AtExitContext {
typedef void(*atexit_t)();
- int atexit(ThreadState *thr, uptr pc, atexit_t f) {
+ int atexit(ThreadState *thr, uptr pc, bool is_on_exit,
+ atexit_t f, void *arg) {
Lock l(&mtx_);
if (pos_ == kMaxAtExit)
return 1;
Release(thr, pc, (uptr)this);
stack_[pos_] = f;
+ args_[pos_] = arg;
+ is_on_exits_[pos_] = is_on_exit;
pos_++;
return 0;
}
@@ -252,11 +258,15 @@ class AtExitContext {
CHECK_EQ(thr->in_rtl, 0);
for (;;) {
atexit_t f = 0;
+ void *arg = 0;
+ bool is_on_exit = false;
{
Lock l(&mtx_);
if (pos_) {
pos_--;
f = stack_[pos_];
+ arg = args_[pos_];
+ is_on_exit = is_on_exits_[pos_];
ScopedInRtl in_rtl;
Acquire(thr, pc, (uptr)this);
}
@@ -265,7 +275,10 @@ class AtExitContext {
break;
DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
CHECK_EQ(thr->in_rtl, 0);
- f();
+ if (is_on_exit)
+ ((void(*)(int status, void *arg))f)(0, arg);
+ else
+ ((void(*)(void *arg, void *dso))f)(arg, 0);
}
}
@@ -273,6 +286,8 @@ class AtExitContext {
static const int kMaxAtExit = 128;
Mutex mtx_;
atexit_t stack_[kMaxAtExit];
+ void *args_[kMaxAtExit];
+ bool is_on_exits_[kMaxAtExit];
int pos_;
};
@@ -282,18 +297,32 @@ static void finalize(void *arg) {
ThreadState * thr = cur_thread();
uptr pc = 0;
atexit_ctx->exit(thr, pc);
- {
- ScopedInRtl in_rtl;
- DestroyAndFree(atexit_ctx);
- }
int status = Finalize(cur_thread());
if (status)
_exit(status);
}
TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
SCOPED_TSAN_INTERCEPTOR(atexit, f);
- return atexit_ctx->atexit(thr, pc, f);
+ return atexit_ctx->atexit(thr, pc, false, (void(*)())f, 0);
+}
+
+TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
+ SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
+ return atexit_ctx->atexit(thr, pc, true, (void(*)())f, arg);
+}
+
+TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
+ if (cur_thread()->in_symbolizer)
+ return 0;
+ SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
+ if (dso)
+ return REAL(__cxa_atexit)(f, arg, dso);
+ return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
}
TSAN_INTERCEPTOR(void, longjmp, void *env, int val) {
@@ -309,6 +338,8 @@ TSAN_INTERCEPTOR(void, siglongjmp, void *env, int val) {
}
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_malloc(size);
void *p = 0;
{
SCOPED_INTERCEPTOR_RAW(malloc, size);
@@ -324,6 +355,9 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
}
TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_calloc(size, n);
+ if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return 0;
void *p = 0;
{
SCOPED_INTERCEPTOR_RAW(calloc, size, n);
@@ -335,6 +369,8 @@ TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
}
TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
+ if (cur_thread()->in_symbolizer)
+ return __libc_realloc(p, size);
if (p)
invoke_free_hook(p);
{
@@ -348,6 +384,8 @@ TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
TSAN_INTERCEPTOR(void, free, void *p) {
if (p == 0)
return;
+ if (cur_thread()->in_symbolizer)
+ return __libc_free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(free, p);
user_free(thr, pc, p);
@@ -356,12 +394,16 @@ TSAN_INTERCEPTOR(void, free, void *p) {
TSAN_INTERCEPTOR(void, cfree, void *p) {
if (p == 0)
return;
+ if (cur_thread()->in_symbolizer)
+ return __libc_free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(cfree, p);
user_free(thr, pc, p);
}
#define OPERATOR_NEW_BODY(mangled_name) \
+ if (cur_thread()->in_symbolizer) \
+ return __libc_malloc(size); \
void *p = 0; \
{ \
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
@@ -385,6 +427,8 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
#define OPERATOR_DELETE_BODY(mangled_name) \
if (ptr == 0) return; \
+ if (cur_thread()->in_symbolizer) \
+ return __libc_free(ptr); \
invoke_free_hook(ptr); \
SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
user_free(thr, pc, ptr);
@@ -549,6 +593,8 @@ TSAN_INTERCEPTOR(void*, mmap, void *addr, long_t sz, int prot,
return MAP_FAILED;
void *res = REAL(mmap)(addr, sz, prot, flags, fd, off);
if (res != MAP_FAILED) {
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
MemoryResetRange(thr, pc, (uptr)res, sz);
}
return res;
@@ -561,6 +607,8 @@ TSAN_INTERCEPTOR(void*, mmap64, void *addr, long_t sz, int prot,
return MAP_FAILED;
void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off);
if (res != MAP_FAILED) {
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
MemoryResetRange(thr, pc, (uptr)res, sz);
}
return res;
@@ -958,14 +1006,14 @@ TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
- MemoryWrite1Byte(thr, pc, (uptr)b);
+ MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
int res = REAL(pthread_barrier_init)(b, a, count);
return res;
}
TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b);
- MemoryWrite1Byte(thr, pc, (uptr)b);
+ MemoryWrite(thr, pc, (uptr)b, kSizeLog1);
int res = REAL(pthread_barrier_destroy)(b);
return res;
}
@@ -973,9 +1021,9 @@ TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b);
Release(thr, pc, (uptr)b);
- MemoryRead1Byte(thr, pc, (uptr)b);
+ MemoryRead(thr, pc, (uptr)b, kSizeLog1);
int res = REAL(pthread_barrier_wait)(b);
- MemoryRead1Byte(thr, pc, (uptr)b);
+ MemoryRead(thr, pc, (uptr)b, kSizeLog1);
if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) {
Acquire(thr, pc, (uptr)b);
}
@@ -1062,6 +1110,74 @@ TSAN_INTERCEPTOR(int, sem_getvalue, void *s, int *sval) {
return res;
}
+TSAN_INTERCEPTOR(int, __xstat, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat, version, path, buf);
+ return REAL(__xstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat, 0, path, buf);
+ return REAL(__xstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __xstat64, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat64, version, path, buf);
+ return REAL(__xstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, stat64, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__xstat64, 0, path, buf);
+ return REAL(__xstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat, version, path, buf);
+ return REAL(__lxstat)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat, 0, path, buf);
+ return REAL(__lxstat)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat64, version, path, buf);
+ return REAL(__lxstat64)(version, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, lstat64, const char *path, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__lxstat64, 0, path, buf);
+ return REAL(__lxstat64)(0, path, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat)(0, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat64)(version, fd, buf);
+}
+
+TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
+ SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
+ if (fd > 0)
+ FdAccess(thr, pc, fd);
+ return REAL(__fxstat64)(0, fd, buf);
+}
+
TSAN_INTERCEPTOR(int, open, const char *name, int flags, int mode) {
SCOPED_TSAN_INTERCEPTOR(open, name, flags, mode);
int fd = REAL(open)(name, flags, mode);
@@ -1177,6 +1293,22 @@ TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) {
return res;
}
+TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) {
+ SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen);
+ int res = REAL(bind)(fd, addr, addrlen);
+ if (fd > 0 && res == 0)
+ FdAccess(thr, pc, fd);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
+ SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog);
+ int res = REAL(listen)(fd, backlog);
+ if (fd > 0 && res == 0)
+ FdAccess(thr, pc, fd);
+ return res;
+}
+
TSAN_INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
SCOPED_TSAN_INTERCEPTOR(accept, fd, addr, addrlen);
int fd2 = REAL(accept)(fd, addr, addrlen);
@@ -1223,6 +1355,18 @@ TSAN_INTERCEPTOR(int, __close, int fd) {
return REAL(__close)(fd);
}
+// glibc guts
+TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
+ SCOPED_TSAN_INTERCEPTOR(__res_iclose, state, free_addr);
+ int fds[64];
+ int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds));
+ for (int i = 0; i < cnt; i++) {
+ if (fds[i] > 0)
+ FdClose(thr, pc, fds[i]);
+ }
+ REAL(__res_iclose)(state, free_addr);
+}
+
TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
int res = REAL(pipe)(pipefd);
@@ -1765,6 +1909,18 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(sem_post);
TSAN_INTERCEPT(sem_getvalue);
+ TSAN_INTERCEPT(stat);
+ TSAN_INTERCEPT(__xstat);
+ TSAN_INTERCEPT(stat64);
+ TSAN_INTERCEPT(__xstat64);
+ TSAN_INTERCEPT(lstat);
+ TSAN_INTERCEPT(__lxstat);
+ TSAN_INTERCEPT(lstat64);
+ TSAN_INTERCEPT(__lxstat64);
+ TSAN_INTERCEPT(fstat);
+ TSAN_INTERCEPT(__fxstat);
+ TSAN_INTERCEPT(fstat64);
+ TSAN_INTERCEPT(__fxstat64);
TSAN_INTERCEPT(open);
TSAN_INTERCEPT(open64);
TSAN_INTERCEPT(creat);
@@ -1779,11 +1935,15 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(socket);
TSAN_INTERCEPT(socketpair);
TSAN_INTERCEPT(connect);
+ TSAN_INTERCEPT(bind);
+ TSAN_INTERCEPT(listen);
TSAN_INTERCEPT(accept);
TSAN_INTERCEPT(accept4);
TSAN_INTERCEPT(epoll_create);
TSAN_INTERCEPT(epoll_create1);
TSAN_INTERCEPT(close);
+ TSAN_INTERCEPT(__close);
+ TSAN_INTERCEPT(__res_iclose);
TSAN_INTERCEPT(pipe);
TSAN_INTERCEPT(pipe2);
@@ -1826,6 +1986,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(munlockall);
TSAN_INTERCEPT(fork);
+ TSAN_INTERCEPT(on_exit);
+ TSAN_INTERCEPT(__cxa_atexit);
// Need to setup it, because interceptors check that the function is resolved.
// But atexit is emitted directly into the module, so can't be resolved.
@@ -1833,7 +1995,7 @@ void InitializeInterceptors() {
atexit_ctx = new(internal_alloc(MBlockAtExit, sizeof(AtExitContext)))
AtExitContext();
- if (__cxa_atexit(&finalize, 0, 0)) {
+ if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
Printf("ThreadSanitizer: failed to setup atexit callback\n");
Die();
}
diff --git a/libsanitizer/tsan/tsan_interface.cc b/libsanitizer/tsan/tsan_interface.cc
index 08a5165..992e3834 100644
--- a/libsanitizer/tsan/tsan_interface.cc
+++ b/libsanitizer/tsan/tsan_interface.cc
@@ -22,13 +22,13 @@ void __tsan_init() {
}
void __tsan_read16(void *addr) {
- MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr);
- MemoryRead8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
}
void __tsan_write16(void *addr) {
- MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr);
- MemoryWrite8Byte(cur_thread(), CALLERPC, (uptr)addr + 8);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
}
void __tsan_acquire(void *addr) {
diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
index 8f265ca..2cfd768 100644
--- a/libsanitizer/tsan/tsan_interface.h
+++ b/libsanitizer/tsan/tsan_interface.h
@@ -14,7 +14,7 @@
#ifndef TSAN_INTERFACE_H
#define TSAN_INTERFACE_H
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.
diff --git a/libsanitizer/tsan/tsan_interface_ann.h b/libsanitizer/tsan/tsan_interface_ann.h
index b10264c..b650032 100644
--- a/libsanitizer/tsan/tsan_interface_ann.h
+++ b/libsanitizer/tsan/tsan_interface_ann.h
@@ -12,7 +12,7 @@
#ifndef TSAN_INTERFACE_ANN_H
#define TSAN_INTERFACE_ANN_H
-#include <sanitizer/common_interface_defs.h>
+#include <sanitizer_common/sanitizer_internal_defs.h>
// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.
diff --git a/libsanitizer/tsan/tsan_interface_atomic.cc b/libsanitizer/tsan/tsan_interface_atomic.cc
index 770f8bd..2c8b2ab 100644
--- a/libsanitizer/tsan/tsan_interface_atomic.cc
+++ b/libsanitizer/tsan/tsan_interface_atomic.cc
@@ -18,25 +18,42 @@
// http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
#include "tsan_interface_atomic.h"
#include "tsan_flags.h"
#include "tsan_rtl.h"
using namespace __tsan; // NOLINT
+#define SCOPED_ATOMIC(func, ...) \
+ const uptr callpc = (uptr)__builtin_return_address(0); \
+ uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
+ pc = __sanitizer::StackTrace::GetPreviousInstructionPc(pc); \
+ mo = ConvertOrder(mo); \
+ mo = flags()->force_seq_cst_atomics ? (morder)mo_seq_cst : mo; \
+ ThreadState *const thr = cur_thread(); \
+ AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
+ ScopedAtomic sa(thr, callpc, __FUNCTION__); \
+ return Atomic##func(thr, pc, __VA_ARGS__); \
+/**/
+
class ScopedAtomic {
public:
ScopedAtomic(ThreadState *thr, uptr pc, const char *func)
: thr_(thr) {
- CHECK_EQ(thr_->in_rtl, 1); // 1 due to our own ScopedInRtl member.
+ CHECK_EQ(thr_->in_rtl, 0);
+ ProcessPendingSignals(thr);
+ FuncEntry(thr_, pc);
DPrintf("#%d: %s\n", thr_->tid, func);
+ thr_->in_rtl++;
}
~ScopedAtomic() {
- CHECK_EQ(thr_->in_rtl, 1);
+ thr_->in_rtl--;
+ CHECK_EQ(thr_->in_rtl, 0);
+ FuncExit(thr_);
}
private:
ThreadState *thr_;
- ScopedInRtl in_rtl_;
};
// Some shortcuts.
@@ -210,16 +227,19 @@ a128 func_cas(volatile a128 *v, a128 cmp, a128 xch) {
}
#endif
-#define SCOPED_ATOMIC(func, ...) \
- 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__); \
- return Atomic##func(thr, pc, __VA_ARGS__); \
-/**/
+template<typename T>
+static int SizeLog() {
+ if (sizeof(T) <= 1)
+ return kSizeLog1;
+ else if (sizeof(T) <= 2)
+ return kSizeLog2;
+ else if (sizeof(T) <= 4)
+ return kSizeLog4;
+ else
+ return kSizeLog8;
+ // For 16-byte atomics we also use 8-byte memory access,
+ // this leads to false negatives only in very obscure cases.
+}
template<typename T>
static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
@@ -227,14 +247,17 @@ static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
CHECK(IsLoadOrder(mo));
// This fast-path is critical for performance.
// Assume the access is atomic.
- if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a))
+ if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
+ MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
return *a;
+ }
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
thr->clock.set(thr->tid, thr->fast_state.epoch());
thr->clock.acquire(&s->clock);
T v = *a;
s->mtx.ReadUnlock();
__sync_synchronize();
+ MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
return v;
}
@@ -242,6 +265,7 @@ template<typename T>
static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
morder mo) {
CHECK(IsStoreOrder(mo));
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
// This fast-path is critical for performance.
// Assume the access is atomic.
// Strictly saying even relaxed store cuts off release sequence,
@@ -263,6 +287,7 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
template<typename T, T (*F)(volatile T *v, T op)>
static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
thr->clock.set(thr->tid, thr->fast_state.epoch());
if (IsAcqRelOrder(mo))
@@ -322,6 +347,7 @@ template<typename T>
static bool AtomicCAS(ThreadState *thr, uptr pc,
volatile T *a, T *c, T v, morder mo, morder fmo) {
(void)fmo; // Unused because llvm does not pass it yet.
+ MemoryWriteAtomic(thr, pc, (uptr)a, SizeLog<T>());
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
thr->clock.set(thr->tid, thr->fast_state.epoch());
if (IsAcqRelOrder(mo))
diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
index 133348a..92796d1 100644
--- a/libsanitizer/tsan/tsan_interface_inl.h
+++ b/libsanitizer/tsan/tsan_interface_inl.h
@@ -17,41 +17,41 @@
using namespace __tsan; // NOLINT
void __tsan_read1(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 0);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
}
void __tsan_read2(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 0);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
}
void __tsan_read4(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 0);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
}
void __tsan_read8(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 0);
+ MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
}
void __tsan_write1(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 0, 1);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog1);
}
void __tsan_write2(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 1, 1);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog2);
}
void __tsan_write4(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 2, 1);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog4);
}
void __tsan_write8(void *addr) {
- MemoryAccess(cur_thread(), CALLERPC, (uptr)addr, 3, 1);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
}
void __tsan_vptr_update(void **vptr_p, void *new_val) {
CHECK_EQ(sizeof(vptr_p), 8);
if (*vptr_p != new_val)
- MemoryAccess(cur_thread(), CALLERPC, (uptr)vptr_p, 3, 1);
+ MemoryWrite(cur_thread(), CALLERPC, (uptr)vptr_p, kSizeLog8);
}
void __tsan_func_entry(void *pc) {
diff --git a/libsanitizer/tsan/tsan_interface_java.cc b/libsanitizer/tsan/tsan_interface_java.cc
index d7325dc..f8c0b4e 100644
--- a/libsanitizer/tsan/tsan_interface_java.cc
+++ b/libsanitizer/tsan/tsan_interface_java.cc
@@ -150,7 +150,7 @@ SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
return 0;
}
-} // namespace __tsan {
+} // namespace __tsan
#define SCOPED_JAVA_FUNC(func) \
ThreadState *thr = cur_thread(); \
diff --git a/libsanitizer/tsan/tsan_md5.cc b/libsanitizer/tsan/tsan_md5.cc
index 6df823d..883239c 100644
--- a/libsanitizer/tsan/tsan_md5.cc
+++ b/libsanitizer/tsan/tsan_md5.cc
@@ -240,4 +240,4 @@ MD5Hash md5_hash(const void *data, uptr size) {
MD5_Final((unsigned char*)&res.hash[0], &ctx);
return res;
}
-}
+} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_mman.cc b/libsanitizer/tsan/tsan_mman.cc
index f4fafaf..23c73c5 100644
--- a/libsanitizer/tsan/tsan_mman.cc
+++ b/libsanitizer/tsan/tsan_mman.cc
@@ -36,8 +36,16 @@ void InitializeAllocator() {
allocator()->Init();
}
-void AlloctorThreadFinish(ThreadState *thr) {
- allocator()->SwallowCache(&thr->alloc_cache);
+void AllocatorThreadStart(ThreadState *thr) {
+ allocator()->InitCache(&thr->alloc_cache);
+}
+
+void AllocatorThreadFinish(ThreadState *thr) {
+ allocator()->DestroyCache(&thr->alloc_cache);
+}
+
+void AllocatorPrintStats() {
+ allocator()->PrintStats();
}
static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
@@ -162,3 +170,49 @@ void internal_free(void *p) {
}
} // namespace __tsan
+
+using namespace __tsan;
+
+extern "C" {
+uptr __tsan_get_current_allocated_bytes() {
+ u64 stats[AllocatorStatCount];
+ allocator()->GetStats(stats);
+ u64 m = stats[AllocatorStatMalloced];
+ u64 f = stats[AllocatorStatFreed];
+ return m >= f ? m - f : 1;
+}
+
+uptr __tsan_get_heap_size() {
+ u64 stats[AllocatorStatCount];
+ allocator()->GetStats(stats);
+ u64 m = stats[AllocatorStatMmapped];
+ u64 f = stats[AllocatorStatUnmapped];
+ return m >= f ? m - f : 1;
+}
+
+uptr __tsan_get_free_bytes() {
+ return 1;
+}
+
+uptr __tsan_get_unmapped_bytes() {
+ return 1;
+}
+
+uptr __tsan_get_estimated_allocated_size(uptr size) {
+ return size;
+}
+
+bool __tsan_get_ownership(void *p) {
+ return allocator()->GetBlockBegin(p) != 0;
+}
+
+uptr __tsan_get_allocated_size(void *p) {
+ if (p == 0)
+ return 0;
+ p = allocator()->GetBlockBegin(p);
+ if (p == 0)
+ return 0;
+ MBlock *b = (MBlock*)allocator()->GetMetaData(p);
+ return b->size;
+}
+} // extern "C"
diff --git a/libsanitizer/tsan/tsan_mman.h b/libsanitizer/tsan/tsan_mman.h
index 8697d22..7a657e1 100644
--- a/libsanitizer/tsan/tsan_mman.h
+++ b/libsanitizer/tsan/tsan_mman.h
@@ -18,7 +18,9 @@ namespace __tsan {
const uptr kDefaultAlignment = 16;
void InitializeAllocator();
-void AlloctorThreadFinish(ThreadState *thr);
+void AllocatorThreadStart(ThreadState *thr);
+void AllocatorThreadFinish(ThreadState *thr);
+void AllocatorPrintStats();
// For user allocations.
void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index 9fdc4dd..78c1a7d 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -149,6 +149,7 @@ bool IsGlobalVar(uptr addr);
uptr GetTlsSize();
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size);
+int ExtractResolvFDs(void *state, int *fds, int nfd);
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc
index 2e7cd51..def9155 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cc
+++ b/libsanitizer/tsan/tsan_platform_linux.cc
@@ -38,6 +38,8 @@
#include <errno.h>
#include <sched.h>
#include <dlfcn.h>
+#define __need_res_state
+#include <resolv.h>
extern "C" int arch_prctl(int code, __sanitizer::uptr *addr);
@@ -287,6 +289,19 @@ bool IsGlobalVar(uptr addr) {
return g_data_start && addr >= g_data_start && addr < g_data_end;
}
+#ifndef TSAN_GO
+int ExtractResolvFDs(void *state, int *fds, int nfd) {
+ int cnt = 0;
+ __res_state *statp = (__res_state*)state;
+ for (int i = 0; i < MAXNS && cnt < nfd; i++) {
+ if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
+ fds[cnt++] = statp->_u._ext.nssocks[i];
+ }
+ return cnt;
+}
+#endif
+
+
} // namespace __tsan
#endif // #ifdef __linux__
diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc
index f99fd2e..098d826 100644
--- a/libsanitizer/tsan/tsan_report.cc
+++ b/libsanitizer/tsan/tsan_report.cc
@@ -41,23 +41,20 @@ const char *thread_name(char *buf, int tid) {
return buf;
}
-static void PrintHeader(ReportType typ) {
- Printf("WARNING: ThreadSanitizer: ");
-
+static const char *ReportTypeString(ReportType typ) {
if (typ == ReportTypeRace)
- Printf("data race");
- else if (typ == ReportTypeUseAfterFree)
- Printf("heap-use-after-free");
- else if (typ == ReportTypeThreadLeak)
- Printf("thread leak");
- else if (typ == ReportTypeMutexDestroyLocked)
- Printf("destroy of a locked mutex");
- else if (typ == ReportTypeSignalUnsafe)
- Printf("signal-unsafe call inside of a signal");
- else if (typ == ReportTypeErrnoInSignal)
- Printf("signal handler spoils errno");
-
- Printf(" (pid=%d)\n", GetPid());
+ return "data race";
+ if (typ == ReportTypeUseAfterFree)
+ return "heap-use-after-free";
+ if (typ == ReportTypeThreadLeak)
+ return "thread leak";
+ if (typ == ReportTypeMutexDestroyLocked)
+ return "destroy of a locked mutex";
+ if (typ == ReportTypeSignalUnsafe)
+ return "signal-unsafe call inside of a signal";
+ if (typ == ReportTypeErrnoInSignal)
+ return "signal handler spoils errno";
+ return "";
}
void PrintStack(const ReportStack *ent) {
@@ -87,11 +84,17 @@ static void PrintMutexSet(Vector<ReportMopMutex> const& mset) {
}
}
+static const char *MopDesc(bool first, bool write, bool atomic) {
+ return atomic ? (first ? (write ? "Atomic write" : "Atomic read")
+ : (write ? "Previous atomic write" : "Previous atomic read"))
+ : (first ? (write ? "Write" : "Read")
+ : (write ? "Previous write" : "Previous read"));
+}
+
static void PrintMop(const ReportMop *mop, bool first) {
char thrbuf[kThreadBufSize];
Printf(" %s of size %d at %p by %s",
- (first ? (mop->write ? "Write" : "Read")
- : (mop->write ? "Previous write" : "Previous read")),
+ MopDesc(first, mop->write, mop->atomic),
mop->size, (void*)mop->addr,
thread_name(thrbuf, mop->tid));
PrintMutexSet(mop->mset);
@@ -150,9 +153,28 @@ static void PrintSleep(const ReportStack *s) {
PrintStack(s);
}
+static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
+ if (rep->mops.Size())
+ return rep->mops[0]->stack;
+ if (rep->stacks.Size())
+ return rep->stacks[0];
+ if (rep->mutexes.Size())
+ return rep->mutexes[0]->stack;
+ if (rep->threads.Size())
+ return rep->threads[0]->stack;
+ return 0;
+}
+
+ReportStack *SkipTsanInternalFrames(ReportStack *ent) {
+ while (FrameIsInternal(ent) && ent->next)
+ ent = ent->next;
+ return ent;
+}
+
void PrintReport(const ReportDesc *rep) {
Printf("==================\n");
- PrintHeader(rep->typ);
+ const char *rep_typ_str = ReportTypeString(rep->typ);
+ Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str, GetPid());
for (uptr i = 0; i < rep->stacks.Size(); i++) {
if (i)
@@ -175,6 +197,9 @@ void PrintReport(const ReportDesc *rep) {
for (uptr i = 0; i < rep->threads.Size(); i++)
PrintThread(rep->threads[i]);
+ if (ReportStack *ent = SkipTsanInternalFrames(ChooseSummaryStack(rep)))
+ ReportErrorSummary(rep_typ_str, ent->file, ent->line, ent->func);
+
Printf("==================\n");
}
diff --git a/libsanitizer/tsan/tsan_report.h b/libsanitizer/tsan/tsan_report.h
index 42f52af..eae2b3c 100644
--- a/libsanitizer/tsan/tsan_report.h
+++ b/libsanitizer/tsan/tsan_report.h
@@ -46,6 +46,7 @@ struct ReportMop {
uptr addr;
int size;
bool write;
+ bool atomic;
Vector<ReportMopMutex> mset;
ReportStack *stack;
diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc
index 3615a7a..673a355 100644
--- a/libsanitizer/tsan/tsan_rtl.cc
+++ b/libsanitizer/tsan/tsan_rtl.cc
@@ -35,6 +35,11 @@ THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
#endif
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
+// Can be overriden by a front-end.
+bool CPP_WEAK OnFinalize(bool failed) {
+ return failed;
+}
+
static Context *ctx;
Context *CTX() {
return ctx;
@@ -136,7 +141,7 @@ static void InitializeMemoryProfile() {
InternalScopedBuffer<char> filename(4096);
internal_snprintf(filename.data(), filename.size(), "%s.%d",
flags()->profile_memory, GetPid());
- fd_t fd = internal_open(filename.data(), true);
+ fd_t fd = OpenFile(filename.data(), true);
if (fd == kInvalidFd) {
Printf("Failed to open memory profile file '%s'\n", &filename[0]);
Die();
@@ -180,6 +185,7 @@ void Initialize(ThreadState *thr) {
if (is_initialized)
return;
is_initialized = true;
+ SanitizerToolName = "ThreadSanitizer";
// Install tool-specific callbacks in sanitizer_common.
SetCheckFailedCallback(TsanCheckFailed);
@@ -237,7 +243,7 @@ void Initialize(ThreadState *thr) {
Printf("ThreadSanitizer is suspended at startup (pid %d)."
" Call __tsan_resume().\n",
GetPid());
- while (__tsan_resumed == 0);
+ while (__tsan_resumed == 0) {}
}
}
@@ -253,6 +259,11 @@ int Finalize(ThreadState *thr) {
ctx->report_mtx.Lock();
ctx->report_mtx.Unlock();
+#ifndef TSAN_GO
+ if (ctx->flags.verbosity)
+ AllocatorPrintStats();
+#endif
+
ThreadFinalize(thr);
if (ctx->nreported) {
@@ -270,6 +281,8 @@ int Finalize(ThreadState *thr) {
ctx->nmissed_expected);
}
+ failed = OnFinalize(failed);
+
StatAggregate(ctx->stat, thr->stat);
StatOutput(ctx->stat);
return failed ? flags()->exitcode : 0;
@@ -356,18 +369,6 @@ static inline void HandleRace(ThreadState *thr, u64 *shadow_mem,
#endif
}
-static inline bool BothReads(Shadow s, int kAccessIsWrite) {
- return !kAccessIsWrite && !s.is_write();
-}
-
-static inline bool OldIsRWNotWeaker(Shadow old, int kAccessIsWrite) {
- return old.is_write() || !kAccessIsWrite;
-}
-
-static inline bool OldIsRWWeakerOrEqual(Shadow old, int kAccessIsWrite) {
- return !old.is_write() || kAccessIsWrite;
-}
-
static inline bool OldIsInSameSynchEpoch(Shadow old, ThreadState *thr) {
return old.epoch() >= thr->fast_synch_epoch;
}
@@ -378,7 +379,7 @@ static inline bool HappensBefore(Shadow old, ThreadState *thr) {
ALWAYS_INLINE
void MemoryAccessImpl(ThreadState *thr, uptr addr,
- int kAccessSizeLog, bool kAccessIsWrite,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
u64 *shadow_mem, Shadow cur) {
StatInc(thr, StatMop);
StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
@@ -452,7 +453,7 @@ void MemoryAccessImpl(ThreadState *thr, uptr addr,
ALWAYS_INLINE
void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
- int kAccessSizeLog, bool kAccessIsWrite) {
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic) {
u64 *shadow_mem = (u64*)MemToShadow(addr);
DPrintf2("#%d: MemoryAccess: @%p %p size=%d"
" is_write=%d shadow_mem=%p {%zx, %zx, %zx, %zx}\n",
@@ -479,12 +480,13 @@ void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
Shadow cur(fast_state);
cur.SetAddr0AndSizeLog(addr & 7, kAccessSizeLog);
cur.SetWrite(kAccessIsWrite);
+ cur.SetAtomic(kIsAtomic);
// We must not store to the trace if we do not store to the shadow.
// That is, this call must be moved somewhere below.
TraceAddEvent(thr, fast_state, EventTypeMop, pc);
- MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite,
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, kAccessIsWrite, kIsAtomic,
shadow_mem, cur);
}
@@ -531,7 +533,10 @@ void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size) {
}
void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size) {
+ CHECK_EQ(thr->is_freeing, false);
+ thr->is_freeing = true;
MemoryAccessRange(thr, pc, addr, size, true);
+ thr->is_freeing = false;
Shadow s(thr->fast_state);
s.ClearIgnoreBit();
s.MarkAsFreed();
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index bb2fe56..717f459 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -171,7 +171,8 @@ class FastState {
// freed : 1
// tid : kTidBits
// epoch : kClkBits
-// is_write : 1
+// is_atomic : 1
+// is_read : 1
// size_log : 2
// addr0 : 3
class Shadow : public FastState {
@@ -195,13 +196,26 @@ class Shadow : public FastState {
}
void SetWrite(unsigned kAccessIsWrite) {
- DCHECK_EQ(x_ & 32, 0);
- if (kAccessIsWrite)
- x_ |= 32;
- DCHECK_EQ(kAccessIsWrite, is_write());
+ DCHECK_EQ(x_ & kReadBit, 0);
+ if (!kAccessIsWrite)
+ x_ |= kReadBit;
+ DCHECK_EQ(kAccessIsWrite, IsWrite());
}
- bool IsZero() const { return x_ == 0; }
+ void SetAtomic(bool kIsAtomic) {
+ DCHECK(!IsAtomic());
+ if (kIsAtomic)
+ x_ |= kAtomicBit;
+ DCHECK_EQ(IsAtomic(), kIsAtomic);
+ }
+
+ bool IsAtomic() const {
+ return x_ & kAtomicBit;
+ }
+
+ bool IsZero() const {
+ return x_ == 0;
+ }
static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
@@ -248,7 +262,8 @@ class Shadow : public FastState {
}
u64 addr0() const { return x_ & 7; }
u64 size() const { return 1ull << size_log(); }
- bool is_write() const { return x_ & 32; }
+ bool IsWrite() const { return !IsRead(); }
+ bool IsRead() const { return x_ & kReadBit; }
// The idea behind the freed bit is as follows.
// When the memory is freed (or otherwise unaccessible) we write to the shadow
@@ -263,13 +278,46 @@ class Shadow : public FastState {
x_ |= kFreedBit;
}
+ bool IsFreed() const {
+ return x_ & kFreedBit;
+ }
+
bool GetFreedAndReset() {
bool res = x_ & kFreedBit;
x_ &= ~kFreedBit;
return res;
}
+ bool IsBothReadsOrAtomic(bool kIsWrite, bool kIsAtomic) const {
+ // analyzes 5-th bit (is_read) and 6-th bit (is_atomic)
+ bool v = x_ & u64(((kIsWrite ^ 1) << kReadShift)
+ | (kIsAtomic << kAtomicShift));
+ DCHECK_EQ(v, (!IsWrite() && !kIsWrite) || (IsAtomic() && kIsAtomic));
+ return v;
+ }
+
+ bool IsRWNotWeaker(bool kIsWrite, bool kIsAtomic) const {
+ bool v = ((x_ >> kReadShift) & 3)
+ <= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+ DCHECK_EQ(v, (IsAtomic() < kIsAtomic) ||
+ (IsAtomic() == kIsAtomic && !IsWrite() <= !kIsWrite));
+ return v;
+ }
+
+ bool IsRWWeakerOrEqual(bool kIsWrite, bool kIsAtomic) const {
+ bool v = ((x_ >> kReadShift) & 3)
+ >= u64((kIsWrite ^ 1) | (kIsAtomic << 1));
+ DCHECK_EQ(v, (IsAtomic() > kIsAtomic) ||
+ (IsAtomic() == kIsAtomic && !IsWrite() >= !kIsWrite));
+ return v;
+ }
+
private:
+ static const u64 kReadShift = 5;
+ static const u64 kReadBit = 1ull << kReadShift;
+ static const u64 kAtomicShift = 6;
+ static const u64 kAtomicBit = 1ull << kAtomicShift;
+
u64 size_log() const { return (x_ >> 3) & 3; }
static bool TwoRangesIntersectSLOW(const Shadow s1, const Shadow s2) {
@@ -324,7 +372,9 @@ struct ThreadState {
const int tid;
const int unique_id;
int in_rtl;
+ bool in_symbolizer;
bool is_alive;
+ bool is_freeing;
const uptr stk_addr;
const uptr stk_size;
const uptr tls_addr;
@@ -501,11 +551,14 @@ void InitializeDynamicAnnotations();
void ReportRace(ThreadState *thr);
bool OutputReport(Context *ctx,
const ScopedReport &srep,
- const ReportStack *suppress_stack = 0);
+ const ReportStack *suppress_stack1 = 0,
+ const ReportStack *suppress_stack2 = 0);
bool IsFiredSuppression(Context *ctx,
const ScopedReport &srep,
const StackTrace &trace);
bool IsExpectedReport(uptr addr, uptr size);
+bool FrameIsInternal(const ReportStack *frame);
+ReportStack *SkipTsanInternalFrames(ReportStack *ent);
#if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
# define DPrintf Printf
@@ -521,6 +574,7 @@ bool IsExpectedReport(uptr addr, uptr size);
u32 CurrentStackId(ThreadState *thr, uptr pc);
void PrintCurrentStack(ThreadState *thr, uptr pc);
+void PrintCurrentStackSlow(); // uses libunwind
void Initialize(ThreadState *thr);
int Finalize(ThreadState *thr);
@@ -530,16 +584,38 @@ SyncVar* GetJavaSync(ThreadState *thr, uptr pc, uptr addr,
SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr);
void MemoryAccess(ThreadState *thr, uptr pc, uptr addr,
- int kAccessSizeLog, bool kAccessIsWrite);
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic);
void MemoryAccessImpl(ThreadState *thr, uptr addr,
- int kAccessSizeLog, bool kAccessIsWrite,
+ int kAccessSizeLog, bool kAccessIsWrite, bool kIsAtomic,
u64 *shadow_mem, Shadow cur);
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr);
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr);
void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
- uptr size, bool is_write);
+ uptr size, bool is_write);
+
+const int kSizeLog1 = 0;
+const int kSizeLog2 = 1;
+const int kSizeLog4 = 2;
+const int kSizeLog8 = 3;
+
+void ALWAYS_INLINE INLINE MemoryRead(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, false, false);
+}
+
+void ALWAYS_INLINE INLINE MemoryWrite(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, true, false);
+}
+
+void ALWAYS_INLINE INLINE MemoryReadAtomic(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, false, true);
+}
+
+void ALWAYS_INLINE INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
+ uptr addr, int kAccessSizeLog) {
+ MemoryAccess(thr, pc, addr, kAccessSizeLog, true, true);
+}
+
void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc
index db97e1d..22a7150 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cc
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cc
@@ -24,8 +24,12 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
StatInc(thr, StatMutexCreate);
- if (!linker_init && IsAppMem(addr))
- MemoryWrite1Byte(thr, pc, addr);
+ if (!linker_init && IsAppMem(addr)) {
+ CHECK(!thr->is_freeing);
+ thr->is_freeing = true;
+ MemoryWrite(thr, pc, addr, kSizeLog1);
+ thr->is_freeing = false;
+ }
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
s->is_rw = rw;
s->is_recursive = recursive;
@@ -47,8 +51,12 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
SyncVar *s = ctx->synctab.GetAndRemove(thr, pc, addr);
if (s == 0)
return;
- if (IsAppMem(addr))
- MemoryWrite1Byte(thr, pc, addr);
+ if (IsAppMem(addr)) {
+ CHECK(!thr->is_freeing);
+ thr->is_freeing = true;
+ MemoryWrite(thr, pc, addr, kSizeLog1);
+ thr->is_freeing = false;
+ }
if (flags()->report_destroy_locked
&& s->owner_tid != SyncVar::kInvalidTid
&& !s->is_broken) {
@@ -73,7 +81,7 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexLock %zx\n", thr->tid, addr);
if (IsAppMem(addr))
- MemoryRead1Byte(thr, pc, addr);
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
@@ -106,7 +114,7 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr);
if (IsAppMem(addr))
- MemoryRead1Byte(thr, pc, addr);
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId());
@@ -144,7 +152,7 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadLock);
if (IsAppMem(addr))
- MemoryRead1Byte(thr, pc, addr);
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
@@ -165,7 +173,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadUnlock);
if (IsAppMem(addr))
- MemoryRead1Byte(thr, pc, addr);
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
@@ -186,7 +194,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
if (IsAppMem(addr))
- MemoryRead1Byte(thr, pc, addr);
+ MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
bool write = true;
if (s->owner_tid == SyncVar::kInvalidTid) {
diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc
index c4256da..ff1d43b 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cc
+++ b/libsanitizer/tsan/tsan_rtl_report.cc
@@ -13,6 +13,7 @@
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_suppressions.h"
@@ -27,12 +28,15 @@ namespace __tsan {
using namespace __sanitizer; // NOLINT
+static ReportStack *SymbolizeStack(const StackTrace& trace);
+
void TsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) {
ScopedInRtl in_rtl;
Printf("FATAL: ThreadSanitizer CHECK failed: "
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
file, line, cond, (uptr)v1, (uptr)v2);
+ PrintCurrentStackSlow();
Die();
}
@@ -144,7 +148,8 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s,
mop->tid = s.tid();
mop->addr = addr + s.addr0();
mop->size = s.size();
- mop->write = s.is_write();
+ mop->write = s.IsWrite();
+ mop->atomic = s.IsAtomic();
mop->stack = SymbolizeStack(*stack);
for (uptr i = 0; i < mset->Size(); i++) {
MutexSet::Desc d = mset->Get(i);
@@ -458,9 +463,12 @@ static void AddRacyStacks(ThreadState *thr, const StackTrace (&traces)[2],
bool OutputReport(Context *ctx,
const ScopedReport &srep,
- const ReportStack *suppress_stack) {
+ const ReportStack *suppress_stack1,
+ const ReportStack *suppress_stack2) {
const ReportDesc *rep = srep.GetReport();
- const uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack);
+ uptr suppress_pc = IsSuppressed(rep->typ, suppress_stack1);
+ if (suppress_pc == 0)
+ suppress_pc = IsSuppressed(rep->typ, suppress_stack2);
if (suppress_pc != 0) {
FiredSuppression supp = {srep.GetReport()->typ, suppress_pc};
ctx->fired_suppressions.PushBack(supp);
@@ -486,6 +494,13 @@ bool IsFiredSuppression(Context *ctx,
return false;
}
+bool FrameIsInternal(const ReportStack *frame) {
+ return frame != 0 && frame->file != 0
+ && (internal_strstr(frame->file, "tsan_interceptors.cc") ||
+ internal_strstr(frame->file, "sanitizer_common_interceptors.inc") ||
+ internal_strstr(frame->file, "tsan_interface_"));
+}
+
// On programs that use Java we see weird reports like:
// WARNING: ThreadSanitizer: data race (pid=22512)
// Read of size 8 at 0x7d2b00084318 by thread 100:
@@ -495,22 +510,20 @@ bool IsFiredSuppression(Context *ctx,
// #0 strncpy tsan_interceptors.cc:501 (foo+0x00000d8e0919)
// #1 <null> <null>:0 (0x7f7ad9b42707)
static bool IsJavaNonsense(const ReportDesc *rep) {
+#ifndef TSAN_GO
for (uptr i = 0; i < rep->mops.Size(); i++) {
ReportMop *mop = rep->mops[i];
ReportStack *frame = mop->stack;
- if (frame != 0 && frame->func != 0
- && (internal_strcmp(frame->func, "memset") == 0
- || internal_strcmp(frame->func, "memcpy") == 0
- || internal_strcmp(frame->func, "memmove") == 0
- || internal_strcmp(frame->func, "strcmp") == 0
- || internal_strcmp(frame->func, "strncpy") == 0
- || internal_strcmp(frame->func, "strlen") == 0
- || internal_strcmp(frame->func, "free") == 0
- || internal_strcmp(frame->func, "pthread_mutex_lock") == 0)) {
+ if (frame == 0
+ || (frame->func == 0 && frame->file == 0 && frame->line == 0
+ && frame->module == 0)) {
+ return true;
+ }
+ if (FrameIsInternal(frame)) {
frame = frame->next;
if (frame == 0
|| (frame->func == 0 && frame->file == 0 && frame->line == 0
- && frame->module == 0)) {
+ && frame->module == 0)) {
if (frame) {
FiredSuppression supp = {rep->typ, frame->pc};
CTX()->fired_suppressions.PushBack(supp);
@@ -519,6 +532,20 @@ static bool IsJavaNonsense(const ReportDesc *rep) {
}
}
}
+#endif
+ return false;
+}
+
+static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
+ Shadow s0(thr->racy_state[0]);
+ Shadow s1(thr->racy_state[1]);
+ CHECK(!(s0.IsAtomic() && s1.IsAtomic()));
+ if (!s0.IsAtomic() && !s1.IsAtomic())
+ return true;
+ if (s0.IsAtomic() && s1.IsFreed())
+ return true;
+ if (s1.IsAtomic() && thr->is_freeing)
+ return true;
return false;
}
@@ -527,6 +554,9 @@ void ReportRace(ThreadState *thr) {
return;
ScopedInRtl in_rtl;
+ if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
+ return;
+
if (thr->in_signal_handler)
Printf("ThreadSanitizer: printing report from signal handler."
" Can crash or hang.\n");
@@ -597,7 +627,8 @@ void ReportRace(ThreadState *thr) {
}
#endif
- if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack))
+ if (!OutputReport(ctx, rep, rep.GetReport()->mops[0]->stack,
+ rep.GetReport()->mops[1]->stack))
return;
AddRacyStacks(thr, traces, addr_min, addr_max);
@@ -609,4 +640,16 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
PrintStack(SymbolizeStack(trace));
}
+void PrintCurrentStackSlow() {
+#ifndef TSAN_GO
+ __sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
+ sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
+ ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
+ kStackTraceMax);
+ StackTrace trace;
+ trace.Init(ptrace->trace, ptrace->size);
+ PrintStack(SymbolizeStack(trace));
+#endif
+}
+
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc
index d5b3444..9c89417 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cc
+++ b/libsanitizer/tsan/tsan_rtl_thread.cc
@@ -207,6 +207,9 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
thr->shadow_stack_pos = thr->shadow_stack;
thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
+#ifndef TSAN_GO
+ AllocatorThreadStart(thr);
+#endif
tctx->thr = thr;
thr->fast_synch_epoch = tctx->epoch0;
thr->clock.set(tid, tctx->epoch0);
@@ -267,7 +270,7 @@ void ThreadFinish(ThreadState *thr) {
tctx->epoch1 = thr->fast_state.epoch();
#ifndef TSAN_GO
- AlloctorThreadFinish(thr);
+ AllocatorThreadFinish(thr);
#endif
thr->~ThreadState();
StatAggregate(ctx->stat, thr->stat);
@@ -392,7 +395,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,
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
shadow_mem, cur);
}
if (unaligned)
@@ -403,7 +406,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,
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
shadow_mem, cur);
shadow_mem += kShadowCnt;
}
@@ -413,24 +416,8 @@ 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,
+ MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
shadow_mem, cur);
}
}
-
-void MemoryRead1Byte(ThreadState *thr, uptr pc, uptr addr) {
- MemoryAccess(thr, pc, addr, 0, 0);
-}
-
-void MemoryWrite1Byte(ThreadState *thr, uptr pc, uptr addr) {
- MemoryAccess(thr, pc, addr, 0, 1);
-}
-
-void MemoryRead8Byte(ThreadState *thr, uptr pc, uptr addr) {
- MemoryAccess(thr, pc, addr, 3, 0);
-}
-
-void MemoryWrite8Byte(ThreadState *thr, uptr pc, uptr addr) {
- MemoryAccess(thr, pc, addr, 3, 1);
-}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc
index 105d0bc..cd88d2d 100644
--- a/libsanitizer/tsan/tsan_stat.cc
+++ b/libsanitizer/tsan/tsan_stat.cc
@@ -179,6 +179,18 @@ void StatOutput(u64 *stat) {
name[StatInt_sem_timedwait] = " sem_timedwait ";
name[StatInt_sem_post] = " sem_post ";
name[StatInt_sem_getvalue] = " sem_getvalue ";
+ name[StatInt_stat] = " stat ";
+ name[StatInt___xstat] = " __xstat ";
+ name[StatInt_stat64] = " stat64 ";
+ name[StatInt___xstat64] = " __xstat64 ";
+ name[StatInt_lstat] = " lstat ";
+ name[StatInt___lxstat] = " __lxstat ";
+ name[StatInt_lstat64] = " lstat64 ";
+ name[StatInt___lxstat64] = " __lxstat64 ";
+ name[StatInt_fstat] = " fstat ";
+ name[StatInt___fxstat] = " __fxstat ";
+ name[StatInt_fstat64] = " fstat64 ";
+ name[StatInt___fxstat64] = " __fxstat64 ";
name[StatInt_open] = " open ";
name[StatInt_open64] = " open64 ";
name[StatInt_creat] = " creat ";
@@ -193,12 +205,15 @@ void StatOutput(u64 *stat) {
name[StatInt_socket] = " socket ";
name[StatInt_socketpair] = " socketpair ";
name[StatInt_connect] = " connect ";
+ name[StatInt_bind] = " bind ";
+ name[StatInt_listen] = " listen ";
name[StatInt_accept] = " accept ";
name[StatInt_accept4] = " accept4 ";
name[StatInt_epoll_create] = " epoll_create ";
name[StatInt_epoll_create1] = " epoll_create1 ";
name[StatInt_close] = " close ";
name[StatInt___close] = " __close ";
+ name[StatInt___res_iclose] = " __res_iclose ";
name[StatInt_pipe] = " pipe ";
name[StatInt_pipe2] = " pipe2 ";
name[StatInt_read] = " read ";
@@ -240,6 +255,14 @@ void StatOutput(u64 *stat) {
name[StatInt_scanf] = " scanf ";
name[StatInt_sscanf] = " sscanf ";
name[StatInt_fscanf] = " fscanf ";
+ name[StatInt___isoc99_vscanf] = " vscanf ";
+ name[StatInt___isoc99_vsscanf] = " vsscanf ";
+ name[StatInt___isoc99_vfscanf] = " vfscanf ";
+ name[StatInt___isoc99_scanf] = " scanf ";
+ name[StatInt___isoc99_sscanf] = " sscanf ";
+ name[StatInt___isoc99_fscanf] = " fscanf ";
+ name[StatInt_on_exit] = " on_exit ";
+ name[StatInt___cxa_atexit] = " __cxa_atexit ";
name[StatAnnotation] = "Dynamic annotations ";
name[StatAnnotateHappensBefore] = " HappensBefore ";
@@ -285,6 +308,7 @@ void StatOutput(u64 *stat) {
name[StatMtxAnnotations] = " Annotations ";
name[StatMtxMBlock] = " MBlock ";
name[StatMtxJavaMBlock] = " JavaMBlock ";
+ name[StatMtxFD] = " FD ";
Printf("Statistics:\n");
for (int i = 0; i < StatCnt; i++)
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index f40d3a2..1d6c54c 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -174,6 +174,18 @@ enum StatType {
StatInt_sem_timedwait,
StatInt_sem_post,
StatInt_sem_getvalue,
+ StatInt_stat,
+ StatInt___xstat,
+ StatInt_stat64,
+ StatInt___xstat64,
+ StatInt_lstat,
+ StatInt___lxstat,
+ StatInt_lstat64,
+ StatInt___lxstat64,
+ StatInt_fstat,
+ StatInt___fxstat,
+ StatInt_fstat64,
+ StatInt___fxstat64,
StatInt_open,
StatInt_open64,
StatInt_creat,
@@ -188,12 +200,15 @@ enum StatType {
StatInt_socket,
StatInt_socketpair,
StatInt_connect,
+ StatInt_bind,
+ StatInt_listen,
StatInt_accept,
StatInt_accept4,
StatInt_epoll_create,
StatInt_epoll_create1,
StatInt_close,
StatInt___close,
+ StatInt___res_iclose,
StatInt_pipe,
StatInt_pipe2,
StatInt_read,
@@ -239,6 +254,14 @@ enum StatType {
StatInt_scanf,
StatInt_sscanf,
StatInt_fscanf,
+ StatInt___isoc99_vscanf,
+ StatInt___isoc99_vsscanf,
+ StatInt___isoc99_vfscanf,
+ StatInt___isoc99_scanf,
+ StatInt___isoc99_sscanf,
+ StatInt___isoc99_fscanf,
+ StatInt_on_exit,
+ StatInt___cxa_atexit,
// Dynamic annotations.
StatAnnotation,
@@ -287,6 +310,7 @@ enum StatType {
StatMtxAtExit,
StatMtxMBlock,
StatMtxJavaMBlock,
+ StatMtxFD,
// This must be the last.
StatCnt
diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc
index 42ba9b5..b6c54db 100644
--- a/libsanitizer/tsan/tsan_suppressions.cc
+++ b/libsanitizer/tsan/tsan_suppressions.cc
@@ -17,6 +17,13 @@
#include "tsan_mman.h"
#include "tsan_platform.h"
+// Can be overriden in frontend.
+#ifndef TSAN_GO
+extern "C" const char *WEAK __tsan_default_suppressions() {
+ return 0;
+}
+#endif
+
namespace __tsan {
static Suppression *g_suppressions;
@@ -29,7 +36,7 @@ static char *ReadFile(const char *filename) {
internal_snprintf(tmp.data(), tmp.size(), "%s", filename);
else
internal_snprintf(tmp.data(), tmp.size(), "%s/%s", GetPwd(), filename);
- fd_t fd = internal_open(tmp.data(), false);
+ fd_t fd = OpenFile(tmp.data(), false);
if (fd == kInvalidFd) {
Printf("ThreadSanitizer: failed to open suppressions file '%s'\n",
tmp.data());
@@ -78,8 +85,7 @@ bool SuppressionMatch(char *templ, const char *str) {
return true;
}
-Suppression *SuppressionParse(const char* supp) {
- Suppression *head = 0;
+Suppression *SuppressionParse(Suppression *head, const char* supp) {
const char *line = supp;
while (line) {
while (line[0] == ' ' || line[0] == '\t')
@@ -128,8 +134,12 @@ Suppression *SuppressionParse(const char* supp) {
}
void InitializeSuppressions() {
- char *supp = ReadFile(flags()->suppressions);
- g_suppressions = SuppressionParse(supp);
+ const char *supp = ReadFile(flags()->suppressions);
+ g_suppressions = SuppressionParse(0, supp);
+#ifndef TSAN_GO
+ supp = __tsan_default_suppressions();
+ g_suppressions = SuppressionParse(0, supp);
+#endif
}
uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
@@ -150,7 +160,8 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack) {
for (Suppression *supp = g_suppressions; supp; supp = supp->next) {
if (stype == supp->type &&
(SuppressionMatch(supp->templ, frame->func) ||
- SuppressionMatch(supp->templ, frame->file))) {
+ SuppressionMatch(supp->templ, frame->file) ||
+ SuppressionMatch(supp->templ, frame->module))) {
DPrintf("ThreadSanitizer: matched suppression '%s'\n", supp->templ);
return frame->pc;
}
diff --git a/libsanitizer/tsan/tsan_suppressions.h b/libsanitizer/tsan/tsan_suppressions.h
index 4761eaa..d44d8dd 100644
--- a/libsanitizer/tsan/tsan_suppressions.h
+++ b/libsanitizer/tsan/tsan_suppressions.h
@@ -33,7 +33,7 @@ struct Suppression {
char *templ;
};
-Suppression *SuppressionParse(const char* supp);
+Suppression *SuppressionParse(Suppression *head, const char* supp);
bool SuppressionMatch(char *templ, const char *str);
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_symbolize.cc b/libsanitizer/tsan/tsan_symbolize.cc
index 015b987..65a9946 100644
--- a/libsanitizer/tsan/tsan_symbolize.cc
+++ b/libsanitizer/tsan/tsan_symbolize.cc
@@ -16,9 +16,24 @@
#include "sanitizer_common/sanitizer_symbolizer.h"
#include "tsan_flags.h"
#include "tsan_report.h"
+#include "tsan_rtl.h"
namespace __tsan {
+struct ScopedInSymbolizer {
+ ScopedInSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(!thr->in_symbolizer);
+ thr->in_symbolizer = true;
+ }
+
+ ~ScopedInSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(thr->in_symbolizer);
+ thr->in_symbolizer = false;
+ }
+};
+
ReportStack *NewReportStackEntry(uptr addr) {
ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
sizeof(ReportStack));
@@ -53,35 +68,36 @@ static ReportStack *NewReportStackEntry(const AddressInfo &info) {
}
ReportStack *SymbolizeCode(uptr addr) {
- if (flags()->external_symbolizer_path[0]) {
- static const uptr kMaxAddrFrames = 16;
- InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
- for (uptr i = 0; i < kMaxAddrFrames; i++)
- new(&addr_frames[i]) AddressInfo();
- uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
- kMaxAddrFrames);
- if (addr_frames_num == 0)
- return NewReportStackEntry(addr);
- ReportStack *top = 0;
- ReportStack *bottom = 0;
- for (uptr i = 0; i < addr_frames_num; i++) {
- ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
- CHECK(cur_entry);
- addr_frames[i].Clear();
- if (i == 0)
- top = cur_entry;
- else
- bottom->next = cur_entry;
- bottom = cur_entry;
- }
- return top;
+ if (!IsSymbolizerAvailable())
+ return SymbolizeCodeAddr2Line(addr);
+ ScopedInSymbolizer in_symbolizer;
+ static const uptr kMaxAddrFrames = 16;
+ InternalScopedBuffer<AddressInfo> addr_frames(kMaxAddrFrames);
+ for (uptr i = 0; i < kMaxAddrFrames; i++)
+ new(&addr_frames[i]) AddressInfo();
+ uptr addr_frames_num = __sanitizer::SymbolizeCode(addr, addr_frames.data(),
+ kMaxAddrFrames);
+ if (addr_frames_num == 0)
+ return NewReportStackEntry(addr);
+ ReportStack *top = 0;
+ ReportStack *bottom = 0;
+ for (uptr i = 0; i < addr_frames_num; i++) {
+ ReportStack *cur_entry = NewReportStackEntry(addr_frames[i]);
+ CHECK(cur_entry);
+ addr_frames[i].Clear();
+ if (i == 0)
+ top = cur_entry;
+ else
+ bottom->next = cur_entry;
+ bottom = cur_entry;
}
- return SymbolizeCodeAddr2Line(addr);
+ return top;
}
ReportLocation *SymbolizeData(uptr addr) {
- if (flags()->external_symbolizer_path[0] == 0)
+ if (!IsSymbolizerAvailable())
return 0;
+ ScopedInSymbolizer in_symbolizer;
DataInfo info;
if (!__sanitizer::SymbolizeData(addr, &info))
return 0;
diff --git a/libsanitizer/tsan/tsan_update_shadow_word_inl.h b/libsanitizer/tsan/tsan_update_shadow_word_inl.h
index e22859c..b9aa51c 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 (OldIsRWNotWeaker(old, kAccessIsWrite)) {
+ if (old.IsRWNotWeaker(kAccessIsWrite, kIsAtomic)) {
// 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 (OldIsRWWeakerOrEqual(old, kAccessIsWrite))
+ if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
StoreIfNotYetStored(sp, &store_word);
break;
}
@@ -50,25 +50,23 @@ do {
StoreIfNotYetStored(sp, &store_word);
break;
}
- if (BothReads(old, kAccessIsWrite))
+ if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
break;
goto RACE;
}
-
// Do the memory access intersect?
- if (Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
+ // In Go all memory accesses are 1 byte, so there can be no intersections.
+ if (kCppMode && Shadow::TwoRangesIntersect(old, cur, kAccessSize)) {
StatInc(thr, StatShadowIntersect);
if (Shadow::TidsAreEqual(old, cur)) {
StatInc(thr, StatShadowSameThread);
break;
}
StatInc(thr, StatShadowAnotherThread);
- if (HappensBefore(old, thr))
+ if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
break;
-
- if (BothReads(old, kAccessIsWrite))
+ if (HappensBefore(old, thr))
break;
-
goto RACE;
}
// The accesses do not intersect.
diff --git a/libsanitizer/tsan/tsan_vector.h b/libsanitizer/tsan/tsan_vector.h
index d6bb707..99e9f79 100644
--- a/libsanitizer/tsan/tsan_vector.h
+++ b/libsanitizer/tsan/tsan_vector.h
@@ -103,6 +103,6 @@ class Vector {
Vector(const Vector&);
void operator=(const Vector&);
};
-}
+} // namespace __tsan
#endif // #ifndef TSAN_VECTOR_H