summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/c-c++-common/asan/null-deref-1.c1
-rw-r--r--libsanitizer/ChangeLog10
-rw-r--r--libsanitizer/MERGE2
-rw-r--r--libsanitizer/asan/asan_allocator.h21
-rw-r--r--libsanitizer/asan/asan_allocator2.cc71
-rw-r--r--libsanitizer/asan/asan_dll_thunk.cc2
-rw-r--r--libsanitizer/asan/asan_fake_stack.cc16
-rw-r--r--libsanitizer/asan/asan_fake_stack.h2
-rw-r--r--libsanitizer/asan/asan_flags.h10
-rw-r--r--libsanitizer/asan/asan_globals.cc6
-rw-r--r--libsanitizer/asan/asan_interceptors.cc48
-rw-r--r--libsanitizer/asan/asan_internal.h2
-rw-r--r--libsanitizer/asan/asan_linux.cc6
-rw-r--r--libsanitizer/asan/asan_mac.cc10
-rw-r--r--libsanitizer/asan/asan_malloc_linux.cc5
-rw-r--r--libsanitizer/asan/asan_malloc_win.cc5
-rw-r--r--libsanitizer/asan/asan_poisoning.cc53
-rw-r--r--libsanitizer/asan/asan_poisoning.h3
-rw-r--r--libsanitizer/asan/asan_posix.cc15
-rw-r--r--libsanitizer/asan/asan_report.cc100
-rw-r--r--libsanitizer/asan/asan_report.h6
-rw-r--r--libsanitizer/asan/asan_rtl.cc61
-rw-r--r--libsanitizer/asan/asan_stack.cc7
-rw-r--r--libsanitizer/asan/asan_stack.h30
-rw-r--r--libsanitizer/asan/asan_stats.h4
-rw-r--r--libsanitizer/asan/asan_thread.cc53
-rw-r--r--libsanitizer/asan/asan_thread.h24
-rw-r--r--libsanitizer/asan/asan_win.cc3
-rw-r--r--libsanitizer/include/sanitizer/common_interface_defs.h42
-rw-r--r--libsanitizer/include/sanitizer/linux_syscall_hooks.h5
-rw-r--r--libsanitizer/interception/interception.h6
-rw-r--r--libsanitizer/interception/interception_linux.h9
-rw-r--r--libsanitizer/interception/interception_mac.h1
-rw-r--r--libsanitizer/interception/interception_win.h3
-rw-r--r--libsanitizer/lsan/Makefile.am1
-rw-r--r--libsanitizer/lsan/Makefile.in4
-rw-r--r--libsanitizer/lsan/lsan.cc31
-rw-r--r--libsanitizer/lsan/lsan.h6
-rw-r--r--libsanitizer/lsan/lsan_allocator.cc9
-rw-r--r--libsanitizer/lsan/lsan_common.cc39
-rw-r--r--libsanitizer/lsan/lsan_common.h2
-rw-r--r--libsanitizer/lsan/lsan_interceptors.cc54
-rw-r--r--libsanitizer/lsan/lsan_preinit.cc24
-rw-r--r--libsanitizer/lsan/lsan_thread.cc4
-rw-r--r--libsanitizer/sanitizer_common/Makefile.am8
-rw-r--r--libsanitizer/sanitizer_common/Makefile.in30
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.h72
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_internal.h14
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.cc108
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.h58
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc1368
-rwxr-xr-xlibsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc185
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage.cc111
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.cc30
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.h19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_internal_defs.h32
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.cc20
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libc.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libignore.cc103
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libignore.h82
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.cc41
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.h11
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc59
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.cc6
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mutex.h4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_placement_new.h10
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform.h7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h44
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc78
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc109
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h207
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc22
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_printf.cc24
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_quarantine.h15
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.cc204
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.h57
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc26
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc115
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_suppressions.cc9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_suppressions.h5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.cc61
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.h86
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc144
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.h38
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc37
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc208
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc16
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_thread_registry.cc12
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_thread_registry.h1
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win.cc30
-rw-r--r--libsanitizer/tsan/Makefile.am1
-rw-r--r--libsanitizer/tsan/Makefile.in14
-rw-r--r--libsanitizer/tsan/tsan_defs.h7
-rw-r--r--libsanitizer/tsan/tsan_fd.cc34
-rw-r--r--libsanitizer/tsan/tsan_flags.cc78
-rw-r--r--libsanitizer/tsan/tsan_flags.h19
-rw-r--r--libsanitizer/tsan/tsan_ignoreset.cc45
-rw-r--r--libsanitizer/tsan/tsan_ignoreset.h36
-rw-r--r--libsanitizer/tsan/tsan_interceptors.cc374
-rw-r--r--libsanitizer/tsan/tsan_interface_ann.cc26
-rw-r--r--libsanitizer/tsan/tsan_interface_atomic.cc33
-rw-r--r--libsanitizer/tsan/tsan_interface_java.cc13
-rw-r--r--libsanitizer/tsan/tsan_interface_java.h6
-rw-r--r--libsanitizer/tsan/tsan_mutexset.h2
-rw-r--r--libsanitizer/tsan/tsan_platform.h12
-rw-r--r--libsanitizer/tsan/tsan_platform_linux.cc48
-rw-r--r--libsanitizer/tsan/tsan_report.cc2
-rw-r--r--libsanitizer/tsan/tsan_rtl.cc100
-rw-r--r--libsanitizer/tsan/tsan_rtl.h40
-rw-r--r--libsanitizer/tsan/tsan_rtl_mutex.cc111
-rw-r--r--libsanitizer/tsan/tsan_rtl_report.cc58
-rw-r--r--libsanitizer/tsan/tsan_rtl_thread.cc68
-rw-r--r--libsanitizer/tsan/tsan_stat.cc59
-rw-r--r--libsanitizer/tsan/tsan_stat.h59
-rw-r--r--libsanitizer/tsan/tsan_suppressions.cc5
-rw-r--r--libsanitizer/tsan/tsan_suppressions.h1
-rw-r--r--libsanitizer/tsan/tsan_symbolize.cc51
-rw-r--r--libsanitizer/tsan/tsan_symbolize.h2
-rw-r--r--libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc1
-rw-r--r--libsanitizer/tsan/tsan_sync.cc5
-rw-r--r--libsanitizer/tsan/tsan_trace.h5
-rw-r--r--libsanitizer/ubsan/ubsan_diag.cc33
-rw-r--r--libsanitizer/ubsan/ubsan_diag.h6
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.cc31
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.h11
-rw-r--r--libsanitizer/ubsan/ubsan_type_hash.cc16
-rw-r--r--libsanitizer/ubsan/ubsan_value.h4
130 files changed, 4535 insertions, 1639 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 12fbdcd49f6..f72c72c8991 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-05 Kostya Serebryany <kcc@google.com>
+
+ * c-c++-common/asan/null-deref-1.c: Update the test
+ to match the fresh asan run-time.
+
2013-12-05 Richard Biener <rguenther@suse.de>
PR tree-optimization/59374
diff --git a/gcc/testsuite/c-c++-common/asan/null-deref-1.c b/gcc/testsuite/c-c++-common/asan/null-deref-1.c
index 14ec514aa9a..6aea9d295f3 100644
--- a/gcc/testsuite/c-c++-common/asan/null-deref-1.c
+++ b/gcc/testsuite/c-c++-common/asan/null-deref-1.c
@@ -18,6 +18,5 @@ int main()
/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address\[^\n\r]*" } */
/* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
/* { dg-output " #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output " #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index 8404d51a053..661c326de73 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,13 @@
+2013-12-05 Kostya Serebryany <kcc@google.com>
+
+ * All source files: Merge from upstream r196090.
+ * tsan/Makefile.am (tsan_files): Added new files.
+ * tsan/Makefile.in: Regenerate.
+ * sanitizer_common/Makefile.am (sanitizer_common_files): Added new fles.
+ * sanitizer_common/Makefile.in: Regenerate.
+ * lsan/Makefile.am (lsan_files): Added new files.
+ * lsan/Makefile.in: Regenerate.
+
2013-11-29 Jakub Jelinek <jakub@redhat.com>
Yury Gribov <y.gribov@samsung.com>
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 0431b147a16..084cd2d4ee6 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-191666
+196090
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.h b/libsanitizer/asan/asan_allocator.h
index 1f83dcd6780..763f4a58ef9 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -33,10 +33,11 @@ void InitializeAllocator();
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid() { return chunk_ != 0; }
- uptr Beg(); // first byte of user memory.
- uptr End(); // last byte of user memory.
- uptr UsedSize(); // size requested by the user.
+ bool IsValid(); // Checks if AsanChunkView points to a valid allocated
+ // or quarantined chunk.
+ uptr Beg(); // First byte of user memory.
+ uptr End(); // Last byte of user memory.
+ uptr UsedSize(); // Size requested by the user.
uptr AllocTid();
uptr FreeTid();
void GetAllocStack(StackTrace *stack);
@@ -88,16 +89,12 @@ class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
};
struct AsanThreadLocalMallocStorage {
- explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
- { }
- AsanThreadLocalMallocStorage() {
- CHECK(REAL(memset));
- REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage));
- }
-
uptr quarantine_cache[16];
uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque.
void CommitBack();
+ private:
+ // These objects are allocated via mmap() and are zero-initialized.
+ AsanThreadLocalMallocStorage() {}
};
void *asan_memalign(uptr alignment, uptr size, StackTrace *stack,
@@ -112,7 +109,7 @@ void *asan_pvalloc(uptr size, StackTrace *stack);
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack);
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp);
uptr asan_mz_size(const void *ptr);
void asan_mz_force_lock();
diff --git a/libsanitizer/asan/asan_allocator2.cc b/libsanitizer/asan/asan_allocator2.cc
index 34aad11ed75..b9d66dc7a4a 100644
--- a/libsanitizer/asan/asan_allocator2.cc
+++ b/libsanitizer/asan/asan_allocator2.cc
@@ -92,7 +92,7 @@ AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) {
static Allocator allocator;
static const uptr kMaxAllowedMallocSize =
- FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
+ FIRST_32_SECOND_64(3UL << 30, 64UL << 30);
static const uptr kMaxThreadLocalQuarantine =
FIRST_32_SECOND_64(1 << 18, 1 << 20);
@@ -184,14 +184,19 @@ COMPILER_CHECK(kChunkHeader2Size <= 16);
struct AsanChunk: ChunkBase {
uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
- uptr UsedSize() {
+ uptr UsedSize(bool locked_version = false) {
if (user_requested_size != SizeClassMap::kMaxSize)
return user_requested_size;
- return *reinterpret_cast<uptr *>(allocator.GetMetaData(AllocBeg()));
- }
- void *AllocBeg() {
- if (from_memalign)
+ return *reinterpret_cast<uptr *>(
+ allocator.GetMetaData(AllocBeg(locked_version)));
+ }
+ void *AllocBeg(bool locked_version = false) {
+ if (from_memalign) {
+ if (locked_version)
+ return allocator.GetBlockBeginFastLocked(
+ reinterpret_cast<void *>(this));
return allocator.GetBlockBegin(reinterpret_cast<void *>(this));
+ }
return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log));
}
// If we don't use stack depot, we store the alloc/free stack traces
@@ -211,11 +216,14 @@ struct AsanChunk: ChunkBase {
uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY);
return (available - kChunkHeader2Size) / sizeof(u32);
}
- bool AddrIsInside(uptr addr) {
- return (addr >= Beg()) && (addr < Beg() + UsedSize());
+ bool AddrIsInside(uptr addr, bool locked_version = false) {
+ return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version));
}
};
+bool AsanChunkView::IsValid() {
+ return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE;
+}
uptr AsanChunkView::Beg() { return chunk_->Beg(); }
uptr AsanChunkView::End() { return Beg() + UsedSize(); }
uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
@@ -226,25 +234,16 @@ static void GetStackTraceFromId(u32 id, StackTrace *stack) {
CHECK(id);
uptr size = 0;
const uptr *trace = StackDepotGet(id, &size);
- CHECK_LT(size, kStackTraceMax);
- internal_memcpy(stack->trace, trace, sizeof(uptr) * size);
- stack->size = size;
+ CHECK(trace);
+ stack->CopyFrom(trace, size);
}
void AsanChunkView::GetAllocStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->alloc_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->AllocStackBeg(),
- chunk_->AllocStackSize());
+ GetStackTraceFromId(chunk_->alloc_context_id, stack);
}
void AsanChunkView::GetFreeStack(StackTrace *stack) {
- if (flags()->use_stack_depot)
- GetStackTraceFromId(chunk_->free_context_id, stack);
- else
- StackTrace::UncompressStack(stack, chunk_->FreeStackBeg(),
- chunk_->FreeStackSize());
+ GetStackTraceFromId(chunk_->free_context_id, stack);
}
struct QuarantineCallback;
@@ -390,12 +389,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
meta[1] = chunk_beg;
}
- if (fl.use_stack_depot) {
- m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->alloc_context_id = 0;
- StackTrace::CompressStack(stack, m->AllocStackBeg(), m->AllocStackSize());
- }
+ m->alloc_context_id = StackDepotPut(stack->trace, stack->size);
uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY);
// Unpoison the bulk of the memory region.
@@ -404,7 +398,7 @@ static void *Allocate(uptr size, uptr alignment, StackTrace *stack,
// Deal with the end of the region if size is not aligned to granularity.
if (size != size_rounded_down_to_granularity && fl.poison_heap) {
u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity);
- *shadow = size & (SHADOW_GRANULARITY - 1);
+ *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0;
}
AsanStats &thread_stats = GetCurrentThreadStats();
@@ -463,12 +457,7 @@ static void QuarantineChunk(AsanChunk *m, void *ptr,
CHECK_EQ(m->free_tid, kInvalidTid);
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
- if (flags()->use_stack_depot) {
- m->free_context_id = StackDepotPut(stack->trace, stack->size);
- } else {
- m->free_context_id = 0;
- StackTrace::CompressStack(stack, m->FreeStackBeg(), m->FreeStackSize());
- }
+ m->free_context_id = StackDepotPut(stack->trace, stack->size);
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -673,12 +662,13 @@ int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
return 0;
}
-uptr asan_malloc_usable_size(void *ptr, StackTrace *stack) {
- CHECK(stack);
+uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) {
if (ptr == 0) return 0;
uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr));
- if (flags()->check_malloc_usable_size && (usable_size == 0))
- ReportMallocUsableSizeNotOwned((uptr)ptr, stack);
+ if (flags()->check_malloc_usable_size && (usable_size == 0)) {
+ GET_STACK_TRACE_FATAL(pc, bp);
+ ReportMallocUsableSizeNotOwned((uptr)ptr, &stack);
+ }
return usable_size;
}
@@ -718,7 +708,8 @@ uptr PointsIntoChunk(void* p) {
__asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr);
if (!m) return 0;
uptr chunk = m->Beg();
- if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr))
+ if ((m->chunk_state == __asan::CHUNK_ALLOCATED) &&
+ m->AddrIsInside(addr, /*locked_version=*/true))
return chunk;
return 0;
}
@@ -751,7 +742,7 @@ void LsanMetadata::set_tag(ChunkTag value) {
uptr LsanMetadata::requested_size() const {
__asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
- return m->UsedSize();
+ return m->UsedSize(/*locked_version=*/true);
}
u32 LsanMetadata::stack_trace_id() const {
diff --git a/libsanitizer/asan/asan_dll_thunk.cc b/libsanitizer/asan/asan_dll_thunk.cc
index 26e19441523..19c31f0def8 100644
--- a/libsanitizer/asan/asan_dll_thunk.cc
+++ b/libsanitizer/asan/asan_dll_thunk.cc
@@ -130,6 +130,8 @@ extern "C" {
}
}
+WRAP_V_V(__asan_handle_no_return)
+
WRAP_V_W(__asan_report_store1)
WRAP_V_W(__asan_report_store2)
WRAP_V_W(__asan_report_store4)
diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc
index b9cce88f34f..cf4122472ef 100644
--- a/libsanitizer/asan/asan_fake_stack.cc
+++ b/libsanitizer/asan/asan_fake_stack.cc
@@ -43,7 +43,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
FakeStack *res = reinterpret_cast<FakeStack *>(
MmapOrDie(RequiredSize(stack_size_log), "FakeStack"));
res->stack_size_log_ = stack_size_log;
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
u8 *p = reinterpret_cast<u8 *>(res);
Report("T%d: FakeStack created: %p -- %p stack_size_log: %zd \n",
GetCurrentTidOrInvalid(), p,
@@ -132,6 +132,20 @@ NOINLINE void FakeStack::GC(uptr real_stack) {
needs_gc_ = false;
}
+void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ uptr begin = reinterpret_cast<uptr>(ff);
+ callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
+ }
+ }
+}
+
#if SANITIZER_LINUX && !SANITIZER_ANDROID
static THREADLOCAL FakeStack *fake_stack_tls;
diff --git a/libsanitizer/asan/asan_fake_stack.h b/libsanitizer/asan/asan_fake_stack.h
index 4287497fd5d..5196025681c 100644
--- a/libsanitizer/asan/asan_fake_stack.h
+++ b/libsanitizer/asan/asan_fake_stack.h
@@ -146,6 +146,8 @@ class FakeStack {
void HandleNoReturn();
void GC(uptr real_stack);
+ void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
+
private:
FakeStack() { }
static const uptr kFlagsOffset = 4096; // This is were the flags begin.
diff --git a/libsanitizer/asan/asan_flags.h b/libsanitizer/asan/asan_flags.h
index c115997ff29..62b5d3215d3 100644
--- a/libsanitizer/asan/asan_flags.h
+++ b/libsanitizer/asan/asan_flags.h
@@ -30,8 +30,6 @@ struct Flags {
// Lower value may reduce memory usage but increase the chance of
// false negatives.
int quarantine_size;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
- int verbosity;
// Size (in bytes) of redzones around heap objects.
// Requirement: redzone >= 32, is a power of two.
int redzone;
@@ -83,6 +81,9 @@ struct Flags {
bool print_legend;
// If set, prints ASan exit stats even after program terminates successfully.
bool atexit;
+ // If set, coverage information will be dumped at shutdown time if the
+ // appropriate instrumentation was enabled.
+ bool coverage;
// By default, disable core dumper on 64-bit - it makes little sense
// to dump 16T+ core.
bool disable_core;
@@ -96,10 +97,11 @@ struct Flags {
// Poison (or not) the heap memory on [de]allocation. Zero value is useful
// for benchmarking the allocator or instrumentator.
bool poison_heap;
+ // If true, poison partially addressable 8-byte aligned words (default=true).
+ // This flag affects heap and global buffers, but not stack buffers.
+ bool poison_partial;
// Report errors on malloc/delete, new/free, new/delete[], etc.
bool alloc_dealloc_mismatch;
- // Use stack depot instead of storing stacks in the redzones.
- bool use_stack_depot;
// If true, assume that memcmp(p1, p2, n) always reads n bytes before
// comparing p1 and p2.
bool strict_memcmp;
diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc
index 96985af71a9..e97850a854a 100644
--- a/libsanitizer/asan/asan_globals.cc
+++ b/libsanitizer/asan/asan_globals.cc
@@ -92,15 +92,13 @@ static void RegisterGlobal(const Global *g) {
CHECK(AddrIsAlignedByGranularity(g->size_with_redzone));
if (flags()->poison_heap)
PoisonRedZones(*g);
- ListOfGlobals *l =
- (ListOfGlobals*)allocator_for_globals.Allocate(sizeof(ListOfGlobals));
+ ListOfGlobals *l = new(allocator_for_globals) ListOfGlobals;
l->g = g;
l->next = list_of_all_globals;
list_of_all_globals = l;
if (g->has_dynamic_init) {
if (dynamic_init_globals == 0) {
- void *mem = allocator_for_globals.Allocate(sizeof(VectorOfGlobals));
- dynamic_init_globals = new(mem)
+ dynamic_init_globals = new(allocator_for_globals)
VectorOfGlobals(kDynamicInitGlobalsInitialCapacity);
}
DynInitGlobal dyn_global = { *g, false };
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index 72f7aae814a..decbfea5f75 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -92,6 +92,11 @@ void SetThreadName(const char *name) {
asanThreadRegistry().SetThreadName(t->tid(), name);
}
+int OnExit() {
+ // FIXME: ask frontend whether we need to return failure.
+ return 0;
+}
+
} // namespace __asan
// ---------------------- Wrappers ---------------- {{{1
@@ -100,6 +105,19 @@ using namespace __asan; // NOLINT
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
+#if !SANITIZER_MAC
+#define ASAN_INTERCEPT_FUNC(name) \
+ do { \
+ if ((!INTERCEPT_FUNCTION(name) || !REAL(name)) && \
+ common_flags()->verbosity > 0) \
+ Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
+ } while (0)
+#else
+// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
+#define ASAN_INTERCEPT_FUNC(name)
+#endif // SANITIZER_MAC
+
+#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
do { \
} while (false)
@@ -124,16 +142,28 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
do { \
} while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
+// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
+// But asan does not remember UserId's for threads (pthread_t);
+// and remembers all ever existed threads, so the linear search by UserId
+// can be slow.
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ do { \
+ } while (false)
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(p, s)
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
do { \
+ (void)(p); \
+ (void)(s); \
} while (false)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
do { \
+ (void)(p); \
+ (void)(s); \
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
@@ -144,8 +174,6 @@ static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
}
#if ASAN_INTERCEPT_PTHREAD_CREATE
-extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
-
INTERCEPTOR(int, pthread_create, void *thread,
void *attr, void *(*start_routine)(void*), void *arg) {
EnsureMainThreadIDIsCorrect();
@@ -155,7 +183,7 @@ INTERCEPTOR(int, pthread_create, void *thread,
GET_STACK_TRACE_THREAD;
int detached = 0;
if (attr != 0)
- pthread_attr_getdetachstate(attr, &detached);
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
u32 current_tid = GetCurrentTidOrInvalid();
AsanThread *t = AsanThread::Create(start_routine, arg);
@@ -256,7 +284,7 @@ static void MlockIsUnsupported() {
static bool printed = false;
if (printed) return;
printed = true;
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Printf("INFO: AddressSanitizer ignores "
"mlock/mlockall/munlock/munlockall\n");
}
@@ -645,16 +673,6 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
}
#endif // ASAN_INTERCEPT___CXA_ATEXIT
-#if !SANITIZER_MAC
-#define ASAN_INTERCEPT_FUNC(name) do { \
- if (!INTERCEPT_FUNCTION(name) && flags()->verbosity > 0) \
- Report("AddressSanitizer: failed to intercept '" #name "'\n"); \
- } while (0)
-#else
-// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
-#define ASAN_INTERCEPT_FUNC(name)
-#endif // SANITIZER_MAC
-
#if SANITIZER_WINDOWS
INTERCEPTOR_WINAPI(DWORD, CreateThread,
void* security, uptr stack_size,
@@ -767,7 +785,7 @@ void InitializeAsanInterceptors() {
InitializeWindowsInterceptors();
#endif
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Report("AddressSanitizer: libc interceptors initialized\n");
}
}
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index b5b48708090..ede273a7170 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -96,6 +96,7 @@ void StopInitOrderChecking();
void AsanTSDInit(void (*destructor)(void *tsd));
void *AsanTSDGet();
void AsanTSDSet(void *tsd);
+void PlatformTSDDtor(void *tsd);
void AppendToErrorMessageBuffer(const char *buffer);
@@ -133,6 +134,7 @@ const int kAsanStackPartialRedzoneMagic = 0xf4;
const int kAsanStackAfterReturnMagic = 0xf5;
const int kAsanInitializationOrderMagic = 0xf6;
const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanContiguousContainerOOBMagic = 0xfc;
const int kAsanStackUseAfterScopeMagic = 0xf8;
const int kAsanGlobalRedzoneMagic = 0xf9;
const int kAsanInternalHeapMagic = 0xfe;
diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc
index 10c6175092b..0692eb1f455 100644
--- a/libsanitizer/asan/asan_linux.cc
+++ b/libsanitizer/asan/asan_linux.cc
@@ -56,6 +56,12 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.arm_pc;
*bp = ucontext->uc_mcontext.arm_fp;
*sp = ucontext->uc_mcontext.arm_sp;
+# elif defined(__hppa__)
+ ucontext_t *ucontext = (ucontext_t*)context;
+ *pc = ucontext->uc_mcontext.sc_iaoq[0];
+ /* GCC uses %r3 whenever a frame pointer is needed. */
+ *bp = ucontext->uc_mcontext.sc_gr[3];
+ *sp = ucontext->uc_mcontext.sc_gr[30];
# elif defined(__x86_64__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index 4b28c1422cd..8d01843afaf 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -172,7 +172,7 @@ void MaybeReexec() {
// Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name.
setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0);
}
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("exec()-ing the program with\n");
Report("%s=%s\n", kDyldInsertLibraries, new_env);
Report("to enable ASan wrappers.\n");
@@ -309,7 +309,7 @@ extern "C"
void asan_dispatch_call_block_and_release(void *block) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *context = (asan_block_context_t*)block;
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("asan_dispatch_call_block_and_release(): "
"context: %p, pthread_self: %p\n",
block, pthread_self());
@@ -344,7 +344,7 @@ asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
dispatch_function_t func) { \
GET_STACK_TRACE_THREAD; \
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \
- if (flags()->verbosity >= 2) { \
+ if (common_flags()->verbosity >= 2) { \
Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \
asan_ctxt, pthread_self()); \
PRINT_CURRENT_STACK(); \
@@ -362,7 +362,7 @@ INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_after_f: %p\n", asan_ctxt);
PRINT_CURRENT_STACK();
}
@@ -375,7 +375,7 @@ INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
dispatch_function_t func) {
GET_STACK_TRACE_THREAD;
asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
asan_ctxt, pthread_self());
PRINT_CURRENT_STACK();
diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc
index 97691fcd361..e3495cb0900 100644
--- a/libsanitizer/asan/asan_malloc_linux.cc
+++ b/libsanitizer/asan/asan_malloc_linux.cc
@@ -103,8 +103,9 @@ INTERCEPTOR(void*, __libc_memalign, uptr align, uptr s)
ALIAS("memalign");
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
// We avoid including malloc.h for portability reasons.
diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc
index cabf8cd254c..1f2495ffc50 100644
--- a/libsanitizer/asan/asan_malloc_win.cc
+++ b/libsanitizer/asan/asan_malloc_win.cc
@@ -96,8 +96,9 @@ void* _recalloc(void* p, size_t n, size_t elem_size) {
SANITIZER_INTERFACE_ATTRIBUTE
size_t _msize(void *ptr) {
- GET_STACK_TRACE_MALLOC;
- return asan_malloc_usable_size(ptr, &stack);
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ return asan_malloc_usable_size(ptr, pc, bp);
}
int _CrtDbgReport(int, const char*, int,
diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc
index b967acded63..86d49909b68 100644
--- a/libsanitizer/asan/asan_poisoning.cc
+++ b/libsanitizer/asan/asan_poisoning.cc
@@ -12,6 +12,7 @@
#include "asan_poisoning.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_flags.h"
namespace __asan {
@@ -66,7 +67,7 @@ void __asan_poison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to poison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -108,7 +109,7 @@ void __asan_unpoison_memory_region(void const volatile *addr, uptr size) {
if (!flags()->allow_user_poisoning || size == 0) return;
uptr beg_addr = (uptr)addr;
uptr end_addr = beg_addr + size;
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Printf("Trying to unpoison memory region [%p, %p)\n",
(void*)beg_addr, (void*)end_addr);
}
@@ -242,13 +243,57 @@ static void PoisonAlignedStackMemory(uptr addr, uptr size, bool do_poison) {
}
void __asan_poison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("poisoning: %p %zx\n", (void*)addr, size);
PoisonAlignedStackMemory(addr, size, true);
}
void __asan_unpoison_stack_memory(uptr addr, uptr size) {
- if (flags()->verbosity > 0)
+ if (common_flags()->verbosity > 0)
Report("unpoisoning: %p %zx\n", (void*)addr, size);
PoisonAlignedStackMemory(addr, size, false);
}
+
+void __sanitizer_annotate_contiguous_container(const void *beg_p,
+ const void *end_p,
+ const void *old_mid_p,
+ const void *new_mid_p) {
+ if (common_flags()->verbosity >= 2)
+ Printf("contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+ new_mid_p);
+ uptr beg = reinterpret_cast<uptr>(beg_p);
+ uptr end= reinterpret_cast<uptr>(end_p);
+ uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
+ uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+ uptr granularity = SHADOW_GRANULARITY;
+ CHECK(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end &&
+ IsAligned(beg, granularity));
+ CHECK_LE(end - beg,
+ FIRST_32_SECOND_64(1UL << 30, 1UL << 34)); // Sanity check.
+
+ uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
+ uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
+ uptr d1 = RoundDownTo(old_mid, granularity);
+ uptr d2 = RoundUpTo(old_mid, granularity);
+ // Currently we should be in this state:
+ // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
+ // Make a quick sanity check that we are indeed in this state.
+ if (d1 != d2)
+ CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
+ if (a + granularity <= d1)
+ CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ if (d2 + granularity <= c && c <= end)
+ CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
+ kAsanContiguousContainerOOBMagic);
+
+ uptr b1 = RoundDownTo(new_mid, granularity);
+ uptr b2 = RoundUpTo(new_mid, granularity);
+ // New state:
+ // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
+ PoisonShadow(a, b1 - a, 0);
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+ if (b1 != b2) {
+ CHECK_EQ(b2 - b1, granularity);
+ *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+ }
+}
diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h
index 866c0a57c7e..da79a0ff2e4 100644
--- a/libsanitizer/asan/asan_poisoning.h
+++ b/libsanitizer/asan/asan_poisoning.h
@@ -41,6 +41,7 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
uptr aligned_addr, uptr size, uptr redzone_size, u8 value) {
DCHECK(flags()->poison_heap);
+ bool poison_partial = flags()->poison_partial;
u8 *shadow = (u8*)MEM_TO_SHADOW(aligned_addr);
for (uptr i = 0; i < redzone_size; i += SHADOW_GRANULARITY, shadow++) {
if (i + SHADOW_GRANULARITY <= size) {
@@ -49,7 +50,7 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
*shadow = (SHADOW_GRANULARITY == 128) ? 0xff : value; // unaddressable
} else {
// first size-i bytes are addressable
- *shadow = static_cast<u8>(size - i);
+ *shadow = poison_partial ? static_cast<u8>(size - i) : 0;
}
}
}
diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc
index a210a810036..ac4ec9e0191 100644
--- a/libsanitizer/asan/asan_posix.cc
+++ b/libsanitizer/asan/asan_posix.cc
@@ -1,4 +1,4 @@
-//===-- asan_linux.cc -----------------------------------------------------===//
+//===-- asan_posix.cc -----------------------------------------------------===//
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
@@ -42,7 +42,7 @@ static void MaybeInstallSigaction(int signum,
sigact.sa_flags = SA_SIGINFO;
if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
CHECK_EQ(0, REAL(sigaction)(signum, &sigact, 0));
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("Installed the sigaction for signal %d\n", signum);
}
}
@@ -69,7 +69,7 @@ void SetAlternateSignalStack() {
altstack.ss_flags = 0;
altstack.ss_size = kAltStackSize;
CHECK_EQ(0, sigaltstack(&altstack, 0));
- if (flags()->verbosity > 0) {
+ if (common_flags()->verbosity > 0) {
Report("Alternative stack for T%d set: [%p,%p)\n",
GetCurrentTidOrInvalid(),
altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
@@ -114,6 +114,15 @@ void AsanTSDSet(void *tsd) {
pthread_setspecific(tsd_key, tsd);
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThreadContext *context = (AsanThreadContext*)tsd;
+ if (context->destructor_iterations > 1) {
+ context->destructor_iterations--;
+ CHECK_EQ(0, pthread_setspecific(tsd_key, tsd));
+ return;
+ }
+ AsanThread::TSDDtor(tsd);
+}
} // namespace __asan
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index 8f11ff4eac3..70c4b481a2f 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -18,6 +18,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
namespace __asan {
@@ -71,6 +72,7 @@ class Decorator: private __sanitizer::AnsiColorDecorator {
case kAsanInitializationOrderMagic:
return Cyan();
case kAsanUserPoisonedMemoryMagic:
+ case kAsanContiguousContainerOOBMagic:
return Blue();
case kAsanStackUseAfterScopeMagic:
return Magenta();
@@ -117,19 +119,21 @@ static void PrintLegend() {
for (u8 i = 1; i < SHADOW_GRANULARITY; i++)
PrintShadowByte("", i, " ");
Printf("\n");
- PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
- PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
- PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
- PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
- PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
- PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
- PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
- PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
- PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
- PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
- PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
- PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
- PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
+ PrintShadowByte(" Heap left redzone: ", kAsanHeapLeftRedzoneMagic);
+ PrintShadowByte(" Heap right redzone: ", kAsanHeapRightRedzoneMagic);
+ PrintShadowByte(" Freed heap region: ", kAsanHeapFreeMagic);
+ PrintShadowByte(" Stack left redzone: ", kAsanStackLeftRedzoneMagic);
+ PrintShadowByte(" Stack mid redzone: ", kAsanStackMidRedzoneMagic);
+ PrintShadowByte(" Stack right redzone: ", kAsanStackRightRedzoneMagic);
+ PrintShadowByte(" Stack partial redzone: ", kAsanStackPartialRedzoneMagic);
+ PrintShadowByte(" Stack after return: ", kAsanStackAfterReturnMagic);
+ PrintShadowByte(" Stack use after scope: ", kAsanStackUseAfterScopeMagic);
+ PrintShadowByte(" Global redzone: ", kAsanGlobalRedzoneMagic);
+ PrintShadowByte(" Global init order: ", kAsanInitializationOrderMagic);
+ PrintShadowByte(" Poisoned by user: ", kAsanUserPoisonedMemoryMagic);
+ PrintShadowByte(" Contiguous container OOB:",
+ kAsanContiguousContainerOOBMagic);
+ PrintShadowByte(" ASan internal: ", kAsanInternalHeapMagic);
}
static void PrintShadowMemoryForAddress(uptr addr) {
@@ -178,8 +182,8 @@ static bool IsASCII(unsigned char c) {
static const char *MaybeDemangleGlobalName(const char *name) {
// We can spoil names of globals with C linkage, so use an heuristic
// approach to check if the name should be demangled.
- return (name[0] == '_' && name[1] == 'Z' && &getSymbolizer)
- ? getSymbolizer()->Demangle(name)
+ return (name[0] == '_' && name[1] == 'Z')
+ ? Symbolizer::Get()->Demangle(name)
: name;
}
@@ -412,7 +416,11 @@ static void DescribeAccessToHeapChunk(AsanChunkView chunk, uptr addr,
void DescribeHeapAddress(uptr addr, uptr access_size) {
AsanChunkView chunk = FindHeapChunkByAddress(addr);
- if (!chunk.IsValid()) return;
+ if (!chunk.IsValid()) {
+ Printf("AddressSanitizer can not describe address in more detail "
+ "(wild memory access suspected).\n");
+ return;
+ }
DescribeAccessToHeapChunk(chunk, addr, access_size);
CHECK(chunk.AllocTid() != kInvalidTid);
asanThreadRegistry().CheckLocked();
@@ -479,7 +487,9 @@ void DescribeThread(AsanThreadContext *context) {
context->parent_tid,
ThreadNameWithParenthesis(context->parent_tid,
tname, sizeof(tname)));
- PrintStack(&context->stack);
+ uptr stack_size;
+ const uptr *stack_trace = StackDepotGet(context->stack_id, &stack_size);
+ PrintStack(stack_trace, stack_size);
// Recursively described parent thread if needed.
if (flags()->print_full_thread_history) {
AsanThreadContext *parent_context =
@@ -540,22 +550,6 @@ class ScopedInErrorReport {
}
};
-static void ReportSummary(const char *error_type, StackTrace *stack) {
- if (!stack->size) return;
- if (&getSymbolizer && getSymbolizer()->IsAvailable()) {
- 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).
- uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
- getSymbolizer()->SymbolizeCode(pc, &ai, 1);
- ReportErrorSummary(error_type,
- StripPathPrefix(ai.file,
- common_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;
@@ -565,13 +559,13 @@ void ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr) {
(void*)addr, (void*)pc, (void*)sp, (void*)bp,
GetCurrentTidOrInvalid());
Printf("%s", d.EndWarning());
- Printf("AddressSanitizer can not provide additional info.\n");
GET_STACK_TRACE_FATAL(pc, bp);
PrintStack(&stack);
- ReportSummary("SEGV", &stack);
+ Printf("AddressSanitizer can not provide additional info.\n");
+ ReportErrorSummary("SEGV", &stack);
}
-void ReportDoubleFree(uptr addr, StackTrace *stack) {
+void ReportDoubleFree(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -581,14 +575,15 @@ void ReportDoubleFree(uptr addr, StackTrace *stack) {
"thread T%d%s:\n",
addr, curr_tid,
ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
-
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("double-free", stack);
+ ReportErrorSummary("double-free", &stack);
}
-void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
+void ReportFreeNotMalloced(uptr addr, StackTrace *free_stack) {
ScopedInErrorReport in_report;
Decorator d;
Printf("%s", d.Warning());
@@ -598,12 +593,14 @@ void ReportFreeNotMalloced(uptr addr, StackTrace *stack) {
"which was not malloc()-ed: %p in thread T%d%s\n", addr,
curr_tid, ThreadNameWithParenthesis(curr_tid, tname, sizeof(tname)));
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-free", stack);
+ ReportErrorSummary("bad-free", &stack);
}
-void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type) {
static const char *alloc_names[] =
@@ -617,9 +614,11 @@ void ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
alloc_names[alloc_type], dealloc_names[dealloc_type], addr);
Printf("%s", d.EndWarning());
- PrintStack(stack);
+ CHECK_GT(free_stack->size, 0);
+ GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
+ PrintStack(&stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("alloc-dealloc-mismatch", stack);
+ ReportErrorSummary("alloc-dealloc-mismatch", &stack);
Report("HINT: if you don't care about these warnings you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
}
@@ -634,7 +633,7 @@ void ReportMallocUsableSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-malloc_usable_size", stack);
+ ReportErrorSummary("bad-malloc_usable_size", stack);
}
void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
@@ -647,7 +646,7 @@ void ReportAsanGetAllocatedSizeNotOwned(uptr addr, StackTrace *stack) {
Printf("%s", d.EndWarning());
PrintStack(stack);
DescribeHeapAddress(addr, 1);
- ReportSummary("bad-__asan_get_allocated_size", stack);
+ ReportErrorSummary("bad-__asan_get_allocated_size", stack);
}
void ReportStringFunctionMemoryRangesOverlap(
@@ -665,7 +664,7 @@ void ReportStringFunctionMemoryRangesOverlap(
PrintStack(stack);
DescribeAddress((uptr)offset1, length1);
DescribeAddress((uptr)offset2, length2);
- ReportSummary(bug_type, stack);
+ ReportErrorSummary(bug_type, stack);
}
// ----------------------- Mac-specific reports ----------------- {{{1
@@ -747,6 +746,9 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
case kAsanUserPoisonedMemoryMagic:
bug_descr = "use-after-poison";
break;
+ case kAsanContiguousContainerOOBMagic:
+ bug_descr = "container-overflow";
+ break;
case kAsanStackUseAfterScopeMagic:
bug_descr = "stack-use-after-scope";
break;
@@ -775,7 +777,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp,
PrintStack(&stack);
DescribeAddress(addr, access_size);
- ReportSummary(bug_descr, &stack);
+ ReportErrorSummary(bug_descr, &stack);
PrintShadowMemoryForAddress(addr);
}
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index afe7673304c..e4c756e557f 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -31,9 +31,9 @@ void DescribeThread(AsanThreadContext *context);
// Different kinds of error reports.
void NORETURN ReportSIGSEGV(uptr pc, uptr sp, uptr bp, uptr addr);
-void NORETURN ReportDoubleFree(uptr addr, StackTrace *stack);
-void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *stack);
-void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *stack,
+void NORETURN ReportDoubleFree(uptr addr, StackTrace *free_stack);
+void NORETURN ReportFreeNotMalloced(uptr addr, StackTrace *free_stack);
+void NORETURN ReportAllocTypeMismatch(uptr addr, StackTrace *free_stack,
AllocType alloc_type,
AllocType dealloc_type);
void NORETURN ReportMallocUsableSizeNotOwned(uptr addr,
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 67327611e84..537d40612aa 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -49,6 +49,8 @@ static void AsanDie() {
UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg);
}
}
+ if (flags()->coverage)
+ __sanitizer_cov_dump();
if (death_callback)
death_callback();
if (flags()->abort_on_error)
@@ -86,11 +88,11 @@ static const char *MaybeUseAsanDefaultOptionsCompileDefiniton() {
}
static void ParseFlagsFromString(Flags *f, const char *str) {
- ParseCommonFlagsFromString(str);
- CHECK((uptr)common_flags()->malloc_context_size <= kStackTraceMax);
+ CommonFlags *cf = common_flags();
+ ParseCommonFlagsFromString(cf, str);
+ CHECK((uptr)cf->malloc_context_size <= kStackTraceMax);
ParseFlag(str, &f->quarantine_size, "quarantine_size");
- ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->redzone, "redzone");
CHECK_GE(f->redzone, 16);
CHECK(IsPowerOfTwo(f->redzone));
@@ -119,32 +121,25 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->print_stats, "print_stats");
ParseFlag(str, &f->print_legend, "print_legend");
ParseFlag(str, &f->atexit, "atexit");
+ ParseFlag(str, &f->coverage, "coverage");
ParseFlag(str, &f->disable_core, "disable_core");
ParseFlag(str, &f->allow_reexec, "allow_reexec");
ParseFlag(str, &f->print_full_thread_history, "print_full_thread_history");
ParseFlag(str, &f->poison_heap, "poison_heap");
+ ParseFlag(str, &f->poison_partial, "poison_partial");
ParseFlag(str, &f->alloc_dealloc_mismatch, "alloc_dealloc_mismatch");
- ParseFlag(str, &f->use_stack_depot, "use_stack_depot");
ParseFlag(str, &f->strict_memcmp, "strict_memcmp");
ParseFlag(str, &f->strict_init_order, "strict_init_order");
}
void InitializeFlags(Flags *f, const char *env) {
CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
- cf->symbolize = true;
cf->malloc_context_size = kDefaultMallocContextSize;
- cf->fast_unwind_on_fatal = false;
- cf->fast_unwind_on_malloc = true;
- cf->strip_path_prefix = "";
- cf->handle_ioctl = false;
- cf->log_path = 0;
- cf->detect_leaks = false;
- cf->leak_check_at_exit = true;
internal_memset(f, 0, sizeof(*f));
f->quarantine_size = (ASAN_LOW_MEMORY) ? 1UL << 26 : 1UL << 28;
- f->verbosity = 0;
f->redzone = 16;
f->debug = false;
f->report_globals = 1;
@@ -168,14 +163,15 @@ void InitializeFlags(Flags *f, const char *env) {
f->print_stats = false;
f->print_legend = true;
f->atexit = false;
+ f->coverage = false;
f->disable_core = (SANITIZER_WORDSIZE == 64);
f->allow_reexec = true;
f->print_full_thread_history = true;
f->poison_heap = true;
+ f->poison_partial = true;
// Turn off alloc/dealloc mismatch checker on Mac and Windows for now.
// TODO(glider,timurrrr): Fix known issues and enable this back.
f->alloc_dealloc_mismatch = (SANITIZER_MAC == 0) && (SANITIZER_WINDOWS == 0);
- f->use_stack_depot = true;
f->strict_memcmp = true;
f->strict_init_order = false;
@@ -184,7 +180,7 @@ void InitializeFlags(Flags *f, const char *env) {
// Override from user-specified string.
ParseFlagsFromString(f, MaybeCallAsanDefaultOptions());
- if (flags()->verbosity) {
+ if (cf->verbosity) {
Report("Using the defaults from __asan_default_options: %s\n",
MaybeCallAsanDefaultOptions());
}
@@ -200,10 +196,10 @@ void InitializeFlags(Flags *f, const char *env) {
}
#endif
- if (cf->detect_leaks && !f->use_stack_depot) {
- Report("%s: detect_leaks is ignored (requires use_stack_depot).\n",
- SanitizerToolName);
- cf->detect_leaks = false;
+ // Make "strict_init_order" imply "check_initialization_order".
+ // TODO(samsonov): Use a single runtime flag for an init-order checker.
+ if (f->strict_init_order) {
+ f->check_initialization_order = true;
}
}
@@ -462,7 +458,7 @@ void __asan_init() {
__asan_option_detect_stack_use_after_return =
flags()->detect_stack_use_after_return;
- if (flags()->verbosity && options) {
+ if (common_flags()->verbosity && options) {
Report("Parsed ASAN_OPTIONS: %s\n", options);
}
@@ -472,11 +468,6 @@ void __asan_init() {
// Setup internal allocator callback.
SetLowLevelAllocateCallback(OnLowLevelAllocate);
- if (flags()->atexit) {
- Atexit(asan_atexit);
- }
-
- // interceptors
InitializeAsanInterceptors();
ReplaceSystemMalloc();
@@ -495,7 +486,7 @@ void __asan_init() {
}
#endif
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
PrintAddressSpaceLayout();
if (flags()->disable_core) {
@@ -531,17 +522,18 @@ void __asan_init() {
Die();
}
+ AsanTSDInit(PlatformTSDDtor);
InstallSignalHandlers();
- AsanTSDInit(AsanThread::TSDDtor);
// Allocator should be initialized before starting external symbolizer, as
// fork() on Mac locks the allocator.
InitializeAllocator();
// Start symbolizer process if necessary.
- if (common_flags()->symbolize && &getSymbolizer) {
- getSymbolizer()
- ->InitializeExternal(common_flags()->external_symbolizer_path);
+ if (common_flags()->symbolize) {
+ Symbolizer::Init(common_flags()->external_symbolizer_path);
+ } else {
+ Symbolizer::Disable();
}
// On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
@@ -549,6 +541,13 @@ void __asan_init() {
asan_inited = 1;
asan_init_is_running = false;
+ if (flags()->atexit)
+ Atexit(asan_atexit);
+
+ if (flags()->coverage)
+ Atexit(__sanitizer_cov_dump);
+
+ // interceptors
InitTlsSize();
// Create main thread.
@@ -568,7 +567,7 @@ void __asan_init() {
}
#endif // CAN_SANITIZE_LEAKS
- if (flags()->verbosity) {
+ if (common_flags()->verbosity) {
Report("AddressSanitizer Init done\n");
}
}
diff --git a/libsanitizer/asan/asan_stack.cc b/libsanitizer/asan/asan_stack.cc
index 74952518642..93671a03a92 100644
--- a/libsanitizer/asan/asan_stack.cc
+++ b/libsanitizer/asan/asan_stack.cc
@@ -22,9 +22,12 @@ static bool MaybeCallAsanSymbolize(const void *pc, char *out_buffer,
: false;
}
+void PrintStack(const uptr *trace, uptr size) {
+ StackTrace::PrintStack(trace, size, MaybeCallAsanSymbolize);
+}
+
void PrintStack(StackTrace *stack) {
- stack->PrintStack(stack->trace, stack->size, common_flags()->symbolize,
- common_flags()->strip_path_prefix, MaybeCallAsanSymbolize);
+ PrintStack(stack->trace, stack->size);
}
} // namespace __asan
diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
index 3c0ac31f6c6..c929c887d06 100644
--- a/libsanitizer/asan/asan_stack.h
+++ b/libsanitizer/asan/asan_stack.h
@@ -20,6 +20,7 @@
namespace __asan {
void PrintStack(StackTrace *stack);
+void PrintStack(const uptr *trace, uptr size);
} // namespace __asan
@@ -29,19 +30,24 @@ void PrintStack(StackTrace *stack);
#if SANITIZER_WINDOWS
#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
StackTrace stack; \
- GetStackTrace(&stack, max_s, pc, bp, 0, 0, fast)
+ stack.Unwind(max_s, pc, bp, 0, 0, fast)
#else
-#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
- StackTrace stack; \
- { \
- AsanThread *t; \
- stack.size = 0; \
- if (asan_inited && (t = GetCurrentThread()) && !t->isUnwinding()) { \
- uptr stack_top = t->stack_top(); \
- uptr stack_bottom = t->stack_bottom(); \
- ScopedUnwinding unwind_scope(t); \
- GetStackTrace(&stack, max_s, pc, bp, stack_top, stack_bottom, fast); \
- } \
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, pc, bp, fast) \
+ StackTrace stack; \
+ { \
+ AsanThread *t; \
+ stack.size = 0; \
+ if (asan_inited) { \
+ if ((t = GetCurrentThread()) && !t->isUnwinding()) { \
+ uptr stack_top = t->stack_top(); \
+ uptr stack_bottom = t->stack_bottom(); \
+ ScopedUnwinding unwind_scope(t); \
+ stack.Unwind(max_s, pc, bp, stack_top, stack_bottom, fast); \
+ } else if (t == 0 && !fast) { \
+ /* If GetCurrentThread() has failed, try to do slow unwind anyways. */ \
+ stack.Unwind(max_s, pc, bp, 0, 0, false); \
+ } \
+ } \
}
#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/asan/asan_stats.h b/libsanitizer/asan/asan_stats.h
index 2f964f8d052..5b04b1718eb 100644
--- a/libsanitizer/asan/asan_stats.h
+++ b/libsanitizer/asan/asan_stats.h
@@ -45,9 +45,9 @@ struct AsanStats {
uptr malloc_large;
uptr malloc_small_slow;
- // Ctor for global AsanStats (accumulated stats and main thread stats).
+ // Ctor for global AsanStats (accumulated stats for dead threads).
explicit AsanStats(LinkerInitialized) { }
- // Default ctor for thread-local stats.
+ // Creates empty stats.
AsanStats();
void Print(); // Prints formatted stats to stderr.
diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc
index 1da714c6013..5a9c2dddffb 100644
--- a/libsanitizer/asan/asan_thread.cc
+++ b/libsanitizer/asan/asan_thread.cc
@@ -17,6 +17,7 @@
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "lsan/lsan_common.h"
namespace __asan {
@@ -25,9 +26,8 @@ namespace __asan {
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
- if (args->stack) {
- internal_memcpy(&stack, args->stack, sizeof(stack));
- }
+ if (args->stack)
+ stack_id = StackDepotPut(args->stack->trace, args->stack->size);
thread = args->thread;
thread->set_context(this);
}
@@ -41,9 +41,12 @@ void AsanThreadContext::OnFinished() {
static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
static ThreadRegistry *asan_thread_registry;
+static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED);
+static LowLevelAllocator allocator_for_thread_context;
+
static ThreadContextBase *GetAsanThreadContext(u32 tid) {
- void *mem = MmapOrDie(sizeof(AsanThreadContext), "AsanThreadContext");
- return new(mem) AsanThreadContext(tid);
+ BlockingMutexLock lock(&mu_for_thread_context);
+ return new(allocator_for_thread_context) AsanThreadContext(tid);
}
ThreadRegistry &asanThreadRegistry() {
@@ -76,24 +79,25 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine,
AsanThread *thread = (AsanThread*)MmapOrDie(size, __FUNCTION__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- thread->context_ = 0;
return thread;
}
void AsanThread::TSDDtor(void *tsd) {
AsanThreadContext *context = (AsanThreadContext*)tsd;
- if (flags()->verbosity >= 1)
+ if (common_flags()->verbosity >= 1)
Report("T%d TSDDtor\n", context->tid);
if (context->thread)
context->thread->Destroy();
}
void AsanThread::Destroy() {
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
Report("T%d exited\n", tid());
}
+ malloc_storage().CommitBack();
+ if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
asanThreadRegistry().FinishThread(tid());
FlushToDeadThreadStats(&stats_);
// We also clear the shadow on thread destruction because
@@ -136,7 +140,7 @@ void AsanThread::Init() {
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
ClearShadowForThreadStackAndTLS();
- if (flags()->verbosity >= 1) {
+ if (common_flags()->verbosity >= 1) {
int local = 0;
Report("T%d: stack [%p,%p) size 0x%zx; local=%p\n",
tid(), (void*)stack_bottom_, (void*)stack_top_,
@@ -160,10 +164,14 @@ thread_return_t AsanThread::ThreadStart(uptr os_id) {
}
thread_return_t res = start_routine_(arg_);
- malloc_storage().CommitBack();
- if (flags()->use_sigaltstack) UnsetAlternateSignalStack();
- this->Destroy();
+ // On POSIX systems we defer this to the TSD destructor. LSan will consider
+ // the thread's memory as non-live from the moment we call Destroy(), even
+ // though that memory might contain pointers to heap objects which will be
+ // cleaned up by a user-defined TSD destructor. Thus, calling Destroy() before
+ // the TSD destructors have run might cause false positives in LSan.
+ if (!SANITIZER_POSIX)
+ this->Destroy();
return res;
}
@@ -257,7 +265,7 @@ AsanThread *GetCurrentThread() {
void SetCurrentThread(AsanThread *t) {
CHECK(t->context());
- if (flags()->verbosity >= 2) {
+ if (common_flags()->verbosity >= 2) {
Report("SetCurrentThread: %p for thread %p\n",
t->context(), (void*)GetThreadSelf());
}
@@ -286,6 +294,13 @@ void EnsureMainThreadIDIsCorrect() {
if (context && (context->tid == 0))
context->os_id = GetTid();
}
+
+__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+ __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
+ __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
+ if (!context) return 0;
+ return context->thread;
+}
} // namespace __asan
// --- Implementation of LSan-specific functions --- {{{1
@@ -293,10 +308,7 @@ namespace __lsan {
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end) {
- __asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
- __asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
- if (!context) return false;
- __asan::AsanThread *t = context->thread;
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (!t) return false;
*stack_begin = t->stack_bottom();
*stack_end = t->stack_top();
@@ -308,6 +320,13 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+ __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
+ if (t && t->has_fake_stack())
+ t->fake_stack()->ForEachFakeFrame(callback, arg);
+}
+
void LockThreadRegistry() {
__asan::asanThreadRegistry().Lock();
}
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index f21971ff430..5a917fa9a3d 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -17,6 +17,7 @@
#include "asan_fake_stack.h"
#include "asan_stack.h"
#include "asan_stats.h"
+#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
@@ -34,11 +35,13 @@ class AsanThreadContext : public ThreadContextBase {
explicit AsanThreadContext(int tid)
: ThreadContextBase(tid),
announced(false),
+ destructor_iterations(kPthreadDestructorIterations),
+ stack_id(0),
thread(0) {
- internal_memset(&stack, 0, sizeof(stack));
}
bool announced;
- StackTrace stack;
+ u8 destructor_iterations;
+ u32 stack_id;
AsanThread *thread;
void OnCreated(void *arg);
@@ -46,7 +49,7 @@ class AsanThreadContext : public ThreadContextBase {
};
// AsanThreadContext objects are never freed, so we need many of them.
-COMPILER_CHECK(sizeof(AsanThreadContext) <= 4096);
+COMPILER_CHECK(sizeof(AsanThreadContext) <= 256);
// AsanThread are stored in TSD and destroyed when the thread dies.
class AsanThread {
@@ -96,14 +99,15 @@ class AsanThread {
// True is this thread is currently unwinding stack (i.e. collecting a stack
// trace). Used to prevent deadlocks on platforms where libc unwinder calls
// malloc internally. See PR17116 for more details.
- bool isUnwinding() const { return unwinding; }
- void setUnwinding(bool b) { unwinding = b; }
+ bool isUnwinding() const { return unwinding_; }
+ void setUnwinding(bool b) { unwinding_ = b; }
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
- AsanThread() : unwinding(false) {}
+ // NOTE: There is no AsanThread constructor. It is allocated
+ // via mmap() and *must* be valid in zero-initialized state.
void SetThreadStackAndTls();
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -111,18 +115,18 @@ class AsanThread {
AsanThreadContext *context_;
thread_callback_t start_routine_;
void *arg_;
- uptr stack_top_;
- uptr stack_bottom_;
+ uptr stack_top_;
+ uptr stack_bottom_;
// stack_size_ == stack_top_ - stack_bottom_;
// It needs to be set in a async-signal-safe manner.
- uptr stack_size_;
+ uptr stack_size_;
uptr tls_begin_;
uptr tls_end_;
FakeStack *fake_stack_;
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
- bool unwinding;
+ bool unwinding_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc
index ed785b69281..8ffa58faa37 100644
--- a/libsanitizer/asan/asan_win.cc
+++ b/libsanitizer/asan/asan_win.cc
@@ -58,6 +58,9 @@ void AsanTSDSet(void *tsd) {
fake_tsd = tsd;
}
+void PlatformTSDDtor(void *tsd) {
+ AsanThread::TSDDtor(tsd);
+}
// ---------------------- Various stuff ---------------- {{{1
void MaybeReexec() {
// No need to re-exec on Windows.
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index a7db2ff1c12..956cb86d697 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -25,10 +25,6 @@ extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
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);
-
// 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.
@@ -49,6 +45,44 @@ extern "C" {
void __sanitizer_unaligned_store32(void *p, uint32_t x);
void __sanitizer_unaligned_store64(void *p, uint64_t x);
+ // Record and dump coverage info.
+ void __sanitizer_cov_dump();
+
+ // Annotate the current state of a contiguous container, such as
+ // std::vector, std::string or similar.
+ // A contiguous container is a container that keeps all of its elements
+ // in a contiguous region of memory. The container owns the region of memory
+ // [beg, end); the memory [beg, mid) is used to store the current elements
+ // and the memory [mid, end) is reserved for future elements;
+ // end <= mid <= end. For example, in "std::vector<> v"
+ // beg = &v[0];
+ // end = beg + v.capacity() * sizeof(v[0]);
+ // mid = beg + v.size() * sizeof(v[0]);
+ //
+ // This annotation tells the Sanitizer tool about the current state of the
+ // container so that the tool can report errors when memory from [mid, end)
+ // is accessed. Insert this annotation into methods like push_back/pop_back.
+ // Supply the old and the new values of mid (old_mid/new_mid).
+ // In the initial state mid == end and so should be the final
+ // state when the container is destroyed or when it reallocates the storage.
+ //
+ // Use with caution and don't use for anything other than vector-like classes.
+ //
+ // For AddressSanitizer, 'beg' should be 8-aligned and 'end' should
+ // be either 8-aligned or it should point to the end of a separate heap-,
+ // stack-, or global- allocated buffer. I.e. the following will not work:
+ // int64_t x[2]; // 16 bytes, 8-aligned.
+ // char *beg = (char *)&x[0];
+ // char *end = beg + 12; // Not 8 aligned, not the end of the buffer.
+ // This however will work fine:
+ // int32_t x[3]; // 12 bytes, but 8-aligned under AddressSanitizer.
+ // char *beg = (char*)&x[0];
+ // char *end = beg + 12; // Not 8-aligned, but is the end of the buffer.
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
index 6cd7d7626b8..17742b6c1c4 100644
--- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
+++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
@@ -985,10 +985,11 @@
#else
#define __sanitizer_syscall_pre_pread64(fd, buf, count, pos0, pos1) \
__sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \
- (long)(pos))
+ (long)(pos0), (long)(pos1))
#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \
__sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \
- (long)(count), (long)(pos))
+ (long)(count), (long)(pos0), \
+ (long)(pos1))
#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \
__sanitizer_syscall_pre_impl_pwrite64( \
(long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1))
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index 71740c5c403..7393f4c26be 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -236,12 +236,18 @@ typedef unsigned long uptr; // NOLINT
#if defined(__linux__)
# include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_LINUX(func, symver)
#elif defined(__APPLE__)
# include "interception_mac.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_MAC(func, symver)
#else // defined(_WIN32)
# include "interception_win.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
+# define INTERCEPT_FUNCTION_VER(func, symver) \
+ INTERCEPT_FUNCTION_VER_WIN(func, symver)
#endif
#undef INCLUDED_FROM_INTERCEPTION_LIB
diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
index fbbfecbe037..5ab24db438e 100644
--- a/libsanitizer/interception/interception_linux.h
+++ b/libsanitizer/interception/interception_linux.h
@@ -33,9 +33,12 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
(::__interception::uptr)&WRAP(func))
#if !defined(__ANDROID__) // android does not have dlvsym
-#define INTERCEPT_FUNCTION_VER(func, symver) \
- ::__interception::real_##func = (func##_f)(unsigned long) \
- ::__interception::GetFuncAddrVer(#func, #symver)
+# define INTERCEPT_FUNCTION_VER_LINUX(func, symver) \
+ ::__interception::real_##func = (func##_f)(unsigned long) \
+ ::__interception::GetFuncAddrVer(#func, symver)
+#else
+# define INTERCEPT_FUNCTION_VER_LINUX(func, symver) \
+ INTERCEPT_FUNCTION_LINUX(func)
#endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H
diff --git a/libsanitizer/interception/interception_mac.h b/libsanitizer/interception/interception_mac.h
index 1b11182da98..fbcb473b579 100644
--- a/libsanitizer/interception/interception_mac.h
+++ b/libsanitizer/interception/interception_mac.h
@@ -20,6 +20,7 @@
#define INTERCEPTION_MAC_H
#define INTERCEPT_FUNCTION_MAC(func)
+#define INTERCEPT_FUNCTION_VER_MAC(func, symver)
#endif // INTERCEPTION_MAC_H
#endif // __APPLE__
diff --git a/libsanitizer/interception/interception_win.h b/libsanitizer/interception/interception_win.h
index ebac168d85a..b46ad0dc66f 100644
--- a/libsanitizer/interception/interception_win.h
+++ b/libsanitizer/interception/interception_win.h
@@ -39,5 +39,8 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func);
(::__interception::uptr*)&REAL(func))
#endif
+#define INTERCEPT_FUNCTION_VER_WIN(func, symver) \
+ INTERCEPT_FUNCTION_WIN(func)
+
#endif // INTERCEPTION_WIN_H
#endif // _WIN32
diff --git a/libsanitizer/lsan/Makefile.am b/libsanitizer/lsan/Makefile.am
index 36fd6058841..4784d7cbdc3 100644
--- a/libsanitizer/lsan/Makefile.am
+++ b/libsanitizer/lsan/Makefile.am
@@ -22,6 +22,7 @@ lsan_files = \
lsan.cc \
lsan_allocator.cc \
lsan_interceptors.cc \
+ lsan_preinit.cc \
lsan_thread.cc
libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index 9296b7048ab..b09469e0990 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -83,7 +83,7 @@ liblsan_la_DEPENDENCIES = \
$(am__DEPENDENCIES_1)
am__objects_1 = lsan_common.lo lsan_common_linux.lo
am__objects_2 = $(am__objects_1) lsan.lo lsan_allocator.lo \
- lsan_interceptors.lo lsan_thread.lo
+ lsan_interceptors.lo lsan_preinit.lo lsan_thread.lo
am_liblsan_la_OBJECTS = $(am__objects_2)
liblsan_la_OBJECTS = $(am_liblsan_la_OBJECTS)
liblsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -264,6 +264,7 @@ lsan_files = \
lsan.cc \
lsan_allocator.cc \
lsan_interceptors.cc \
+ lsan_preinit.cc \
lsan_thread.cc
libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
@@ -400,6 +401,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_interceptors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_preinit.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_thread.Plo@am__quote@
.cc.o:
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc
index 500da50622c..270979a78e7 100644
--- a/libsanitizer/lsan/lsan.cc
+++ b/libsanitizer/lsan/lsan.cc
@@ -18,26 +18,30 @@
#include "lsan_common.h"
#include "lsan_thread.h"
+bool lsan_inited;
+bool lsan_init_is_running;
+
namespace __lsan {
static void InitializeCommonFlags() {
CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
cf->external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH");
- cf->symbolize = true;
- cf->strip_path_prefix = "";
- cf->fast_unwind_on_malloc = true;
cf->malloc_context_size = 30;
cf->detect_leaks = true;
- cf->leak_check_at_exit = true;
- ParseCommonFlagsFromString(GetEnv("LSAN_OPTIONS"));
+ ParseCommonFlagsFromString(cf, GetEnv("LSAN_OPTIONS"));
}
-void Init() {
- static bool inited;
- if (inited)
+} // namespace __lsan
+
+using namespace __lsan; // NOLINT
+
+extern "C" void __lsan_init() {
+ CHECK(!lsan_init_is_running);
+ if (lsan_inited)
return;
- inited = true;
+ lsan_init_is_running = true;
SanitizerToolName = "LeakSanitizer";
InitializeCommonFlags();
InitializeAllocator();
@@ -51,13 +55,14 @@ void Init() {
// Start symbolizer process if necessary.
if (common_flags()->symbolize) {
- getSymbolizer()
- ->InitializeExternal(common_flags()->external_symbolizer_path);
+ Symbolizer::Init(common_flags()->external_symbolizer_path);
+ } else {
+ Symbolizer::Disable();
}
InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit)
Atexit(DoLeakCheck);
+ lsan_inited = true;
+ lsan_init_is_running = false;
}
-
-} // namespace __lsan
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index 18ff5da6281..8a5030ce878 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -15,7 +15,11 @@
namespace __lsan {
-void Init();
void InitializeInterceptors();
} // namespace __lsan
+
+extern bool lsan_inited;
+extern bool lsan_init_is_running;
+
+extern "C" void __lsan_init();
diff --git a/libsanitizer/lsan/lsan_allocator.cc b/libsanitizer/lsan/lsan_allocator.cc
index 66af603e656..ce47dfcd215 100644
--- a/libsanitizer/lsan/lsan_allocator.cc
+++ b/libsanitizer/lsan/lsan_allocator.cc
@@ -18,6 +18,8 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "lsan_common.h"
+extern "C" void *memset(void *ptr, int value, uptr num);
+
namespace __lsan {
static const uptr kMaxAllowedMallocSize = 8UL << 30;
@@ -32,7 +34,7 @@ struct ChunkMetadata {
};
typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
- sizeof(ChunkMetadata), CompactSizeClassMap> PrimaryAllocator;
+ sizeof(ChunkMetadata), DefaultSizeClassMap> PrimaryAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
@@ -78,7 +80,10 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
return 0;
}
- void *p = allocator.Allocate(&cache, size, alignment, cleared);
+ void *p = allocator.Allocate(&cache, size, alignment, false);
+ // Do not rely on the allocator to clear the memory (it's slow).
+ if (cleared && allocator.FromPrimary(p))
+ memset(p, 0, size);
RegisterAllocation(stack, p, size);
return p;
}
diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc
index ce82430f48b..bbc5b5f0378 100644
--- a/libsanitizer/lsan/lsan_common.cc
+++ b/libsanitizer/lsan/lsan_common.cc
@@ -91,8 +91,12 @@ void InitializeSuppressions() {
void InitCommonLsan() {
InitializeFlags();
- InitializeSuppressions();
- InitializePlatformSpecificModules();
+ if (common_flags()->detect_leaks) {
+ // Initialization which can fail or print warnings should only be done if
+ // LSan is actually enabled.
+ InitializeSuppressions();
+ InitializePlatformSpecificModules();
+ }
}
class Decorator: private __sanitizer::AnsiColorDecorator {
@@ -136,6 +140,8 @@ void ScanRangeForPointers(uptr begin, uptr end,
if (!CanBeAHeapPointer(reinterpret_cast<uptr>(p))) continue;
uptr chunk = PointsIntoChunk(p);
if (!chunk) continue;
+ // Pointers to self don't count. This matters when tag == kIndirectlyLeaked.
+ if (chunk == begin) continue;
LsanMetadata m(chunk);
// Reachable beats ignored beats leaked.
if (m.tag() == kReachable) continue;
@@ -149,6 +155,11 @@ void ScanRangeForPointers(uptr begin, uptr end,
}
}
+void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
+ Frontier *frontier = reinterpret_cast<Frontier *>(arg);
+ ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
+}
+
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
@@ -197,6 +208,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
kReachable);
+ ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
}
if (flags()->use_tls) {
@@ -261,6 +273,8 @@ static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
// The check here is relatively expensive, so we do this in a separate flood
// fill. That way we can skip the check for chunks that are reachable
// otherwise.
+ if (flags()->log_pointers)
+ Report("Processing platform-specific allocations.\n");
ProcessPlatformSpecificAllocations(&frontier);
FloodFillTag(&frontier, kReachable);
@@ -281,8 +295,7 @@ static void PrintStackTraceById(u32 stack_trace_id) {
CHECK(stack_trace_id);
uptr size = 0;
const uptr *trace = StackDepotGet(stack_trace_id, &size);
- StackTrace::PrintStack(trace, size, common_flags()->symbolize,
- common_flags()->strip_path_prefix, 0);
+ StackTrace::PrintStack(trace, size);
}
// ForEachChunk callback. Aggregates unreachable chunks into a LeakReport.
@@ -400,8 +413,8 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
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 =
- getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
+ uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
+ addr, addr_frames.data(), kMaxAddrFrames);
for (uptr i = 0; i < addr_frames_num; i++) {
Suppression* s;
if (suppression_ctx->Match(addr_frames[i].function, SuppressionLeak, &s) ||
@@ -479,7 +492,6 @@ void LeakReport::PrintLargest(uptr num_leaks_to_print) {
leaks_[i].total_size, leaks_[i].hit_count);
Printf("%s", d.End());
PrintStackTraceById(leaks_[i].stack_trace_id);
- Printf("\n");
leaks_printed++;
if (leaks_printed == num_leaks_to_print) break;
}
@@ -497,12 +509,11 @@ void LeakReport::PrintSummary() {
bytes += leaks_[i].total_size;
allocations += leaks_[i].hit_count;
}
- const int kMaxSummaryLength = 128;
InternalScopedBuffer<char> summary(kMaxSummaryLength);
- internal_snprintf(summary.data(), kMaxSummaryLength,
- "LeakSanitizer: %zu byte(s) leaked in %zu allocation(s).",
- bytes, allocations);
- __sanitizer_report_error_summary(summary.data());
+ internal_snprintf(summary.data(), summary.size(),
+ "%zu byte(s) leaked in %zu allocation(s).", bytes,
+ allocations);
+ ReportErrorSummary(summary.data());
}
uptr LeakReport::ApplySuppressions() {
@@ -528,6 +539,8 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_ignore_object(const void *p) {
#if CAN_SANITIZE_LEAKS
+ if (!common_flags()->detect_leaks)
+ return;
// Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
// locked.
BlockingMutexLock l(&global_mutex);
@@ -552,7 +565,7 @@ void __lsan_disable() {
SANITIZER_INTERFACE_ATTRIBUTE
void __lsan_enable() {
#if CAN_SANITIZE_LEAKS
- if (!__lsan::disable_counter) {
+ if (!__lsan::disable_counter && common_flags()->detect_leaks) {
Report("Unmatched call to __lsan_enable().\n");
Die();
}
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index 7906ecb9177..5d9b4eb62e1 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -133,6 +133,8 @@ void UnlockThreadRegistry();
bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end,
uptr *cache_begin, uptr *cache_end);
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg);
// If called from the main thread, updates the main thread's TID in the thread
// registry. We need this to handle processes that fork() without a subsequent
// exec(), which invalidates the recorded TID. To update it, we must call
diff --git a/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc
index 40ddc7773e2..1940902ef83 100644
--- a/libsanitizer/lsan/lsan_interceptors.cc
+++ b/libsanitizer/lsan/lsan_interceptors.cc
@@ -42,11 +42,17 @@ int pthread_setspecific(unsigned key, const void *v);
stack_top = t->stack_end(); \
stack_bottom = t->stack_begin(); \
} \
- GetStackTrace(&stack, __sanitizer::common_flags()->malloc_context_size, \
- StackTrace::GetCurrentPc(), \
- GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \
+ stack.Unwind(__sanitizer::common_flags()->malloc_context_size, \
+ StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), stack_top, stack_bottom, fast); \
}
+#define ENSURE_LSAN_INITED do { \
+ CHECK(!lsan_init_is_running); \
+ if (!lsan_inited) \
+ __lsan_init(); \
+} while (0)
+
///// Malloc/free interceptors. /////
const bool kAlwaysClearMemory = true;
@@ -56,38 +62,49 @@ namespace std {
}
INTERCEPTOR(void*, malloc, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
return Allocate(stack, size, 1, kAlwaysClearMemory);
}
INTERCEPTOR(void, free, void *p) {
- Init();
+ ENSURE_LSAN_INITED;
Deallocate(p);
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
+ if (lsan_init_is_running) {
+ // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
+ const uptr kCallocPoolSize = 1024;
+ static uptr calloc_memory_for_dlsym[kCallocPoolSize];
+ static uptr allocated;
+ uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+ void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+ allocated += size_in_words;
+ CHECK(allocated < kCallocPoolSize);
+ return mem;
+ }
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return 0;
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
size *= nmemb;
return Allocate(stack, size, 1, true);
}
INTERCEPTOR(void*, realloc, void *q, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
return Reallocate(stack, q, size, 1);
}
INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
return Allocate(stack, size, alignment, kAlwaysClearMemory);
}
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
*memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
// FIXME: Return ENOMEM if user requested more than max alloc size.
@@ -95,7 +112,7 @@ INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
}
INTERCEPTOR(void*, valloc, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
if (size == 0)
size = GetPageSizeCached();
@@ -103,7 +120,7 @@ INTERCEPTOR(void*, valloc, uptr size) {
}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
- Init();
+ ENSURE_LSAN_INITED;
return GetMallocUsableSize(ptr);
}
@@ -122,7 +139,7 @@ INTERCEPTOR(int, mallopt, int cmd, int value) {
}
INTERCEPTOR(void*, pvalloc, uptr size) {
- Init();
+ ENSURE_LSAN_INITED;
GET_STACK_TRACE;
uptr PageSize = GetPageSizeCached();
size = RoundUpTo(size, PageSize);
@@ -136,7 +153,7 @@ INTERCEPTOR(void*, pvalloc, uptr size) {
INTERCEPTOR(void, cfree, void *p) ALIAS("free");
#define OPERATOR_NEW_BODY \
- Init(); \
+ ENSURE_LSAN_INITED; \
GET_STACK_TRACE; \
return Allocate(stack, size, 1, kAlwaysClearMemory);
@@ -150,7 +167,7 @@ INTERCEPTOR_ATTRIBUTE
void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
#define OPERATOR_DELETE_BODY \
- Init(); \
+ ENSURE_LSAN_INITED; \
Deallocate(ptr);
INTERCEPTOR_ATTRIBUTE
@@ -190,9 +207,6 @@ struct ThreadParam {
atomic_uintptr_t tid;
};
-// PTHREAD_DESTRUCTOR_ITERATIONS from glibc.
-const uptr kPthreadDestructorIterations = 4;
-
extern "C" void *__lsan_thread_start_func(void *arg) {
ThreadParam *p = (ThreadParam*)arg;
void* (*callback)(void *arg) = p->callback;
@@ -215,14 +229,14 @@ extern "C" void *__lsan_thread_start_func(void *arg) {
INTERCEPTOR(int, pthread_create, void *th, void *attr,
void *(*callback)(void *), void *param) {
- Init();
+ ENSURE_LSAN_INITED;
EnsureMainThreadIDIsCorrect();
__sanitizer_pthread_attr_t myattr;
if (attr == 0) {
pthread_attr_init(&myattr);
attr = &myattr;
}
- AdjustStackSizeLinux(attr, 0);
+ AdjustStackSizeLinux(attr);
int detached = 0;
pthread_attr_getdetachstate(attr, &detached);
ThreadParam p;
@@ -243,7 +257,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
}
INTERCEPTOR(int, pthread_join, void *th, void **ret) {
- Init();
+ ENSURE_LSAN_INITED;
int tid = ThreadTid((uptr)th);
int res = REAL(pthread_join)(th, ret);
if (res == 0)
diff --git a/libsanitizer/lsan/lsan_preinit.cc b/libsanitizer/lsan/lsan_preinit.cc
new file mode 100644
index 00000000000..856f9f78787
--- /dev/null
+++ b/libsanitizer/lsan/lsan_preinit.cc
@@ -0,0 +1,24 @@
+//===-- lsan_preinit.cc ---------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+//
+// Call __lsan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+
+#include "lsan.h"
+
+#ifndef LSAN_USE_PREINIT_ARRAY
+#define LSAN_USE_PREINIT_ARRAY 1
+#endif
+
+#if LSAN_USE_PREINIT_ARRAY && !defined(PIC)
+ // We force __lsan_init to be called before anyone else by placing it into
+ // .preinit_array section.
+ __attribute__((section(".preinit_array"), used))
+ void (*__local_lsan_preinit)(void) = __lsan_init;
+#endif
diff --git a/libsanitizer/lsan/lsan_thread.cc b/libsanitizer/lsan/lsan_thread.cc
index c260972cb47..07f9d0ab439 100644
--- a/libsanitizer/lsan/lsan_thread.cc
+++ b/libsanitizer/lsan/lsan_thread.cc
@@ -143,6 +143,10 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
+void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+ void *arg) {
+}
+
void LockThreadRegistry() {
thread_registry->Lock();
}
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am
index 13071c6af55..979d52d77e1 100644
--- a/libsanitizer/sanitizer_common/Makefile.am
+++ b/libsanitizer/sanitizer_common/Makefile.am
@@ -14,22 +14,28 @@ sanitizer_common_files = \
sanitizer_allocator.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
+ sanitizer_coverage.cc \
sanitizer_flags.cc \
sanitizer_libc.cc \
+ sanitizer_libignore.cc \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
sanitizer_mac.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
- sanitizer_posix.cc \
sanitizer_posix_libcdep.cc \
+ sanitizer_posix.cc \
sanitizer_printf.cc \
sanitizer_stackdepot.cc \
sanitizer_stacktrace.cc \
+ sanitizer_stacktrace_libcdep.cc \
sanitizer_stoptheworld_linux_libcdep.cc \
sanitizer_suppressions.cc \
sanitizer_symbolizer_posix_libcdep.cc \
sanitizer_symbolizer_win.cc \
+ sanitizer_symbolizer.cc \
+ sanitizer_symbolizer_libbacktrace.cc \
+ sanitizer_symbolizer_libcdep.cc \
sanitizer_thread_registry.cc \
sanitizer_win.cc
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index 9bbdfd6acfe..032cca41198 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -56,17 +56,19 @@ CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libsanitizer_common_la_LIBADD =
am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
- sanitizer_common_libcdep.lo sanitizer_flags.lo \
- sanitizer_libc.lo sanitizer_linux.lo \
- sanitizer_linux_libcdep.lo sanitizer_mac.lo \
+ sanitizer_common_libcdep.lo sanitizer_coverage.lo \
+ sanitizer_flags.lo sanitizer_libc.lo sanitizer_libignore.lo \
+ sanitizer_linux.lo sanitizer_linux_libcdep.lo sanitizer_mac.lo \
sanitizer_platform_limits_linux.lo \
- sanitizer_platform_limits_posix.lo sanitizer_posix.lo \
- sanitizer_posix_libcdep.lo sanitizer_printf.lo \
- sanitizer_stackdepot.lo sanitizer_stacktrace.lo \
+ sanitizer_platform_limits_posix.lo sanitizer_posix_libcdep.lo \
+ sanitizer_posix.lo sanitizer_printf.lo sanitizer_stackdepot.lo \
+ sanitizer_stacktrace.lo sanitizer_stacktrace_libcdep.lo \
sanitizer_stoptheworld_linux_libcdep.lo \
sanitizer_suppressions.lo \
sanitizer_symbolizer_posix_libcdep.lo \
- sanitizer_symbolizer_win.lo sanitizer_thread_registry.lo \
+ sanitizer_symbolizer_win.lo sanitizer_symbolizer.lo \
+ sanitizer_symbolizer_libbacktrace.lo \
+ sanitizer_symbolizer_libcdep.lo sanitizer_thread_registry.lo \
sanitizer_win.lo
am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
@@ -235,22 +237,28 @@ sanitizer_common_files = \
sanitizer_allocator.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
+ sanitizer_coverage.cc \
sanitizer_flags.cc \
sanitizer_libc.cc \
+ sanitizer_libignore.cc \
sanitizer_linux.cc \
sanitizer_linux_libcdep.cc \
sanitizer_mac.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
- sanitizer_posix.cc \
sanitizer_posix_libcdep.cc \
+ sanitizer_posix.cc \
sanitizer_printf.cc \
sanitizer_stackdepot.cc \
sanitizer_stacktrace.cc \
+ sanitizer_stacktrace_libcdep.cc \
sanitizer_stoptheworld_linux_libcdep.cc \
sanitizer_suppressions.cc \
sanitizer_symbolizer_posix_libcdep.cc \
sanitizer_symbolizer_win.cc \
+ sanitizer_symbolizer.cc \
+ sanitizer_symbolizer_libbacktrace.cc \
+ sanitizer_symbolizer_libcdep.cc \
sanitizer_thread_registry.cc \
sanitizer_win.cc
@@ -350,8 +358,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libignore.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
@@ -362,8 +372,12 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_linux_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_suppressions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_libbacktrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_posix_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h
index 505fa5b8837..8ba825f14ec 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h
@@ -585,7 +585,69 @@ class FlatByteMap {
u8 map_[kSize];
};
-// FIXME: Also implement TwoLevelByteMap.
+// TwoLevelByteMap maps integers in range [0, kSize1*kSize2) to u8 values.
+// It is implemented as a two-dimensional array: array of kSize1 pointers
+// to kSize2-byte arrays. The secondary arrays are mmaped on demand.
+// Each value is initially zero and can be set to something else only once.
+// Setting and getting values from multiple threads is safe w/o extra locking.
+template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+class TwoLevelByteMap {
+ public:
+ void TestOnlyInit() {
+ internal_memset(map1_, 0, sizeof(map1_));
+ mu_.Init();
+ }
+ void TestOnlyUnmap() {
+ for (uptr i = 0; i < kSize1; i++) {
+ u8 *p = Get(i);
+ if (!p) continue;
+ MapUnmapCallback().OnUnmap(reinterpret_cast<uptr>(p), kSize2);
+ UnmapOrDie(p, kSize2);
+ }
+ }
+
+ uptr size() const { return kSize1 * kSize2; }
+ uptr size1() const { return kSize1; }
+ uptr size2() const { return kSize2; }
+
+ void set(uptr idx, u8 val) {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = GetOrCreate(idx / kSize2);
+ CHECK_EQ(0U, map2[idx % kSize2]);
+ map2[idx % kSize2] = val;
+ }
+
+ u8 operator[] (uptr idx) const {
+ CHECK_LT(idx, kSize1 * kSize2);
+ u8 *map2 = Get(idx / kSize2);
+ if (!map2) return 0;
+ return map2[idx % kSize2];
+ }
+
+ private:
+ u8 *Get(uptr idx) const {
+ CHECK_LT(idx, kSize1);
+ return reinterpret_cast<u8 *>(
+ atomic_load(&map1_[idx], memory_order_acquire));
+ }
+
+ u8 *GetOrCreate(uptr idx) {
+ u8 *res = Get(idx);
+ if (!res) {
+ SpinMutexLock l(&mu_);
+ if (!(res = Get(idx))) {
+ res = (u8*)MmapOrDie(kSize2, "TwoLevelByteMap");
+ MapUnmapCallback().OnMap(reinterpret_cast<uptr>(res), kSize2);
+ atomic_store(&map1_[idx], reinterpret_cast<uptr>(res),
+ memory_order_release);
+ }
+ }
+ return res;
+ }
+
+ atomic_uintptr_t map1_[kSize1];
+ StaticSpinMutex mu_;
+};
// SizeClassAllocator32 -- allocator for 32-bit address space.
// This allocator can theoretically be used on 64-bit arch, but there it is less
@@ -1049,6 +1111,7 @@ class LargeMmapAllocator {
// This function does the same as GetBlockBegin, but is much faster.
// Must be called with the allocator locked.
void *GetBlockBeginFastLocked(void *ptr) {
+ mutex_.CheckLocked();
uptr p = reinterpret_cast<uptr>(ptr);
uptr n = n_chunks_;
if (!n) return 0;
@@ -1181,14 +1244,15 @@ class CombinedAllocator {
if (alignment > 8)
size = RoundUpTo(size, alignment);
void *res;
- if (primary_.CanAllocate(size, alignment))
+ bool from_primary = primary_.CanAllocate(size, alignment);
+ if (from_primary)
res = cache->Allocate(&primary_, primary_.ClassID(size));
else
res = secondary_.Allocate(&stats_, size, alignment);
if (alignment > 8)
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
- if (cleared && res)
- internal_memset(res, 0, size);
+ if (cleared && res && from_primary)
+ internal_bzero_aligned16(res, RoundUpTo(size, 16));
return res;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
index c033b96e4dd..efdb89e3682 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
@@ -25,21 +25,25 @@ static const uptr kInternalAllocatorSpace = 0;
#if SANITIZER_WORDSIZE == 32
static const u64 kInternalAllocatorSize = (1ULL << 32);
static const uptr kInternalAllocatorRegionSizeLog = 20;
+static const uptr kInternalAllocatorNumRegions =
+ kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
#else
static const u64 kInternalAllocatorSize = (1ULL << 47);
static const uptr kInternalAllocatorRegionSizeLog = 24;
-#endif
-static const uptr kInternalAllocatorFlatByteMapSize =
+static const uptr kInternalAllocatorNumRegions =
kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
+#endif
typedef SizeClassAllocator32<
kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap,
- kInternalAllocatorRegionSizeLog,
- FlatByteMap<kInternalAllocatorFlatByteMapSize> > PrimaryInternalAllocator;
+ kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
InternalAllocatorCache;
-// We don't want our internal allocator to do any map/unmap operations.
+// We don't want our internal allocator to do any map/unmap operations from
+// LargeMmapAllocator.
struct CrashOnMapUnmap {
void OnMap(uptr p, uptr size) const {
RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!");
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc
index f689df421aa..bf73dc6339b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cc
@@ -10,12 +10,14 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
+#include "sanitizer_stacktrace.h"
+#include "sanitizer_symbolizer.h"
namespace __sanitizer {
const char *SanitizerToolName = "SanitizerTool";
-uptr SanitizerVerbosity = 0;
uptr GetPageSizeCached() {
static uptr PageSize;
@@ -134,14 +136,71 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
return (void*)res;
}
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_path_prefix) {
+ if (filepath == 0) return 0;
+ if (strip_path_prefix == 0) return filepath;
+ const char *pos = internal_strstr(filepath, strip_path_prefix);
+ if (pos == 0) return filepath;
+ pos += internal_strlen(strip_path_prefix);
+ if (pos[0] == '.' && pos[1] == '/')
+ pos += 2;
+ return pos;
+}
+
+void PrintSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column) {
+ CHECK(file);
+ buffer->append("%s",
+ StripPathPrefix(file, common_flags()->strip_path_prefix));
+ if (line > 0) {
+ buffer->append(":%d", line);
+ if (column > 0)
+ buffer->append(":%d", column);
+ }
+}
+
+void PrintModuleAndOffset(InternalScopedString *buffer, const char *module,
+ uptr offset) {
+ buffer->append("(%s+0x%zx)",
+ StripPathPrefix(module, common_flags()->strip_path_prefix),
+ offset);
+}
+
+void ReportErrorSummary(const char *error_message) {
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedBuffer<char> buff(kMaxSummaryLength);
+ internal_snprintf(buff.data(), buff.size(),
+ "SUMMARY: %s: %s", SanitizerToolName, error_message);
+ __sanitizer_report_error_summary(buff.data());
+}
+
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());
+ if (!common_flags()->print_summary)
+ return;
+ InternalScopedBuffer<char> buff(kMaxSummaryLength);
+ internal_snprintf(
+ buff.data(), buff.size(), "%s %s:%d %s", error_type,
+ file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??",
+ line, function ? function : "??");
+ ReportErrorSummary(buff.data());
+}
+
+void ReportErrorSummary(const char *error_type, StackTrace *stack) {
+ if (!common_flags()->print_summary)
+ return;
+ AddressInfo ai;
+#if !SANITIZER_GO
+ if (stack->size > 0 && Symbolizer::Get()->IsAvailable()) {
+ // Currently, we include the first stack frame into the report summary.
+ // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
+ uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+ Symbolizer::Get()->SymbolizeCode(pc, &ai, 1);
+ }
+#endif
+ ReportErrorSummary(error_type, ai.file, ai.line, ai.function);
}
LoadedModule::LoadedModule(const char *module_name, uptr base_address) {
@@ -165,13 +224,25 @@ bool LoadedModule::containsAddress(uptr address) const {
return false;
}
+char *StripModuleName(const char *module) {
+ if (module == 0)
+ return 0;
+ const char *short_module_name = internal_strrchr(module, '/');
+ if (short_module_name)
+ short_module_name += 1;
+ else
+ short_module_name = module;
+ return internal_strdup(short_module_name);
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
extern "C" {
void __sanitizer_set_report_path(const char *path) {
- if (!path) return;
+ if (!path)
+ return;
uptr len = internal_strlen(path);
if (len > sizeof(report_path_prefix) - 100) {
Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
@@ -179,18 +250,21 @@ void __sanitizer_set_report_path(const char *path) {
path[4], path[5], path[6], path[7]);
Die();
}
- internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
- report_path_prefix[len] = '\0';
- report_fd = kInvalidFd;
- log_to_file = true;
-}
-
-void __sanitizer_set_report_fd(int fd) {
if (report_fd != kStdoutFd &&
report_fd != kStderrFd &&
report_fd != kInvalidFd)
internal_close(report_fd);
- report_fd = fd;
+ report_fd = kInvalidFd;
+ log_to_file = false;
+ if (internal_strcmp(path, "stdout") == 0) {
+ report_fd = kStdoutFd;
+ } else if (internal_strcmp(path, "stderr") == 0) {
+ report_fd = kStderrFd;
+ } else {
+ internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix));
+ report_path_prefix[len] = '\0';
+ log_to_file = true;
+ }
}
void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
@@ -199,6 +273,6 @@ void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) {
}
void __sanitizer_report_error_summary(const char *error_summary) {
- Printf("SUMMARY: %s\n", error_summary);
+ Printf("%s\n", error_summary);
}
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 417f71f987c..833c2b07e35 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -34,7 +34,6 @@ const uptr kCacheLineSize = 64;
const uptr kMaxPathLength = 512;
extern const char *SanitizerToolName; // Can be changed by the tool.
-extern uptr SanitizerVerbosity;
uptr GetPageSize();
uptr GetPageSizeCached();
@@ -86,6 +85,23 @@ class InternalScopedBuffer {
void operator=(const InternalScopedBuffer&);
};
+class InternalScopedString : public InternalScopedBuffer<char> {
+ public:
+ explicit InternalScopedString(uptr max_length)
+ : InternalScopedBuffer<char>(max_length), length_(0) {
+ (*this)[0] = '\0';
+ }
+ uptr length() { return length_; }
+ void clear() {
+ (*this)[0] = '\0';
+ length_ = 0;
+ }
+ void append(const char *format, ...);
+
+ private:
+ uptr length_;
+};
+
// Simple low-level (mmap-based) allocator for internal use. Doesn't have
// constructor, so all instances of LowLevelAllocator should be
// linker initialized.
@@ -110,6 +126,7 @@ bool PrintsToTtyCached();
void Printf(const char *format, ...);
void Report(const char *format, ...);
void SetPrintfAndReportCallback(void (*callback)(const char *));
+
// Can be used to prevent mixing error reports from different sanitizers.
extern StaticSpinMutex CommonSanitizerReportMutex;
void MaybeOpenReportFile();
@@ -130,6 +147,14 @@ uptr ReadFileToBuffer(const char *file_name, char **buff,
// in '*buff_size'.
void *MapFileToMemory(const char *file_name, uptr *buff_size);
+// Error report formatting.
+const char *StripPathPrefix(const char *filepath,
+ const char *strip_file_prefix);
+void PrintSourceLocation(InternalScopedString *buffer, const char *file,
+ int line, int column);
+void PrintModuleAndOffset(InternalScopedString *buffer,
+ const char *module, uptr offset);
+
// OS
void DisableCoreDumper();
void DumpProcessMap();
@@ -153,6 +178,9 @@ void SleepForMillis(int millis);
u64 NanoTime();
int Atexit(void (*function)(void));
void SortArray(uptr *array, uptr size);
+// Strip the directories from the module name, return a new string allocated
+// with internal_strdup.
+char *StripModuleName(const char *module);
// Exit
void NORETURN Abort();
@@ -176,11 +204,17 @@ 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.
+// We don't want a summary too long.
+const int kMaxSummaryLength = 1024;
+// Construct a one-line string:
+// SUMMARY: SanitizerToolName: error_message
+// and pass it to __sanitizer_report_error_summary.
+void ReportErrorSummary(const char *error_message);
+// Same as above, but construct error_message as:
+// error_type: file:line function
void ReportErrorSummary(const char *error_type, const char *file,
int line, const char *function);
+void ReportErrorSummary(const char *error_type, StackTrace *trace);
// Math
#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
@@ -326,6 +360,8 @@ class InternalMmapVector {
return capacity_;
}
+ void clear() { size_ = 0; }
+
private:
void Resize(uptr new_capacity) {
CHECK_GT(new_capacity, 0);
@@ -431,6 +467,20 @@ typedef bool (*string_predicate_t)(const char *);
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
string_predicate_t filter);
+#if SANITIZER_POSIX
+const uptr kPthreadDestructorIterations = 4;
+#else
+// Unused on Windows.
+const uptr kPthreadDestructorIterations = 0;
+#endif
+
+// Callback type for iterating over a set of memory ranges.
+typedef void (*RangeIteratorCallback)(uptr begin, uptr end, void *arg);
} // namespace __sanitizer
+inline void *operator new(__sanitizer::operator_new_size_type size,
+ __sanitizer::LowLevelAllocator &alloc) {
+ return alloc.Allocate(size);
+}
+
#endif // SANITIZER_COMMON_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 17ef72e0c98..45b12fcaf16 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -13,19 +13,51 @@
// COMMON_INTERCEPTOR_ENTER
// COMMON_INTERCEPTOR_READ_RANGE
// COMMON_INTERCEPTOR_WRITE_RANGE
+// COMMON_INTERCEPTOR_INITIALIZE_RANGE
// COMMON_INTERCEPTOR_FD_ACQUIRE
// COMMON_INTERCEPTOR_FD_RELEASE
+// COMMON_INTERCEPTOR_FD_ACCESS
// COMMON_INTERCEPTOR_SET_THREAD_NAME
+// COMMON_INTERCEPTOR_ON_EXIT
+// COMMON_INTERCEPTOR_MUTEX_LOCK
+// COMMON_INTERCEPTOR_MUTEX_UNLOCK
+// COMMON_INTERCEPTOR_MUTEX_REPAIR
+// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
+// COMMON_INTERCEPTOR_HANDLE_RECVMSG
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
#include "sanitizer_platform_interceptors.h"
#include <stdarg.h>
-#if SANITIZER_WINDOWS
+#if SANITIZER_WINDOWS && !defined(va_copy)
#define va_copy(dst, src) ((dst) = (src))
#endif // _WIN32
+#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
+#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, p, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_FD_ACCESS
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
+#endif
+
#if SANITIZER_INTERCEPT_STRCMP
static inline int CharCmpX(unsigned char c1, unsigned char c2) {
return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
@@ -36,7 +68,7 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) {
COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2);
unsigned char c1, c2;
uptr i;
- for (i = 0; ; i++) {
+ for (i = 0;; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
if (c1 != c2 || c1 == '\0') break;
@@ -61,8 +93,8 @@ INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
return CharCmpX(c1, c2);
}
-#define INIT_STRCMP INTERCEPT_FUNCTION(strcmp)
-#define INIT_STRNCMP INTERCEPT_FUNCTION(strncmp)
+#define INIT_STRCMP COMMON_INTERCEPT_FUNCTION(strcmp)
+#define INIT_STRNCMP COMMON_INTERCEPT_FUNCTION(strncmp)
#else
#define INIT_STRCMP
#define INIT_STRNCMP
@@ -80,11 +112,10 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2);
unsigned char c1 = 0, c2 = 0;
uptr i;
- for (i = 0; ; i++) {
+ for (i = 0;; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
- if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
- break;
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, i + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, i + 1);
@@ -99,16 +130,15 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
for (i = 0; i < n; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
- if (CharCaseCmp(c1, c2) != 0 || c1 == '\0')
- break;
+ if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
return CharCaseCmp(c1, c2);
}
-#define INIT_STRCASECMP INTERCEPT_FUNCTION(strcasecmp)
-#define INIT_STRNCASECMP INTERCEPT_FUNCTION(strncasecmp)
+#define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
+#define INIT_STRNCASECMP COMMON_INTERCEPT_FUNCTION(strncasecmp)
#else
#define INIT_STRCASECMP
#define INIT_STRNCASECMP
@@ -123,10 +153,10 @@ INTERCEPTOR(double, frexp, double x, int *exp) {
return res;
}
-#define INIT_FREXP INTERCEPT_FUNCTION(frexp);
+#define INIT_FREXP COMMON_INTERCEPT_FUNCTION(frexp);
#else
#define INIT_FREXP
-#endif // SANITIZER_INTERCEPT_FREXP
+#endif // SANITIZER_INTERCEPT_FREXP
#if SANITIZER_INTERCEPT_FREXPF_FREXPL
INTERCEPTOR(float, frexpf, float x, int *exp) {
@@ -145,12 +175,12 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
return res;
}
-#define INIT_FREXPF_FREXPL \
- INTERCEPT_FUNCTION(frexpf); \
- INTERCEPT_FUNCTION(frexpl)
+#define INIT_FREXPF_FREXPL \
+ COMMON_INTERCEPT_FUNCTION(frexpf); \
+ COMMON_INTERCEPT_FUNCTION(frexpl)
#else
#define INIT_FREXPF_FREXPL
-#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
+#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
#if SI_NOT_WINDOWS
static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
@@ -177,14 +207,13 @@ static void read_iovec(void *ctx, struct __sanitizer_iovec *iovec,
INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, count);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(read)(fd, ptr, count);
- if (res > 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
- if (res >= 0 && fd >= 0)
- COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_READ INTERCEPT_FUNCTION(read)
+#define INIT_READ COMMON_INTERCEPT_FUNCTION(read)
#else
#define INIT_READ
#endif
@@ -193,14 +222,13 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
- if (res >= 0 && fd >= 0)
- COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREAD INTERCEPT_FUNCTION(pread)
+#define INIT_PREAD COMMON_INTERCEPT_FUNCTION(pread)
#else
#define INIT_PREAD
#endif
@@ -209,14 +237,13 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
- if (res >= 0 && fd >= 0)
- COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+ if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREAD64 INTERCEPT_FUNCTION(pread64)
+#define INIT_PREAD64 COMMON_INTERCEPT_FUNCTION(pread64)
#else
#define INIT_PREAD64
#endif
@@ -226,12 +253,13 @@ INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
int iovcnt) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
if (res > 0) write_iovec(ctx, iov, iovcnt, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_READV INTERCEPT_FUNCTION(readv)
+#define INIT_READV COMMON_INTERCEPT_FUNCTION(readv)
#else
#define INIT_READV
#endif
@@ -241,12 +269,13 @@ INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
OFF_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
if (res > 0) write_iovec(ctx, iov, iovcnt, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREADV INTERCEPT_FUNCTION(preadv)
+#define INIT_PREADV COMMON_INTERCEPT_FUNCTION(preadv)
#else
#define INIT_PREADV
#endif
@@ -256,12 +285,13 @@ INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
OFF64_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
if (res > 0) write_iovec(ctx, iov, iovcnt, res);
if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
return res;
}
-#define INIT_PREADV64 INTERCEPT_FUNCTION(preadv64)
+#define INIT_PREADV64 COMMON_INTERCEPT_FUNCTION(preadv64)
#else
#define INIT_PREADV64
#endif
@@ -270,15 +300,14 @@ INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(write)(fd, ptr, count);
// FIXME: this check should be _before_ the call to REAL(write), not after
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_WRITE INTERCEPT_FUNCTION(write)
+#define INIT_WRITE COMMON_INTERCEPT_FUNCTION(write)
#else
#define INIT_WRITE
#endif
@@ -287,14 +316,13 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T 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);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_PWRITE INTERCEPT_FUNCTION(pwrite)
+#define INIT_PWRITE COMMON_INTERCEPT_FUNCTION(pwrite)
#else
#define INIT_PWRITE
#endif
@@ -304,14 +332,13 @@ 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);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
- if (res > 0)
- COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
return res;
}
-#define INIT_PWRITE64 INTERCEPT_FUNCTION(pwrite64)
+#define INIT_PWRITE64 COMMON_INTERCEPT_FUNCTION(pwrite64)
#else
#define INIT_PWRITE64
#endif
@@ -321,12 +348,13 @@ INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
int iovcnt) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
if (res > 0) read_iovec(ctx, iov, iovcnt, res);
return res;
}
-#define INIT_WRITEV INTERCEPT_FUNCTION(writev)
+#define INIT_WRITEV COMMON_INTERCEPT_FUNCTION(writev)
#else
#define INIT_WRITEV
#endif
@@ -336,12 +364,13 @@ INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
OFF_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
if (res > 0) read_iovec(ctx, iov, iovcnt, res);
return res;
}
-#define INIT_PWRITEV INTERCEPT_FUNCTION(pwritev)
+#define INIT_PWRITEV COMMON_INTERCEPT_FUNCTION(pwritev)
#else
#define INIT_PWRITEV
#endif
@@ -351,20 +380,21 @@ INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
OFF64_T offset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
+ COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
if (res > 0) read_iovec(ctx, iov, iovcnt, res);
return res;
}
-#define INIT_PWRITEV64 INTERCEPT_FUNCTION(pwritev64)
+#define INIT_PWRITEV64 COMMON_INTERCEPT_FUNCTION(pwritev64)
#else
#define INIT_PWRITEV64
#endif
#if SANITIZER_INTERCEPT_PRCTL
-INTERCEPTOR(int, prctl, int option,
- unsigned long arg2, unsigned long arg3, // NOLINT
- unsigned long arg4, unsigned long arg5) { // NOLINT
+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;
@@ -377,11 +407,10 @@ INTERCEPTOR(int, prctl, int option,
}
return res;
}
-#define INIT_PRCTL INTERCEPT_FUNCTION(prctl)
+#define INIT_PRCTL COMMON_INTERCEPT_FUNCTION(prctl)
#else
#define INIT_PRCTL
-#endif // SANITIZER_INTERCEPT_PRCTL
-
+#endif // SANITIZER_INTERCEPT_PRCTL
#if SANITIZER_INTERCEPT_TIME
INTERCEPTOR(unsigned long, time, unsigned long *t) {
@@ -393,51 +422,58 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) {
}
return res;
}
-#define INIT_TIME \
- INTERCEPT_FUNCTION(time);
+#define INIT_TIME COMMON_INTERCEPT_FUNCTION(time);
#else
#define INIT_TIME
-#endif // SANITIZER_INTERCEPT_TIME
-
+#endif // SANITIZER_INTERCEPT_TIME
#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
-INTERCEPTOR(void *, localtime, unsigned long *timep) {
+static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ if (tm->tm_zone) {
+ // Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
+ // can point to shared memory and tsan would report a data race.
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, tm->tm_zone,
+ REAL(strlen(tm->tm_zone)) + 1);
+ }
+}
+INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, localtime, timep);
- void *res = REAL(localtime)(timep);
+ __sanitizer_tm *res = REAL(localtime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, localtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, localtime_r, unsigned long *timep, void *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, localtime_r, timep, result);
- void *res = REAL(localtime_r)(timep, result);
+ __sanitizer_tm *res = REAL(localtime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, gmtime, unsigned long *timep) {
+INTERCEPTOR(__sanitizer_tm *, gmtime, unsigned long *timep) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gmtime, timep);
- void *res = REAL(gmtime)(timep);
+ __sanitizer_tm *res = REAL(gmtime)(timep);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
-INTERCEPTOR(void *, gmtime_r, unsigned long *timep, void *result) {
+INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gmtime_r, timep, result);
- void *res = REAL(gmtime_r)(timep, result);
+ __sanitizer_tm *res = REAL(gmtime_r)(timep, result);
if (res) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep));
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_tm_sz);
+ unpoison_tm(ctx, res);
}
return res;
}
@@ -461,38 +497,59 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) {
}
return res;
}
-INTERCEPTOR(char *, asctime, void *tm) {
+INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm);
char *res = REAL(asctime)(tm);
if (res) {
- COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
}
return res;
}
-INTERCEPTOR(char *, asctime_r, void *tm, char *result) {
+INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result);
char *res = REAL(asctime_r)(tm, result);
if (res) {
- COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, struct_tm_sz);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm));
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
}
return res;
}
-#define INIT_LOCALTIME_AND_FRIENDS \
- INTERCEPT_FUNCTION(localtime); \
- INTERCEPT_FUNCTION(localtime_r); \
- INTERCEPT_FUNCTION(gmtime); \
- INTERCEPT_FUNCTION(gmtime_r); \
- INTERCEPT_FUNCTION(ctime); \
- INTERCEPT_FUNCTION(ctime_r); \
- INTERCEPT_FUNCTION(asctime); \
- INTERCEPT_FUNCTION(asctime_r);
+#define INIT_LOCALTIME_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(localtime); \
+ COMMON_INTERCEPT_FUNCTION(localtime_r); \
+ COMMON_INTERCEPT_FUNCTION(gmtime); \
+ COMMON_INTERCEPT_FUNCTION(gmtime_r); \
+ COMMON_INTERCEPT_FUNCTION(ctime); \
+ COMMON_INTERCEPT_FUNCTION(ctime_r); \
+ COMMON_INTERCEPT_FUNCTION(asctime); \
+ COMMON_INTERCEPT_FUNCTION(asctime_r);
#else
#define INIT_LOCALTIME_AND_FRIENDS
-#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+#endif // SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
+
+#if SANITIZER_INTERCEPT_STRPTIME
+INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm);
+ if (format)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1);
+ char *res = REAL(strptime)(s, format, tm);
+ if (res) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s);
+ // Do not call unpoison_tm here, because strptime does not, in fact,
+ // initialize the entire struct tm. For example, tm_zone pointer is left
+ // uninitialized.
+ if (tm) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
+ }
+ return res;
+}
+#define INIT_STRPTIME COMMON_INTERCEPT_FUNCTION(strptime);
+#else
+#define INIT_STRPTIME
+#endif
#if SANITIZER_INTERCEPT_SCANF
@@ -566,25 +623,25 @@ SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
#endif
#if SANITIZER_INTERCEPT_SCANF
-#define INIT_SCANF \
- INTERCEPT_FUNCTION(scanf); \
- INTERCEPT_FUNCTION(sscanf); \
- INTERCEPT_FUNCTION(fscanf); \
- INTERCEPT_FUNCTION(vscanf); \
- INTERCEPT_FUNCTION(vsscanf); \
- INTERCEPT_FUNCTION(vfscanf);
+#define INIT_SCANF \
+ COMMON_INTERCEPT_FUNCTION(scanf); \
+ COMMON_INTERCEPT_FUNCTION(sscanf); \
+ COMMON_INTERCEPT_FUNCTION(fscanf); \
+ COMMON_INTERCEPT_FUNCTION(vscanf); \
+ COMMON_INTERCEPT_FUNCTION(vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(vfscanf);
#else
#define INIT_SCANF
#endif
#if SANITIZER_INTERCEPT_ISOC99_SCANF
-#define INIT_ISOC99_SCANF \
- INTERCEPT_FUNCTION(__isoc99_scanf); \
- INTERCEPT_FUNCTION(__isoc99_sscanf); \
- INTERCEPT_FUNCTION(__isoc99_fscanf); \
- INTERCEPT_FUNCTION(__isoc99_vscanf); \
- INTERCEPT_FUNCTION(__isoc99_vsscanf); \
- INTERCEPT_FUNCTION(__isoc99_vfscanf);
+#define INIT_ISOC99_SCANF \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_scanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_sscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_fscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vsscanf); \
+ COMMON_INTERCEPT_FUNCTION(__isoc99_vfscanf);
#else
#define INIT_ISOC99_SCANF
#endif
@@ -599,45 +656,38 @@ INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
// Note: TSan does not use common flags, and they are zero-initialized.
// This effectively disables ioctl handling in TSan.
- if (!common_flags()->handle_ioctl)
- return REAL(ioctl)(d, request, arg);
+ if (!common_flags()->handle_ioctl) return REAL(ioctl)(d, request, arg);
const ioctl_desc *desc = ioctl_lookup(request);
- if (!desc)
- Printf("WARNING: unknown ioctl %x\n", request);
+ if (!desc) Printf("WARNING: unknown ioctl %x\n", request);
- if (desc)
- ioctl_common_pre(ctx, desc, d, request, arg);
+ if (desc) ioctl_common_pre(ctx, desc, d, request, arg);
int res = REAL(ioctl)(d, request, arg);
// FIXME: some ioctls have different return values for success and failure.
- if (desc && res != -1)
- ioctl_common_post(ctx, desc, res, d, request, arg);
+ if (desc && res != -1) ioctl_common_post(ctx, desc, res, d, request, arg);
return res;
}
#define INIT_IOCTL \
ioctl_init(); \
- INTERCEPT_FUNCTION(ioctl);
+ COMMON_INTERCEPT_FUNCTION(ioctl);
#else
#define INIT_IOCTL
#endif
-
#if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
INTERCEPTOR(void *, getpwnam, const char *name) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
void *res = REAL(getpwnam)(name);
- if (res != 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
return res;
}
INTERCEPTOR(void *, getpwuid, u32 uid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid);
void *res = REAL(getpwuid)(uid);
- if (res != 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_passwd_sz);
return res;
}
INTERCEPTOR(void *, getgrnam, const char *name) {
@@ -645,31 +695,28 @@ INTERCEPTOR(void *, getgrnam, const char *name) {
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
void *res = REAL(getgrnam)(name);
- if (res != 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
return res;
}
INTERCEPTOR(void *, getgrgid, u32 gid) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid);
void *res = REAL(getgrgid)(gid);
- if (res != 0)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
+ if (res != 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, struct_group_sz);
return res;
}
-#define INIT_GETPWNAM_AND_FRIENDS \
- INTERCEPT_FUNCTION(getpwnam); \
- INTERCEPT_FUNCTION(getpwuid); \
- INTERCEPT_FUNCTION(getgrnam); \
- INTERCEPT_FUNCTION(getgrgid);
+#define INIT_GETPWNAM_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid);
#else
#define INIT_GETPWNAM_AND_FRIENDS
#endif
-
#if SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
-INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd, char *buf,
+ SIZE_T buflen, void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
@@ -680,8 +727,8 @@ INTERCEPTOR(int, getpwnam_r, const char *name, void *pwd,
}
return res;
}
-INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd, char *buf, SIZE_T buflen,
+ void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result);
int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result);
@@ -691,8 +738,8 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, void *pwd,
}
return res;
}
-INTERCEPTOR(int, getgrnam_r, const char *name, void *grp,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getgrnam_r, const char *name, void *grp, char *buf,
+ SIZE_T buflen, void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result);
COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
@@ -703,8 +750,8 @@ INTERCEPTOR(int, getgrnam_r, const char *name, void *grp,
}
return res;
}
-INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
- char *buf, SIZE_T buflen, void **result) {
+INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp, char *buf, SIZE_T buflen,
+ void **result) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result);
int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result);
@@ -714,16 +761,15 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, void *grp,
}
return res;
}
-#define INIT_GETPWNAM_R_AND_FRIENDS \
- INTERCEPT_FUNCTION(getpwnam_r); \
- INTERCEPT_FUNCTION(getpwuid_r); \
- INTERCEPT_FUNCTION(getgrnam_r); \
- INTERCEPT_FUNCTION(getgrgid_r);
+#define INIT_GETPWNAM_R_AND_FRIENDS \
+ COMMON_INTERCEPT_FUNCTION(getpwnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getpwuid_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrnam_r); \
+ COMMON_INTERCEPT_FUNCTION(getgrgid_r);
#else
#define INIT_GETPWNAM_R_AND_FRIENDS
#endif
-
#if SANITIZER_INTERCEPT_CLOCK_GETTIME
INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) {
void *ctx;
@@ -749,15 +795,14 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
COMMON_INTERCEPTOR_READ_RANGE(ctx, tp, struct_timespec_sz);
return REAL(clock_settime)(clk_id, tp);
}
-#define INIT_CLOCK_GETTIME \
- INTERCEPT_FUNCTION(clock_getres); \
- INTERCEPT_FUNCTION(clock_gettime); \
- INTERCEPT_FUNCTION(clock_settime);
+#define INIT_CLOCK_GETTIME \
+ COMMON_INTERCEPT_FUNCTION(clock_getres); \
+ COMMON_INTERCEPT_FUNCTION(clock_gettime); \
+ COMMON_INTERCEPT_FUNCTION(clock_settime);
#else
#define INIT_CLOCK_GETTIME
#endif
-
#if SANITIZER_INTERCEPT_GETITIMER
INTERCEPTOR(int, getitimer, int which, void *curr_value) {
void *ctx;
@@ -779,9 +824,9 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) {
}
return res;
}
-#define INIT_GETITIMER \
- INTERCEPT_FUNCTION(getitimer); \
- INTERCEPT_FUNCTION(setitimer);
+#define INIT_GETITIMER \
+ COMMON_INTERCEPT_FUNCTION(getitimer); \
+ COMMON_INTERCEPT_FUNCTION(setitimer);
#else
#define INIT_GETITIMER
#endif
@@ -799,8 +844,8 @@ static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
}
}
-static THREADLOCAL __sanitizer_glob_t* pglob_copy;
-static THREADLOCAL void* glob_ctx;
+static THREADLOCAL __sanitizer_glob_t *pglob_copy;
+static THREADLOCAL void *glob_ctx;
static void wrapped_gl_closedir(void *dir) {
COMMON_INTERCEPTOR_UNPOISON_PARAM(glob_ctx, 1);
@@ -835,9 +880,10 @@ INTERCEPTOR(int, glob, const char *pattern, int flags,
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
- __sanitizer_glob_t glob_copy = {0, 0, 0, 0, wrapped_gl_closedir,
- wrapped_gl_readdir, wrapped_gl_opendir,
- wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -866,9 +912,10 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob);
- __sanitizer_glob_t glob_copy = {0, 0, 0, 0, wrapped_gl_closedir,
- wrapped_gl_readdir, wrapped_gl_opendir,
- wrapped_gl_lstat, wrapped_gl_stat};
+ __sanitizer_glob_t glob_copy = {
+ 0, 0, 0,
+ 0, wrapped_gl_closedir, wrapped_gl_readdir,
+ wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat};
if (flags & glob_altdirfunc) {
Swap(pglob->gl_closedir, glob_copy.gl_closedir);
Swap(pglob->gl_readdir, glob_copy.gl_readdir);
@@ -891,9 +938,9 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
-#define INIT_GLOB \
- INTERCEPT_FUNCTION(glob); \
- INTERCEPT_FUNCTION(glob64);
+#define INIT_GLOB \
+ COMMON_INTERCEPT_FUNCTION(glob); \
+ COMMON_INTERCEPT_FUNCTION(glob64);
#else // SANITIZER_INTERCEPT_GLOB
#define INIT_GLOB
#endif // SANITIZER_INTERCEPT_GLOB
@@ -911,7 +958,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
return res;
}
INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
- int options) {
+ int options) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options);
int res = REAL(waitid)(idtype, id, infop, options);
@@ -932,10 +979,8 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage);
int res = REAL(wait3)(status, options, rusage);
if (res != -1) {
- if (status)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
- if (rusage)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
}
return res;
}
@@ -944,19 +989,17 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage);
int res = REAL(wait4)(pid, status, options, rusage);
if (res != -1) {
- if (status)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
- if (rusage)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
+ if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
+ if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
}
return res;
}
-#define INIT_WAIT \
- INTERCEPT_FUNCTION(wait); \
- INTERCEPT_FUNCTION(waitid); \
- INTERCEPT_FUNCTION(waitpid); \
- INTERCEPT_FUNCTION(wait3); \
- INTERCEPT_FUNCTION(wait4);
+#define INIT_WAIT \
+ COMMON_INTERCEPT_FUNCTION(wait); \
+ COMMON_INTERCEPT_FUNCTION(waitid); \
+ COMMON_INTERCEPT_FUNCTION(waitpid); \
+ COMMON_INTERCEPT_FUNCTION(wait3); \
+ COMMON_INTERCEPT_FUNCTION(wait4);
#else
#define INIT_WAIT
#endif
@@ -969,8 +1012,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) {
if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz);
// FIXME: figure out read size based on the address family.
char *res = REAL(inet_ntop)(af, src, dst, size);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
@@ -984,9 +1026,9 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) {
}
return res;
}
-#define INIT_INET \
- INTERCEPT_FUNCTION(inet_ntop); \
- INTERCEPT_FUNCTION(inet_pton);
+#define INIT_INET \
+ COMMON_INTERCEPT_FUNCTION(inet_ntop); \
+ COMMON_INTERCEPT_FUNCTION(inet_pton);
#else
#define INIT_INET
#endif
@@ -1003,7 +1045,7 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) {
}
return res;
}
-#define INIT_INET_ATON INTERCEPT_FUNCTION(inet_aton);
+#define INIT_INET_ATON COMMON_INTERCEPT_FUNCTION(inet_aton);
#else
#define INIT_INET_ATON
#endif
@@ -1019,7 +1061,8 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
}
return res;
}
-#define INIT_PTHREAD_GETSCHEDPARAM INTERCEPT_FUNCTION(pthread_getschedparam);
+#define INIT_PTHREAD_GETSCHEDPARAM \
+ COMMON_INTERCEPT_FUNCTION(pthread_getschedparam);
#else
#define INIT_PTHREAD_GETSCHEDPARAM
#endif
@@ -1051,7 +1094,7 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service,
}
return res;
}
-#define INIT_GETADDRINFO INTERCEPT_FUNCTION(getaddrinfo);
+#define INIT_GETADDRINFO COMMON_INTERCEPT_FUNCTION(getaddrinfo);
#else
#define INIT_GETADDRINFO
#endif
@@ -1074,7 +1117,7 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
}
return res;
}
-#define INIT_GETNAMEINFO INTERCEPT_FUNCTION(getnameinfo);
+#define INIT_GETNAMEINFO COMMON_INTERCEPT_FUNCTION(getnameinfo);
#else
#define INIT_GETNAMEINFO
#endif
@@ -1091,7 +1134,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) {
}
return res;
}
-#define INIT_GETSOCKNAME INTERCEPT_FUNCTION(getsockname);
+#define INIT_GETSOCKNAME COMMON_INTERCEPT_FUNCTION(getsockname);
#else
#define INIT_GETSOCKNAME
#endif
@@ -1137,10 +1180,10 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyaddr, void *addr, int len,
return res;
}
-INTERCEPTOR(struct __sanitizer_hostent *, gethostent) {
+INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, gethostent);
- struct __sanitizer_hostent *res = REAL(gethostent)();
+ COMMON_INTERCEPTOR_ENTER(ctx, gethostent, fake);
+ struct __sanitizer_hostent *res = REAL(gethostent)(fake);
if (res) write_hostent(ctx, res);
return res;
}
@@ -1152,11 +1195,11 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
if (res) write_hostent(ctx, res);
return res;
}
-#define INIT_GETHOSTBYNAME \
- INTERCEPT_FUNCTION(gethostent); \
- INTERCEPT_FUNCTION(gethostbyaddr); \
- INTERCEPT_FUNCTION(gethostbyname); \
- INTERCEPT_FUNCTION(gethostbyname2);
+#define INIT_GETHOSTBYNAME \
+ COMMON_INTERCEPT_FUNCTION(gethostent); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2);
#else
#define INIT_GETHOSTBYNAME
#endif
@@ -1235,11 +1278,11 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af,
}
return res;
}
-#define INIT_GETHOSTBYNAME_R \
- INTERCEPT_FUNCTION(gethostent_r); \
- INTERCEPT_FUNCTION(gethostbyaddr_r); \
- INTERCEPT_FUNCTION(gethostbyname_r); \
- INTERCEPT_FUNCTION(gethostbyname2_r);
+#define INIT_GETHOSTBYNAME_R \
+ COMMON_INTERCEPT_FUNCTION(gethostent_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname_r); \
+ COMMON_INTERCEPT_FUNCTION(gethostbyname2_r);
#else
#define INIT_GETHOSTBYNAME_R
#endif
@@ -1256,7 +1299,7 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval,
if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen);
return res;
}
-#define INIT_GETSOCKOPT INTERCEPT_FUNCTION(getsockopt);
+#define INIT_GETSOCKOPT COMMON_INTERCEPT_FUNCTION(getsockopt);
#else
#define INIT_GETSOCKOPT
#endif
@@ -1272,14 +1315,13 @@ INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
}
int fd2 = REAL(accept)(fd, addr, addrlen);
if (fd2 >= 0) {
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
if (addr && addrlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
}
return fd2;
}
-#define INIT_ACCEPT INTERCEPT_FUNCTION(accept);
+#define INIT_ACCEPT COMMON_INTERCEPT_FUNCTION(accept);
#else
#define INIT_ACCEPT
#endif
@@ -1295,14 +1337,13 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
}
int fd2 = REAL(accept4)(fd, addr, addrlen, f);
if (fd2 >= 0) {
- if (fd >= 0)
- COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
+ if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
if (addr && addrlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(*addrlen, addrlen0));
}
return fd2;
}
-#define INIT_ACCEPT4 INTERCEPT_FUNCTION(accept4);
+#define INIT_ACCEPT4 COMMON_INTERCEPT_FUNCTION(accept4);
#else
#define INIT_ACCEPT4
#endif
@@ -1335,10 +1376,10 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
}
return res;
}
-#define INIT_MODF \
- INTERCEPT_FUNCTION(modf); \
- INTERCEPT_FUNCTION(modff); \
- INTERCEPT_FUNCTION(modfl);
+#define INIT_MODF \
+ COMMON_INTERCEPT_FUNCTION(modf); \
+ COMMON_INTERCEPT_FUNCTION(modff); \
+ COMMON_INTERCEPT_FUNCTION(modfl);
#else
#define INIT_MODF
#endif
@@ -1347,14 +1388,13 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) {
static void write_msghdr(void *ctx, struct __sanitizer_msghdr *msg,
SSIZE_T maxlen) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg, sizeof(*msg));
- if (msg->msg_name)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name,
- REAL(strlen)((char *)msg->msg_name) + 1);
- if (msg->msg_iov)
+ if (msg->msg_name && msg->msg_namelen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_name, msg->msg_namelen);
+ if (msg->msg_iov && msg->msg_iovlen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_iov,
sizeof(*msg->msg_iov) * msg->msg_iovlen);
write_iovec(ctx, msg->msg_iov, msg->msg_iovlen, maxlen);
- if (msg->msg_control)
+ if (msg->msg_control && msg->msg_controllen)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msg->msg_control, msg->msg_controllen);
}
@@ -1365,11 +1405,14 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
if (res >= 0) {
if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
- if (msg) write_msghdr(ctx, msg, res);
+ if (msg) {
+ write_msghdr(ctx, msg, res);
+ COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg);
+ }
}
return res;
}
-#define INIT_RECVMSG INTERCEPT_FUNCTION(recvmsg);
+#define INIT_RECVMSG COMMON_INTERCEPT_FUNCTION(recvmsg);
#else
#define INIT_RECVMSG
#endif
@@ -1385,7 +1428,7 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen));
return res;
}
-#define INIT_GETPEERNAME INTERCEPT_FUNCTION(getpeername);
+#define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername);
#else
#define INIT_GETPEERNAME
#endif
@@ -1399,7 +1442,7 @@ INTERCEPTOR(int, sysinfo, void *info) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, struct_sysinfo_sz);
return res;
}
-#define INIT_SYSINFO INTERCEPT_FUNCTION(sysinfo);
+#define INIT_SYSINFO COMMON_INTERCEPT_FUNCTION(sysinfo);
#else
#define INIT_SYSINFO
#endif
@@ -1409,8 +1452,7 @@ INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp);
__sanitizer_dirent *res = REAL(readdir)(dirp);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
}
@@ -1427,9 +1469,9 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry,
return res;
}
-#define INIT_READDIR \
- INTERCEPT_FUNCTION(readdir); \
- INTERCEPT_FUNCTION(readdir_r);
+#define INIT_READDIR \
+ COMMON_INTERCEPT_FUNCTION(readdir); \
+ COMMON_INTERCEPT_FUNCTION(readdir_r);
#else
#define INIT_READDIR
#endif
@@ -1439,8 +1481,7 @@ INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp);
__sanitizer_dirent64 *res = REAL(readdir64)(dirp);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen);
return res;
}
@@ -1456,9 +1497,9 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry,
}
return res;
}
-#define INIT_READDIR64 \
- INTERCEPT_FUNCTION(readdir64); \
- INTERCEPT_FUNCTION(readdir64_r);
+#define INIT_READDIR64 \
+ COMMON_INTERCEPT_FUNCTION(readdir64); \
+ COMMON_INTERCEPT_FUNCTION(readdir64_r);
#else
#define INIT_READDIR64
#endif
@@ -1504,8 +1545,7 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
return res;
}
-#define INIT_PTRACE \
- INTERCEPT_FUNCTION(ptrace);
+#define INIT_PTRACE COMMON_INTERCEPT_FUNCTION(ptrace);
#else
#define INIT_PTRACE
#endif
@@ -1517,13 +1557,11 @@ INTERCEPTOR(char *, setlocale, int category, char *locale) {
if (locale)
COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
char *res = REAL(setlocale)(category, locale);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_SETLOCALE \
- INTERCEPT_FUNCTION(setlocale);
+#define INIT_SETLOCALE COMMON_INTERCEPT_FUNCTION(setlocale);
#else
#define INIT_SETLOCALE
#endif
@@ -1533,28 +1571,25 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size);
char *res = REAL(getcwd)(buf, size);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_GETCWD \
- INTERCEPT_FUNCTION(getcwd);
+#define INIT_GETCWD COMMON_INTERCEPT_FUNCTION(getcwd);
#else
#define INIT_GETCWD
#endif
#if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
-INTERCEPTOR(char *, get_current_dir_name) {
+INTERCEPTOR(char *, get_current_dir_name, int fake) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name);
- char *res = REAL(get_current_dir_name)();
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake);
+ char *res = REAL(get_current_dir_name)(fake);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_GET_CURRENT_DIR_NAME \
- INTERCEPT_FUNCTION(get_current_dir_name);
+#define INIT_GET_CURRENT_DIR_NAME \
+ COMMON_INTERCEPT_FUNCTION(get_current_dir_name);
#else
#define INIT_GET_CURRENT_DIR_NAME
#endif
@@ -1576,9 +1611,9 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) {
return res;
}
-#define INIT_STRTOIMAX \
- INTERCEPT_FUNCTION(strtoimax); \
- INTERCEPT_FUNCTION(strtoumax);
+#define INIT_STRTOIMAX \
+ COMMON_INTERCEPT_FUNCTION(strtoimax); \
+ COMMON_INTERCEPT_FUNCTION(strtoumax);
#else
#define INIT_STRTOIMAX
#endif
@@ -1611,9 +1646,9 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
return res;
}
-#define INIT_MBSTOWCS \
- INTERCEPT_FUNCTION(mbstowcs); \
- INTERCEPT_FUNCTION(mbsrtowcs);
+#define INIT_MBSTOWCS \
+ COMMON_INTERCEPT_FUNCTION(mbstowcs); \
+ COMMON_INTERCEPT_FUNCTION(mbsrtowcs);
#else
#define INIT_MBSTOWCS
#endif
@@ -1636,7 +1671,7 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
return res;
}
-#define INIT_MBSNRTOWCS INTERCEPT_FUNCTION(mbsnrtowcs);
+#define INIT_MBSNRTOWCS COMMON_INTERCEPT_FUNCTION(mbsnrtowcs);
#else
#define INIT_MBSNRTOWCS
#endif
@@ -1667,9 +1702,9 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
return res;
}
-#define INIT_WCSTOMBS \
- INTERCEPT_FUNCTION(wcstombs); \
- INTERCEPT_FUNCTION(wcsrtombs);
+#define INIT_WCSTOMBS \
+ COMMON_INTERCEPT_FUNCTION(wcstombs); \
+ COMMON_INTERCEPT_FUNCTION(wcsrtombs);
#else
#define INIT_WCSTOMBS
#endif
@@ -1692,12 +1727,11 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
return res;
}
-#define INIT_WCSNRTOMBS INTERCEPT_FUNCTION(wcsnrtombs);
+#define INIT_WCSNRTOMBS COMMON_INTERCEPT_FUNCTION(wcsnrtombs);
#else
#define INIT_WCSNRTOMBS
#endif
-
#if SANITIZER_INTERCEPT_TCGETATTR
INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
void *ctx;
@@ -1708,12 +1742,11 @@ INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
return res;
}
-#define INIT_TCGETATTR INTERCEPT_FUNCTION(tcgetattr);
+#define INIT_TCGETATTR COMMON_INTERCEPT_FUNCTION(tcgetattr);
#else
#define INIT_TCGETATTR
#endif
-
#if SANITIZER_INTERCEPT_REALPATH
INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
void *ctx;
@@ -1729,12 +1762,11 @@ INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
char *res = REAL(realpath)(path, resolved_path);
- if (allocated_path && !res)
- WRAP(free)(allocated_path);
+ if (allocated_path && !res) WRAP(free)(allocated_path);
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_REALPATH INTERCEPT_FUNCTION(realpath);
+#define INIT_REALPATH COMMON_INTERCEPT_FUNCTION(realpath);
#else
#define INIT_REALPATH
#endif
@@ -1748,7 +1780,8 @@ INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_CANONICALIZE_FILE_NAME INTERCEPT_FUNCTION(canonicalize_file_name);
+#define INIT_CANONICALIZE_FILE_NAME \
+ COMMON_INTERCEPT_FUNCTION(canonicalize_file_name);
#else
#define INIT_CANONICALIZE_FILE_NAME
#endif
@@ -1762,7 +1795,7 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
return res;
}
-#define INIT_CONFSTR INTERCEPT_FUNCTION(confstr);
+#define INIT_CONFSTR COMMON_INTERCEPT_FUNCTION(confstr);
#else
#define INIT_CONFSTR
#endif
@@ -1772,11 +1805,10 @@ INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask);
int res = REAL(sched_getaffinity)(pid, cpusetsize, mask);
- if (mask && !res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
+ if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize);
return res;
}
-#define INIT_SCHED_GETAFFINITY INTERCEPT_FUNCTION(sched_getaffinity);
+#define INIT_SCHED_GETAFFINITY COMMON_INTERCEPT_FUNCTION(sched_getaffinity);
#else
#define INIT_SCHED_GETAFFINITY
#endif
@@ -1786,11 +1818,10 @@ INTERCEPTOR(char *, strerror, int errnum) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strerror, errnum);
char *res = REAL(strerror)(errnum);
- if (res)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
return res;
}
-#define INIT_STRERROR INTERCEPT_FUNCTION(strerror);
+#define INIT_STRERROR COMMON_INTERCEPT_FUNCTION(strerror);
#else
#define INIT_STRERROR
#endif
@@ -1818,11 +1849,26 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
}
return res;
}
-#define INIT_STRERROR_R INTERCEPT_FUNCTION(strerror_r);
+#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
#else
#define INIT_STRERROR_R
#endif
+#if SANITIZER_INTERCEPT_XPG_STRERROR_R
+INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen);
+ int res = REAL(__xpg_strerror_r)(errnum, buf, buflen);
+ // This version always returns a null-terminated string.
+ if (buf && buflen)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ return res;
+}
+#define INIT_XPG_STRERROR_R COMMON_INTERCEPT_FUNCTION(__xpg_strerror_r);
+#else
+#define INIT_XPG_STRERROR_R
+#endif
+
#if SANITIZER_INTERCEPT_SCANDIR
typedef int (*scandir_filter_f)(const struct __sanitizer_dirent *);
typedef int (*scandir_compar_f)(const struct __sanitizer_dirent **,
@@ -1871,7 +1917,7 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
}
return res;
}
-#define INIT_SCANDIR INTERCEPT_FUNCTION(scandir);
+#define INIT_SCANDIR COMMON_INTERCEPT_FUNCTION(scandir);
#else
#define INIT_SCANDIR
#endif
@@ -1925,7 +1971,7 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
}
return res;
}
-#define INIT_SCANDIR64 INTERCEPT_FUNCTION(scandir64);
+#define INIT_SCANDIR64 COMMON_INTERCEPT_FUNCTION(scandir64);
#else
#define INIT_SCANDIR64
#endif
@@ -1935,11 +1981,10 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst);
int res = REAL(getgroups)(size, lst);
- if (res && lst)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+ if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
return res;
}
-#define INIT_GETGROUPS INTERCEPT_FUNCTION(getgroups);
+#define INIT_GETGROUPS COMMON_INTERCEPT_FUNCTION(getgroups);
#else
#define INIT_GETGROUPS
#endif
@@ -1969,7 +2014,7 @@ INTERCEPTOR(int, poll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
if (fds && nfds) write_pollfd(ctx, fds, nfds);
return res;
}
-#define INIT_POLL INTERCEPT_FUNCTION(poll);
+#define INIT_POLL COMMON_INTERCEPT_FUNCTION(poll);
#else
#define INIT_POLL
#endif
@@ -1988,7 +2033,7 @@ INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
if (fds && nfds) write_pollfd(ctx, fds, nfds);
return res;
}
-#define INIT_PPOLL INTERCEPT_FUNCTION(ppoll);
+#define INIT_PPOLL COMMON_INTERCEPT_FUNCTION(ppoll);
#else
#define INIT_PPOLL
#endif
@@ -2011,7 +2056,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
}
return res;
}
-#define INIT_WORDEXP INTERCEPT_FUNCTION(wordexp);
+#define INIT_WORDEXP COMMON_INTERCEPT_FUNCTION(wordexp);
#else
#define INIT_WORDEXP
#endif
@@ -2025,7 +2070,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
return res;
}
-#define INIT_SIGWAIT INTERCEPT_FUNCTION(sigwait);
+#define INIT_SIGWAIT COMMON_INTERCEPT_FUNCTION(sigwait);
#else
#define INIT_SIGWAIT
#endif
@@ -2039,7 +2084,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
}
-#define INIT_SIGWAITINFO INTERCEPT_FUNCTION(sigwaitinfo);
+#define INIT_SIGWAITINFO COMMON_INTERCEPT_FUNCTION(sigwaitinfo);
#else
#define INIT_SIGWAITINFO
#endif
@@ -2055,7 +2100,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
return res;
}
-#define INIT_SIGTIMEDWAIT INTERCEPT_FUNCTION(sigtimedwait);
+#define INIT_SIGTIMEDWAIT COMMON_INTERCEPT_FUNCTION(sigtimedwait);
#else
#define INIT_SIGTIMEDWAIT
#endif
@@ -2076,9 +2121,9 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) {
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
}
-#define INIT_SIGSETOPS \
- INTERCEPT_FUNCTION(sigemptyset); \
- INTERCEPT_FUNCTION(sigfillset);
+#define INIT_SIGSETOPS \
+ COMMON_INTERCEPT_FUNCTION(sigemptyset); \
+ COMMON_INTERCEPT_FUNCTION(sigfillset);
#else
#define INIT_SIGSETOPS
#endif
@@ -2091,7 +2136,7 @@ INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) {
if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set));
return res;
}
-#define INIT_SIGPENDING INTERCEPT_FUNCTION(sigpending);
+#define INIT_SIGPENDING COMMON_INTERCEPT_FUNCTION(sigpending);
#else
#define INIT_SIGPENDING
#endif
@@ -2107,7 +2152,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset));
return res;
}
-#define INIT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask);
+#define INIT_SIGPROCMASK COMMON_INTERCEPT_FUNCTION(sigprocmask);
#else
#define INIT_SIGPROCMASK
#endif
@@ -2127,7 +2172,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size);
if (buffer && size)
COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer));
- char ** res = REAL(backtrace_symbols)(buffer, size);
+ char **res = REAL(backtrace_symbols)(buffer, size);
if (res && size) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res));
for (int i = 0; i < size; ++i)
@@ -2135,13 +2180,716 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
}
return res;
}
-#define INIT_BACKTRACE \
- INTERCEPT_FUNCTION(backtrace); \
- INTERCEPT_FUNCTION(backtrace_symbols);
+#define INIT_BACKTRACE \
+ COMMON_INTERCEPT_FUNCTION(backtrace); \
+ COMMON_INTERCEPT_FUNCTION(backtrace_symbols);
#else
#define INIT_BACKTRACE
#endif
+#if SANITIZER_INTERCEPT__EXIT
+INTERCEPTOR(void, _exit, int status) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, _exit, status);
+ int status1 = COMMON_INTERCEPTOR_ON_EXIT(ctx);
+ if (status == 0) status = status1;
+ REAL(_exit)(status);
+}
+#define INIT__EXIT COMMON_INTERCEPT_FUNCTION(_exit);
+#else
+#define INIT__EXIT
+#endif
+
+#if SANITIZER_INTERCEPT_PHTREAD_MUTEX
+INTERCEPTOR(int, pthread_mutex_lock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
+ int res = REAL(pthread_mutex_lock)(m);
+ if (res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ return REAL(pthread_mutex_unlock)(m);
+}
+
+#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
+#define INIT_PTHREAD_MUTEX_UNLOCK \
+ COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock)
+#else
+#define INIT_PTHREAD_MUTEX_LOCK
+#define INIT_PTHREAD_MUTEX_UNLOCK
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_COND
+INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_wait, c, m);
+ COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
+ int res = REAL(pthread_cond_wait)(c, m);
+ COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ return res;
+}
+
+INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_init, c, a);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, c, pthread_cond_t_sz);
+ return REAL(pthread_cond_init)(c, a);
+}
+
+INTERCEPTOR(int, pthread_cond_signal, void *c) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_signal, c);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
+ return REAL(pthread_cond_signal)(c);
+}
+
+INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_cond_broadcast, c);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, c, pthread_cond_t_sz);
+ return REAL(pthread_cond_broadcast)(c);
+}
+
+#define INIT_PTHREAD_COND_WAIT \
+ INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2")
+#define INIT_PTHREAD_COND_INIT \
+ INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2")
+#define INIT_PTHREAD_COND_SIGNAL \
+ INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2")
+#define INIT_PTHREAD_COND_BROADCAST \
+ INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2")
+#else
+#define INIT_PTHREAD_COND_WAIT
+#define INIT_PTHREAD_COND_INIT
+#define INIT_PTHREAD_COND_SIGNAL
+#define INIT_PTHREAD_COND_BROADCAST
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT || SANITIZER_INTERCEPT_GETMNTENT_R
+static void write_mntent(void *ctx, __sanitizer_mntent *mnt) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt, sizeof(*mnt));
+ if (mnt->mnt_fsname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_fsname,
+ REAL(strlen)(mnt->mnt_fsname) + 1);
+ if (mnt->mnt_dir)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_dir,
+ REAL(strlen)(mnt->mnt_dir) + 1);
+ if (mnt->mnt_type)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_type,
+ REAL(strlen)(mnt->mnt_type) + 1);
+ if (mnt->mnt_opts)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mnt->mnt_opts,
+ REAL(strlen)(mnt->mnt_opts) + 1);
+}
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT
+INTERCEPTOR(__sanitizer_mntent *, getmntent, void *fp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent, fp);
+ __sanitizer_mntent *res = REAL(getmntent)(fp);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT COMMON_INTERCEPT_FUNCTION(getmntent);
+#else
+#define INIT_GETMNTENT
+#endif
+
+#if SANITIZER_INTERCEPT_GETMNTENT_R
+INTERCEPTOR(__sanitizer_mntent *, getmntent_r, void *fp,
+ __sanitizer_mntent *mntbuf, char *buf, int buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getmntent_r, fp, mntbuf, buf, buflen);
+ __sanitizer_mntent *res = REAL(getmntent_r)(fp, mntbuf, buf, buflen);
+ if (res) write_mntent(ctx, res);
+ return res;
+}
+#define INIT_GETMNTENT_R COMMON_INTERCEPT_FUNCTION(getmntent_r);
+#else
+#define INIT_GETMNTENT_R
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS
+INTERCEPTOR(int, statfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf);
+ int res = REAL(fstatfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz);
+ return res;
+}
+#define INIT_STATFS \
+ COMMON_INTERCEPT_FUNCTION(statfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs);
+#else
+#define INIT_STATFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATFS64
+INTERCEPTOR(int, statfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf);
+ int res = REAL(fstatfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz);
+ return res;
+}
+#define INIT_STATFS64 \
+ COMMON_INTERCEPT_FUNCTION(statfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatfs64);
+#else
+#define INIT_STATFS64
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS
+INTERCEPTOR(int, statvfs, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statvfs)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+ int res = REAL(fstatvfs)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+ return res;
+}
+#define INIT_STATVFS \
+ COMMON_INTERCEPT_FUNCTION(statvfs); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs);
+#else
+#define INIT_STATVFS
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS64
+INTERCEPTOR(int, statvfs64, char *path, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, buf);
+ if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+ int res = REAL(statvfs64)(path, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+INTERCEPTOR(int, fstatvfs64, int fd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf);
+ int res = REAL(fstatvfs64)(fd, buf);
+ if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz);
+ return res;
+}
+#define INIT_STATVFS64 \
+ COMMON_INTERCEPT_FUNCTION(statvfs64); \
+ COMMON_INTERCEPT_FUNCTION(fstatvfs64);
+#else
+#define INIT_STATVFS64
+#endif
+
+#if SANITIZER_INTERCEPT_INITGROUPS
+INTERCEPTOR(int, initgroups, char *user, u32 group) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, initgroups, user, group);
+ if (user) COMMON_INTERCEPTOR_READ_RANGE(ctx, user, REAL(strlen)(user) + 1);
+ int res = REAL(initgroups)(user, group);
+ return res;
+}
+#define INIT_INITGROUPS COMMON_INTERCEPT_FUNCTION(initgroups);
+#else
+#define INIT_INITGROUPS
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER
+INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ char *res = REAL(ether_ntoa)(addr);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton, buf);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ __sanitizer_ether_addr *res = REAL(ether_aton)(buf);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, sizeof(*res));
+ return res;
+}
+INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, addr);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ int res = REAL(ether_ntohost)(hostname, addr);
+ if (!res && hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ return res;
+}
+INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr);
+ if (hostname)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ int res = REAL(ether_hostton)(hostname, addr);
+ if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ return res;
+}
+INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr,
+ char *hostname) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname);
+ if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1);
+ int res = REAL(ether_line)(line, addr, hostname);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (hostname)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1);
+ }
+ return res;
+}
+#define INIT_ETHER \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton); \
+ COMMON_INTERCEPT_FUNCTION(ether_ntohost); \
+ COMMON_INTERCEPT_FUNCTION(ether_hostton); \
+ COMMON_INTERCEPT_FUNCTION(ether_line);
+#else
+#define INIT_ETHER
+#endif
+
+#if SANITIZER_INTERCEPT_ETHER_R
+INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, buf);
+ if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr));
+ char *res = REAL(ether_ntoa_r)(addr, buf);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf,
+ __sanitizer_ether_addr *addr) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr);
+ if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+ __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr);
+ if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res));
+ return res;
+}
+#define INIT_ETHER_R \
+ COMMON_INTERCEPT_FUNCTION(ether_ntoa_r); \
+ COMMON_INTERCEPT_FUNCTION(ether_aton_r);
+#else
+#define INIT_ETHER_R
+#endif
+
+#if SANITIZER_INTERCEPT_SHMCTL
+INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf);
+ int res = REAL(shmctl)(shmid, cmd, buf);
+ if (res >= 0) {
+ unsigned sz = 0;
+ if (cmd == shmctl_ipc_stat || cmd == shmctl_shm_stat)
+ sz = sizeof(__sanitizer_shmid_ds);
+ else if (cmd == shmctl_ipc_info)
+ sz = struct_shminfo_sz;
+ else if (cmd == shmctl_shm_info)
+ sz = struct_shm_info_sz;
+ if (sz) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ }
+ return res;
+}
+#define INIT_SHMCTL COMMON_INTERCEPT_FUNCTION(shmctl);
+#else
+#define INIT_SHMCTL
+#endif
+
+#if SANITIZER_INTERCEPT_RANDOM_R
+INTERCEPTOR(int, random_r, void *buf, u32 *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result);
+ int res = REAL(random_r)(buf, result);
+ if (!res && result)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_RANDOM_R COMMON_INTERCEPT_FUNCTION(random_r);
+#else
+#define INIT_RANDOM_R
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \
+ SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED
+#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \
+ INTERCEPTOR(int, pthread_attr_get##what, void *attr, void *r) { \
+ void *ctx; \
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_get##what, attr, r); \
+ int res = REAL(pthread_attr_get##what)(attr, r); \
+ if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \
+ return res; \
+ }
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET
+INTERCEPTOR_PTHREAD_ATTR_GET(detachstate, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(guardsize, sizeof(SIZE_T))
+INTERCEPTOR_PTHREAD_ATTR_GET(schedparam, struct_sched_param_sz)
+INTERCEPTOR_PTHREAD_ATTR_GET(schedpolicy, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(scope, sizeof(int))
+INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T))
+INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size);
+ int res = REAL(pthread_attr_getstack)(attr, addr, size);
+ if (!res) {
+ if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr));
+ if (size) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, size, sizeof(*size));
+ }
+ return res;
+}
+
+// We may need to call the real pthread_attr_getstack from the run-time
+// in sanitizer_common, but we don't want to include the interception headers
+// there. So, just define this function here.
+int __sanitizer_pthread_attr_getstack(void *attr, void **addr, SIZE_T *size) {
+ return REAL(pthread_attr_getstack)(attr, addr, size);
+}
+
+#define INIT_PTHREAD_ATTR_GET \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getdetachstate); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getguardsize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedparam); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getschedpolicy); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getscope); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstacksize); \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getstack);
+#else
+#define INIT_PTHREAD_ATTR_GET
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED
+INTERCEPTOR_PTHREAD_ATTR_GET(inheritsched, sizeof(int))
+
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getinheritsched);
+#else
+#define INIT_PTHREAD_ATTR_GETINHERITSCHED
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP
+INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize,
+ void *cpuset) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, cpusetsize,
+ cpuset);
+ int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset);
+ if (!res && cpusetsize && cpuset)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize);
+ return res;
+}
+
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP \
+ COMMON_INTERCEPT_FUNCTION(pthread_attr_getaffinity_np);
+#else
+#define INIT_PTHREAD_ATTR_GETAFFINITY_NP
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM
+INTERCEPTOR(char *, tmpnam, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam, s);
+ char *res = REAL(tmpnam)(s);
+ if (res) {
+ if (s)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ else
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ }
+ return res;
+}
+#define INIT_TMPNAM COMMON_INTERCEPT_FUNCTION(tmpnam);
+#else
+#define INIT_TMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_TMPNAM_R
+INTERCEPTOR(char *, tmpnam_r, char *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s);
+ char *res = REAL(tmpnam_r)(s);
+ if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1);
+ return res;
+}
+#define INIT_TMPNAM_R COMMON_INTERCEPT_FUNCTION(tmpnam_r);
+#else
+#define INIT_TMPNAM_R
+#endif
+
+#if SANITIZER_INTERCEPT_TEMPNAM
+INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, tempnam, dir, pfx);
+ if (dir) COMMON_INTERCEPTOR_READ_RANGE(ctx, dir, REAL(strlen)(dir) + 1);
+ if (pfx) COMMON_INTERCEPTOR_READ_RANGE(ctx, pfx, REAL(strlen)(pfx) + 1);
+ char *res = REAL(tempnam)(dir, pfx);
+ if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+ return res;
+}
+#define INIT_TEMPNAM COMMON_INTERCEPT_FUNCTION(tempnam);
+#else
+#define INIT_TEMPNAM
+#endif
+
+#if SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP
+INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, pthread_setname_np, thread, name);
+ COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name);
+ return REAL(pthread_setname_np)(thread, name);
+}
+#define INIT_PTHREAD_SETNAME_NP COMMON_INTERCEPT_FUNCTION(pthread_setname_np);
+#else
+#define INIT_PTHREAD_SETNAME_NP
+#endif
+
+#if SANITIZER_INTERCEPT_SINCOS
+INTERCEPTOR(void, sincos, double x, double *sin, double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos);
+ REAL(sincos)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos);
+ REAL(sincosf)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos);
+ REAL(sincosl)(x, sin, cos);
+ if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin));
+ if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos));
+}
+#define INIT_SINCOS \
+ COMMON_INTERCEPT_FUNCTION(sincos); \
+ COMMON_INTERCEPT_FUNCTION(sincosf); \
+ COMMON_INTERCEPT_FUNCTION(sincosl);
+#else
+#define INIT_SINCOS
+#endif
+
+#if SANITIZER_INTERCEPT_REMQUO
+INTERCEPTOR(double, remquo, double x, double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo);
+ double res = REAL(remquo)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(float, remquof, float x, float y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo);
+ float res = REAL(remquof)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo);
+ long double res = REAL(remquol)(x, y, quo);
+ if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo));
+ return res;
+}
+#define INIT_REMQUO \
+ COMMON_INTERCEPT_FUNCTION(remquo); \
+ COMMON_INTERCEPT_FUNCTION(remquof); \
+ COMMON_INTERCEPT_FUNCTION(remquol);
+#else
+#define INIT_REMQUO
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA
+extern int signgam;
+INTERCEPTOR(double, lgamma, double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma, x);
+ double res = REAL(lgamma)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(float, lgammaf, float x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf, x);
+ float res = REAL(lgammaf)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+INTERCEPTOR(long double, lgammal, long double x) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal, x);
+ long double res = REAL(lgammal)(x);
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &signgam, sizeof(signgam));
+ return res;
+}
+#define INIT_LGAMMA \
+ COMMON_INTERCEPT_FUNCTION(lgamma); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf); \
+ COMMON_INTERCEPT_FUNCTION(lgammal);
+#else
+#define INIT_LGAMMA
+#endif
+
+#if SANITIZER_INTERCEPT_LGAMMA_R
+INTERCEPTOR(double, lgamma_r, double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp);
+ double res = REAL(lgamma_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(float, lgammaf_r, float x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp);
+ float res = REAL(lgammaf_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+INTERCEPTOR(long double, lgammal_r, long double x, int *signp) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp);
+ long double res = REAL(lgammal_r)(x, signp);
+ if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp));
+ return res;
+}
+#define INIT_LGAMMA_R \
+ COMMON_INTERCEPT_FUNCTION(lgamma_r); \
+ COMMON_INTERCEPT_FUNCTION(lgammaf_r); \
+ COMMON_INTERCEPT_FUNCTION(lgammal_r);
+#else
+#define INIT_LGAMMA_R
+#endif
+
+#if SANITIZER_INTERCEPT_DRAND48_R
+INTERCEPTOR(int, drand48_r, void *buffer, double *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result);
+ int res = REAL(drand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+INTERCEPTOR(int, lrand48_r, void *buffer, long *result) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result);
+ int res = REAL(lrand48_r)(buffer, result);
+ if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
+ return res;
+}
+#define INIT_DRAND48_R \
+ COMMON_INTERCEPT_FUNCTION(drand48_r); \
+ COMMON_INTERCEPT_FUNCTION(lrand48_r);
+#else
+#define INIT_DRAND48_R
+#endif
+
+#if SANITIZER_INTERCEPT_GETLINE
+INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream);
+ SSIZE_T res = REAL(getline)(lineptr, n, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim,
+ void *stream) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getdelim, lineptr, n, delim, stream);
+ SSIZE_T res = REAL(getdelim)(lineptr, n, delim, stream);
+ if (res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *lineptr, res + 1);
+ }
+ return res;
+}
+#define INIT_GETLINE \
+ COMMON_INTERCEPT_FUNCTION(getline); \
+ COMMON_INTERCEPT_FUNCTION(getdelim);
+#else
+#define INIT_GETLINE
+#endif
+
+#if SANITIZER_INTERCEPT_ICONV
+INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
+ char **outbuf, SIZE_T *outbytesleft) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, iconv, cd, inbuf, inbytesleft, outbuf,
+ outbytesleft);
+ if (inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, inbytesleft, sizeof(*inbytesleft));
+ if (inbuf && inbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft);
+ if (outbytesleft)
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft));
+ void *outbuf_orig = outbuf ? *outbuf : 0;
+ SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
+ if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
+ SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
+ }
+ return res;
+}
+#define INIT_ICONV COMMON_INTERCEPT_FUNCTION(iconv);
+#else
+#define INIT_ICONV
+#endif
+
+#if SANITIZER_INTERCEPT_TIMES
+INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, times, tms);
+ __sanitizer_clock_t res = REAL(times)(tms);
+ if (res != (__sanitizer_clock_t)-1 && tms)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz);
+ return res;
+}
+#define INIT_TIMES COMMON_INTERCEPT_FUNCTION(times);
+#else
+#define INIT_TIMES
+#endif
+
#define SANITIZER_COMMON_INTERCEPTORS_INIT \
INIT_STRCMP; \
INIT_STRNCMP; \
@@ -2161,6 +2909,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
INIT_PWRITEV64; \
INIT_PRCTL; \
INIT_LOCALTIME_AND_FRIENDS; \
+ INIT_STRPTIME; \
INIT_SCANF; \
INIT_ISOC99_SCANF; \
INIT_FREXP; \
@@ -2206,6 +2955,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
INIT_SCHED_GETAFFINITY; \
INIT_STRERROR; \
INIT_STRERROR_R; \
+ INIT_XPG_STRERROR_R; \
INIT_SCANDIR; \
INIT_SCANDIR64; \
INIT_GETGROUPS; \
@@ -2218,4 +2968,38 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) {
INIT_SIGSETOPS; \
INIT_SIGPENDING; \
INIT_SIGPROCMASK; \
- INIT_BACKTRACE;
+ INIT_BACKTRACE; \
+ INIT__EXIT; \
+ INIT_PTHREAD_MUTEX_LOCK; \
+ INIT_PTHREAD_MUTEX_UNLOCK; \
+ INIT_PTHREAD_COND_WAIT; \
+ INIT_PTHREAD_COND_INIT; \
+ INIT_PTHREAD_COND_SIGNAL; \
+ INIT_PTHREAD_COND_BROADCAST; \
+ INIT_GETMNTENT; \
+ INIT_GETMNTENT_R; \
+ INIT_STATFS; \
+ INIT_STATFS64; \
+ INIT_STATVFS; \
+ INIT_STATVFS64; \
+ INIT_INITGROUPS; \
+ INIT_ETHER; \
+ INIT_ETHER_R; \
+ INIT_SHMCTL; \
+ INIT_RANDOM_R; \
+ INIT_PTHREAD_ATTR_GET; \
+ INIT_PTHREAD_ATTR_GETINHERITSCHED; \
+ INIT_PTHREAD_ATTR_GETAFFINITY_NP; \
+ INIT_TMPNAM; \
+ INIT_TMPNAM_R; \
+ INIT_TEMPNAM; \
+ INIT_PTHREAD_SETNAME_NP; \
+ INIT_SINCOS; \
+ INIT_REMQUO; \
+ INIT_LGAMMA; \
+ INIT_LGAMMA_R; \
+ INIT_DRAND48_R; \
+ INIT_GETLINE; \
+ INIT_ICONV; \
+ INIT_TIMES; \
+/**/
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 50db0d71d89..ac8cdae5b81 100755
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -86,7 +86,7 @@ static void ioctl_table_fill() {
_(TIOCSTI, READ, sizeof(char));
_(TIOCSWINSZ, READ, struct_winsize_sz);
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
_(SIOCGETSGCNT, WRITE, struct_sioc_sg_req_sz);
_(SIOCGETVIFCNT, WRITE, struct_sioc_vif_req_sz);
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
index ae6a6304dba..75f7d1d1e89 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
@@ -23,8 +23,16 @@
// COMMON_SYSCALL_POST_WRITE_RANGE
// Called in posthook for regions that were written to by the kernel
// and are now initialized.
+// COMMON_SYSCALL_ACQUIRE(addr)
+// Acquire memory visibility from addr.
+// COMMON_SYSCALL_RELEASE(addr)
+// Release memory visibility to addr.
// COMMON_SYSCALL_FD_CLOSE(fd)
// Called before closing file descriptor fd.
+// COMMON_SYSCALL_FD_ACQUIRE(fd)
+// Acquire memory visibility from fd.
+// COMMON_SYSCALL_FD_RELEASE(fd)
+// Release memory visibility to fd.
// COMMON_SYSCALL_PRE_FORK()
// Called before fork syscall.
// COMMON_SYSCALL_POST_FORK(long res)
@@ -46,20 +54,34 @@
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
+#ifndef COMMON_SYSCALL_ACQUIRE
+# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
+#endif
+
+#ifndef COMMON_SYSCALL_RELEASE
+# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
+#endif
+
#ifndef COMMON_SYSCALL_FD_CLOSE
-# define COMMON_SYSCALL_FD_CLOSE(fd)
+# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_ACQUIRE
+# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
+#endif
+
+#ifndef COMMON_SYSCALL_FD_RELEASE
+# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
#endif
#ifndef COMMON_SYSCALL_PRE_FORK
-# define COMMON_SYSCALL_PRE_FORK()
+# define COMMON_SYSCALL_PRE_FORK() {}
#endif
#ifndef COMMON_SYSCALL_POST_FORK
-# define COMMON_SYSCALL_POST_FORK(res)
+# define COMMON_SYSCALL_POST_FORK(res) {}
#endif
-#ifdef SYSCALL_INTERCEPTION
-
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
extern "C" {
@@ -1245,11 +1267,17 @@ PRE_SYSCALL(flock)(long fd, long cmd) {}
POST_SYSCALL(flock)(long res, long fd, long cmd) {}
-PRE_SYSCALL(io_setup)(long nr_reqs, void *ctx) {}
+PRE_SYSCALL(io_setup)(long nr_reqs, void **ctx) {
+ if (ctx) PRE_WRITE(ctx, sizeof(*ctx));
+}
-POST_SYSCALL(io_setup)(long res, long nr_reqs, void *ctx) {
+POST_SYSCALL(io_setup)(long res, long nr_reqs, void **ctx) {
if (res >= 0) {
- if (ctx) POST_WRITE(ctx, sizeof(long));
+ if (ctx) POST_WRITE(ctx, sizeof(*ctx));
+ // (*ctx) is actually a pointer to a kernel mapped page, and there are
+ // people out there who are crazy enough to peek into that page's 32-byte
+ // header.
+ if (*ctx) POST_WRITE(*ctx, 32);
}
}
@@ -1257,29 +1285,70 @@ PRE_SYSCALL(io_destroy)(long ctx) {}
POST_SYSCALL(io_destroy)(long res, long ctx) {}
-PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr, void *events,
- void *timeout) {
+PRE_SYSCALL(io_getevents)(long ctx_id, long min_nr, long nr,
+ __sanitizer_io_event *ioevpp, void *timeout) {
if (timeout) PRE_READ(timeout, struct_timespec_sz);
}
POST_SYSCALL(io_getevents)(long res, long ctx_id, long min_nr, long nr,
- void *events, void *timeout) {
+ __sanitizer_io_event *ioevpp, void *timeout) {
if (res >= 0) {
- if (events) POST_WRITE(events, res * struct_io_event_sz);
+ if (ioevpp) POST_WRITE(ioevpp, res * sizeof(*ioevpp));
if (timeout) POST_WRITE(timeout, struct_timespec_sz);
}
+ for (long i = 0; i < res; i++) {
+ // We synchronize io_submit -> io_getevents/io_cancel using the
+ // user-provided data context. Data is not necessary a pointer, it can be
+ // an int, 0 or whatever; acquire/release will correctly handle this.
+ // This scheme can lead to false negatives, e.g. when all operations
+ // synchronize on 0. But there does not seem to be a better solution
+ // (except wrapping all operations in own context, which is unreliable).
+ // We can not reliably extract fildes in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)ioevpp[i].data);
+ }
+}
+
+PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) {
+ for (long i = 0; i < nr; ++i) {
+ uptr op = iocbpp[i]->aio_lio_opcode;
+ void *data = (void*)iocbpp[i]->aio_data;
+ void *buf = (void*)iocbpp[i]->aio_buf;
+ uptr len = (uptr)iocbpp[i]->aio_nbytes;
+ if (op == iocb_cmd_pwrite && buf && len) {
+ PRE_READ(buf, len);
+ } else if (op == iocb_cmd_pread && buf && len) {
+ POST_WRITE(buf, len);
+ } else if (op == iocb_cmd_pwritev) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
+ for (uptr v = 0; v < len; v++)
+ PRE_READ(iovec[i].iov_base, iovec[i].iov_len);
+ } else if (op == iocb_cmd_preadv) {
+ __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf;
+ for (uptr v = 0; v < len; v++)
+ POST_WRITE(iovec[i].iov_base, iovec[i].iov_len);
+ }
+ // See comment in io_getevents.
+ COMMON_SYSCALL_RELEASE(data);
+ }
}
-PRE_SYSCALL(io_submit)(long, long arg1, void *arg2) {}
-
-POST_SYSCALL(io_submit)(long res, long, long arg1, void *arg2) {}
+POST_SYSCALL(io_submit)(long res, long ctx_id, long nr,
+ __sanitizer_iocb **iocbpp) {}
-PRE_SYSCALL(io_cancel)(long ctx_id, void *iocb, void *result) {}
+PRE_SYSCALL(io_cancel)(long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+}
-POST_SYSCALL(io_cancel)(long res, long ctx_id, void *iocb, void *result) {
- if (res >= 0) {
- if (iocb) POST_WRITE(iocb, struct_iocb_sz);
- if (result) POST_WRITE(result, struct_io_event_sz);
+POST_SYSCALL(io_cancel)(long res, long ctx_id, __sanitizer_iocb *iocb,
+ __sanitizer_io_event *result) {
+ if (res == 0) {
+ if (result) {
+ // See comment in io_getevents.
+ COMMON_SYSCALL_ACQUIRE((void*)result->data);
+ POST_WRITE(result, sizeof(*result));
+ }
+ if (iocb)
+ POST_WRITE(iocb, sizeof(*iocb));
}
}
@@ -2063,14 +2132,6 @@ POST_SYSCALL(shmdt)(long res, void *shmaddr) {
}
}
-PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {}
-
-POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) {
- if (res >= 0) {
- if (buf) POST_WRITE(buf, struct_shmid_ds_sz);
- }
-}
-
PRE_SYSCALL(ipc)(long call, long first, long second, long third, void *ptr,
long fifth) {}
@@ -2078,6 +2139,14 @@ POST_SYSCALL(ipc)(long res, long call, long first, long second, long third,
void *ptr, long fifth) {}
#if !SANITIZER_ANDROID
+PRE_SYSCALL(shmctl)(long shmid, long cmd, void *buf) {}
+
+POST_SYSCALL(shmctl)(long res, long shmid, long cmd, void *buf) {
+ if (res >= 0) {
+ if (buf) POST_WRITE(buf, sizeof(__sanitizer_shmid_ds));
+ }
+}
+
PRE_SYSCALL(mq_open)(const void *name, long oflag, long mode, void *attr) {
if (name)
PRE_READ(name, __sanitizer::internal_strlen((const char *)name) + 1);
@@ -2218,9 +2287,49 @@ PRE_SYSCALL(ni_syscall)() {}
POST_SYSCALL(ni_syscall)(long res) {}
-PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {}
+PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
+#if defined(__i386) || defined (__x86_64)
+ if (data) {
+ if (request == ptrace_setregs) {
+ PRE_READ((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_setfpregs) {
+ PRE_READ((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_setfpxregs) {
+ PRE_READ((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_setsiginfo) {
+ PRE_READ((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_setregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ PRE_READ(iov->iov_base, iov->iov_len);
+ }
+ }
+#endif
+}
-POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {}
+POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
+#if defined(__i386) || defined (__x86_64)
+ if (res >= 0 && data) {
+ // Note that this is different from the interceptor in
+ // sanitizer_common_interceptors.inc.
+ // PEEK* requests return resulting values through data pointer.
+ if (request == ptrace_getregs) {
+ POST_WRITE((void *)data, struct_user_regs_struct_sz);
+ } else if (request == ptrace_getfpregs) {
+ POST_WRITE((void *)data, struct_user_fpregs_struct_sz);
+ } else if (request == ptrace_getfpxregs) {
+ POST_WRITE((void *)data, struct_user_fpxregs_struct_sz);
+ } else if (request == ptrace_getsiginfo) {
+ POST_WRITE((void *)data, siginfo_t_sz);
+ } else if (request == ptrace_getregset) {
+ __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+ POST_WRITE(iov->iov_base, iov->iov_len);
+ } else if (request == ptrace_peekdata || request == ptrace_peektext ||
+ request == ptrace_peekuser) {
+ POST_WRITE((void *)data, sizeof(void *));
+ }
+ }
+#endif
+}
PRE_SYSCALL(add_key)(const void *_type, const void *_description,
const void *_payload, long plen, long destringid) {
@@ -2648,16 +2757,14 @@ PRE_SYSCALL(syncfs)(long fd) {}
POST_SYSCALL(syncfs)(long res, long fd) {}
-PRE_SYSCALL(perf_event_open)(void *attr_uptr, long pid, long cpu, long group_fd,
- long flags) {}
-
-POST_SYSCALL(perf_event_open)(long res, void *attr_uptr, long pid, long cpu,
- long group_fd, long flags) {
- if (res >= 0) {
- if (attr_uptr) POST_WRITE(attr_uptr, struct_perf_event_attr_sz);
- }
+PRE_SYSCALL(perf_event_open)(__sanitizer_perf_event_attr *attr_uptr, long pid,
+ long cpu, long group_fd, long flags) {
+ if (attr_uptr) PRE_READ(attr_uptr, attr_uptr->size);
}
+POST_SYSCALL(perf_event_open)(long res, __sanitizer_perf_event_attr *attr_uptr,
+ long pid, long cpu, long group_fd, long flags) {}
+
PRE_SYSCALL(mmap_pgoff)(long addr, long len, long prot, long flags, long fd,
long pgoff) {}
@@ -2724,8 +2831,6 @@ POST_SYSCALL(vfork)(long res) {
}
} // extern "C"
-#endif
-
#undef PRE_SYSCALL
#undef PRE_READ
#undef PRE_WRITE
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage.cc b/libsanitizer/sanitizer_common/sanitizer_coverage.cc
new file mode 100644
index 00000000000..e87b76c0081
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage.cc
@@ -0,0 +1,111 @@
+//===-- sanitizer_coverage.cc ---------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage.
+// This file implements run-time support for a poor man's coverage tool.
+//
+// Compiler instrumentation:
+// For every function F the compiler injects the following code:
+// if (*Guard) {
+// __sanitizer_cov(&F);
+// *Guard = 1;
+// }
+// It's fine to call __sanitizer_cov more than once for a given function.
+//
+// Run-time:
+// - __sanitizer_cov(pc): record that we've executed a given PC.
+// - __sanitizer_cov_dump: dump the coverage data to disk.
+// For every module of the current process that has coverage data
+// this will create a file module_name.PID.sancov. The file format is simple:
+// it's just a sorted sequence of 4-byte offsets in the module.
+//
+// Eventually, this coverage implementation should be obsoleted by a more
+// powerful general purpose Clang/LLVM coverage instrumentation.
+// Consider this implementation as prototype.
+//
+// FIXME: support (or at least test with) dlclose.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_flags.h"
+
+struct CovData {
+ BlockingMutex mu;
+ InternalMmapVector<uptr> v;
+};
+
+static uptr cov_data_placeholder[sizeof(CovData) / sizeof(uptr)];
+COMPILER_CHECK(sizeof(cov_data_placeholder) >= sizeof(CovData));
+static CovData *cov_data = reinterpret_cast<CovData*>(cov_data_placeholder);
+
+namespace __sanitizer {
+
+// Simply add the pc into the vector under lock. If the function is called more
+// than once for a given PC it will be inserted multiple times, which is fine.
+static void CovAdd(uptr pc) {
+ BlockingMutexLock lock(&cov_data->mu);
+ cov_data->v.push_back(pc);
+}
+
+static inline bool CompareLess(const uptr &a, const uptr &b) {
+ return a < b;
+}
+
+// Dump the coverage on disk.
+void CovDump() {
+#if !SANITIZER_WINDOWS
+ BlockingMutexLock lock(&cov_data->mu);
+ InternalMmapVector<uptr> &v = cov_data->v;
+ InternalSort(&v, v.size(), CompareLess);
+ InternalMmapVector<u32> offsets(v.size());
+ const uptr *vb = v.data();
+ const uptr *ve = vb + v.size();
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ uptr mb, me, off, prot;
+ InternalScopedBuffer<char> module(4096);
+ InternalScopedBuffer<char> path(4096 * 2);
+ for (int i = 0;
+ proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot);
+ i++) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ if (vb >= ve) break;
+ if (mb <= *vb && *vb < me) {
+ offsets.clear();
+ const uptr *old_vb = vb;
+ CHECK_LE(off, *vb);
+ for (; vb < ve && *vb < me; vb++) {
+ uptr diff = *vb - (i ? mb : 0) + off;
+ CHECK_LE(diff, 0xffffffffU);
+ offsets.push_back(static_cast<u32>(diff));
+ }
+ char *module_name = StripModuleName(module.data());
+ internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov",
+ module_name, internal_getpid());
+ InternalFree(module_name);
+ uptr fd = OpenFile(path.data(), true);
+ internal_write(fd, offsets.data(), offsets.size() * sizeof(u32));
+ internal_close(fd);
+ if (common_flags()->verbosity)
+ Report(" CovDump: %s: %zd PCs written\n", path.data(), vb - old_vb);
+ }
+ }
+#endif // !SANITIZER_WINDOWS
+}
+
+} // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc) {
+ CovAdd(reinterpret_cast<uptr>(pc));
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
+} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cc b/libsanitizer/sanitizer_common/sanitizer_flags.cc
index 06ac5435b9d..90bb57dff98 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.cc
@@ -16,20 +16,40 @@
namespace __sanitizer {
-CommonFlags common_flags_dont_use_directly;
+void SetCommonFlagsDefaults(CommonFlags *f) {
+ f->symbolize = true;
+ f->external_symbolizer_path = 0;
+ f->strip_path_prefix = "";
+ f->fast_unwind_on_fatal = false;
+ f->fast_unwind_on_malloc = true;
+ f->handle_ioctl = false;
+ f->malloc_context_size = 1;
+ f->log_path = "stderr";
+ f->verbosity = 0;
+ f->detect_leaks = false;
+ f->leak_check_at_exit = true;
+ f->allocator_may_return_null = false;
+ f->print_summary = true;
+}
-void ParseCommonFlagsFromString(const char *str) {
- CommonFlags *f = common_flags();
- ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str) {
+ ParseFlag(str, &f->symbolize, "symbolize");
+ ParseFlag(str, &f->external_symbolizer_path, "external_symbolizer_path");
ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
ParseFlag(str, &f->fast_unwind_on_fatal, "fast_unwind_on_fatal");
ParseFlag(str, &f->fast_unwind_on_malloc, "fast_unwind_on_malloc");
- ParseFlag(str, &f->symbolize, "symbolize");
ParseFlag(str, &f->handle_ioctl, "handle_ioctl");
+ ParseFlag(str, &f->malloc_context_size, "malloc_context_size");
ParseFlag(str, &f->log_path, "log_path");
+ ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->detect_leaks, "detect_leaks");
ParseFlag(str, &f->leak_check_at_exit, "leak_check_at_exit");
ParseFlag(str, &f->allocator_may_return_null, "allocator_may_return_null");
+ ParseFlag(str, &f->print_summary, "print_summary");
+
+ // Do a sanity check for certain flags.
+ if (f->malloc_context_size < 1)
+ f->malloc_context_size = 1;
}
static bool GetFlagValue(const char *env, const char *name,
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.h b/libsanitizer/sanitizer_common/sanitizer_flags.h
index 62aa96bbb69..46ec0928193 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.h
@@ -23,7 +23,8 @@ void ParseFlag(const char *env, const char **flag, const char *name);
struct CommonFlags {
// If set, use the online symbolizer from common sanitizer runtime.
bool symbolize;
- // Path to external symbolizer.
+ // Path to external symbolizer. If it is NULL, symbolizer will be looked for
+ // in PATH. If it is empty, external symbolizer will not be started.
const char *external_symbolizer_path;
// Strips this prefix from file paths in error reports.
const char *strip_path_prefix;
@@ -35,8 +36,12 @@ struct CommonFlags {
bool handle_ioctl;
// Max number of stack frames kept for each allocation/deallocation.
int malloc_context_size;
- // Write logs to "log_path.pid" instead of stderr.
+ // Write logs to "log_path.pid".
+ // The special values are "stdout" and "stderr".
+ // The default is "stderr".
const char *log_path;
+ // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
+ int verbosity;
// Enable memory leak detection.
bool detect_leaks;
// Invoke leak checking in an atexit handler. Has no effect if
@@ -45,15 +50,17 @@ struct CommonFlags {
bool leak_check_at_exit;
// If false, the allocator will crash instead of returning 0 on out-of-memory.
bool allocator_may_return_null;
+ // If false, disable printing error summaries in addition to error reports.
+ bool print_summary;
};
-extern CommonFlags common_flags_dont_use_directly;
-
inline CommonFlags *common_flags() {
- return &common_flags_dont_use_directly;
+ static CommonFlags f;
+ return &f;
}
-void ParseCommonFlagsFromString(const char *str);
+void SetCommonFlagsDefaults(CommonFlags *f);
+void ParseCommonFlagsFromString(CommonFlags *f, const char *str);
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index cc9233cad5f..0dab7c2f6c7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -32,6 +32,12 @@
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
+#if __LP64__ || defined(_WIN64)
+# define SANITIZER_WORDSIZE 64
+#else
+# define SANITIZER_WORDSIZE 32
+#endif
+
// GCC does not understand __has_feature
#if !defined(__has_feature)
# define __has_feature(x) 0
@@ -77,18 +83,20 @@ typedef u64 OFF_T;
typedef uptr OFF_T;
#endif
typedef u64 OFF64_T;
+
+#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
+typedef uptr operator_new_size_type;
+#else
+typedef u32 operator_new_size_type;
+#endif
} // namespace __sanitizer
extern "C" {
// Tell the tools to write their reports to "path.<pid>" instead of stderr.
+ // The special values are "stdout" and "stderr".
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.
- 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.
@@ -100,6 +108,14 @@ extern "C" {
// the error message. This function can be overridden by the client.
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
void __sanitizer_report_error_summary(const char *error_summary);
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(void *pc);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
} // extern "C"
@@ -169,12 +185,6 @@ typedef void* thread_return_t;
#endif // _WIN32
typedef thread_return_t (THREAD_CALLING_CONV *thread_callback_t)(void* arg);
-#if __LP64__ || defined(_WIN64)
-# define SANITIZER_WORDSIZE 64
-#else
-# define SANITIZER_WORDSIZE 32
-#endif
-
// NOTE: Functions below must be defined in each run-time.
namespace __sanitizer {
void NORETURN Die();
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.cc b/libsanitizer/sanitizer_common/sanitizer_libc.cc
index 2a75e431b31..53c87555092 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.cc
@@ -14,6 +14,16 @@
namespace __sanitizer {
+// Make the compiler think that something is going on there.
+static inline void break_optimization(void *arg) {
+#if SANITIZER_WINDOWS
+ // FIXME: make sure this is actually enough.
+ __asm;
+#else
+ __asm__ __volatile__("" : : "r" (arg) : "memory");
+#endif
+}
+
s64 internal_atoll(const char *nptr) {
return internal_simple_strtoll(nptr, (char**)0, 10);
}
@@ -60,6 +70,16 @@ void *internal_memmove(void *dest, const void *src, uptr n) {
return dest;
}
+// Semi-fast bzero for 16-aligned data. Still far from peak performance.
+void internal_bzero_aligned16(void *s, uptr n) {
+ struct S16 { u64 a, b; } ALIGNED(16);
+ CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0);
+ for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) {
+ p->a = p->b = 0;
+ break_optimization(0); // Make sure this does not become memset.
+ }
+}
+
void *internal_memset(void* s, int c, uptr n) {
// The next line prevents Clang from making a call to memset() instead of the
// loop below.
diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h
index f90ffcc679a..ae23bc45e9d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libc.h
@@ -27,6 +27,8 @@ void *internal_memchr(const void *s, int c, uptr n);
int internal_memcmp(const void* s1, const void* s2, uptr n);
void *internal_memcpy(void *dest, const void *src, uptr n);
void *internal_memmove(void *dest, const void *src, uptr n);
+// Set [s, s + n) to 0. Both s and n should be 16-aligned.
+void internal_bzero_aligned16(void *s, uptr n);
// Should not be used in performance-critical places.
void *internal_memset(void *s, int c, uptr n);
char* internal_strchr(const char *s, int c);
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cc b/libsanitizer/sanitizer_common/sanitizer_libignore.cc
new file mode 100644
index 00000000000..310e811df1d
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cc
@@ -0,0 +1,103 @@
+//===-- sanitizer_libignore.cc --------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_LINUX
+
+#include "sanitizer_libignore.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+LibIgnore::LibIgnore(LinkerInitialized) {
+}
+
+void LibIgnore::Init(const SuppressionContext &supp) {
+ BlockingMutexLock lock(&mutex_);
+ CHECK_EQ(count_, 0);
+ const uptr n = supp.SuppressionCount();
+ for (uptr i = 0; i < n; i++) {
+ const Suppression *s = supp.SuppressionAt(i);
+ if (s->type != SuppressionLib)
+ continue;
+ if (count_ >= kMaxLibs) {
+ Report("%s: too many called_from_lib suppressions (max: %d)\n",
+ SanitizerToolName, kMaxLibs);
+ Die();
+ }
+ Lib *lib = &libs_[count_++];
+ lib->templ = internal_strdup(s->templ);
+ lib->name = 0;
+ lib->loaded = false;
+ }
+}
+
+void LibIgnore::OnLibraryLoaded(const char *name) {
+ BlockingMutexLock lock(&mutex_);
+ // Try to match suppressions with symlink target.
+ InternalScopedBuffer<char> buf(4096);
+ if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
+ buf.data()[0]) {
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ if (!lib->loaded && lib->real_name == 0 &&
+ TemplateMatch(lib->templ, name))
+ lib->real_name = internal_strdup(buf.data());
+ }
+ }
+
+ // Scan suppressions list and find newly loaded and unloaded libraries.
+ MemoryMappingLayout proc_maps(/*cache_enabled*/false);
+ InternalScopedBuffer<char> module(4096);
+ for (uptr i = 0; i < count_; i++) {
+ Lib *lib = &libs_[i];
+ bool loaded = false;
+ proc_maps.Reset();
+ uptr b, e, off, prot;
+ while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) {
+ if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
+ continue;
+ if (TemplateMatch(lib->templ, module.data()) ||
+ (lib->real_name != 0 &&
+ internal_strcmp(lib->real_name, module.data()) == 0)) {
+ if (loaded) {
+ Report("%s: called_from_lib suppression '%s' is matched against"
+ " 2 libraries: '%s' and '%s'\n",
+ SanitizerToolName, lib->templ, lib->name, module.data());
+ Die();
+ }
+ loaded = true;
+ if (lib->loaded)
+ continue;
+ if (common_flags()->verbosity)
+ Report("Matched called_from_lib suppression '%s' against library"
+ " '%s'\n", lib->templ, module.data());
+ lib->loaded = true;
+ lib->name = internal_strdup(module.data());
+ const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
+ code_ranges_[idx].begin = b;
+ code_ranges_[idx].end = e;
+ atomic_store(&loaded_count_, idx + 1, memory_order_release);
+ }
+ }
+ if (lib->loaded && !loaded) {
+ Report("%s: library '%s' that was matched against called_from_lib"
+ " suppression '%s' is unloaded\n",
+ SanitizerToolName, lib->name, lib->templ);
+ Die();
+ }
+ }
+}
+
+void LibIgnore::OnLibraryUnloaded() {
+ OnLibraryLoaded(0);
+}
+
+} // namespace __sanitizer
+
+#endif // #if SANITIZER_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.h b/libsanitizer/sanitizer_common/sanitizer_libignore.h
new file mode 100644
index 00000000000..2089c4bbeeb
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.h
@@ -0,0 +1,82 @@
+//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// LibIgnore allows to ignore all interceptors called from a particular set
+// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
+// from the provided SuppressionContext; finds code ranges for the libraries;
+// and checks whether the provided PC value belongs to the code ranges.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_LIBIGNORE_H
+#define SANITIZER_LIBIGNORE_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_suppressions.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+class LibIgnore {
+ public:
+ explicit LibIgnore(LinkerInitialized);
+
+ // Fetches all "called_from_lib" suppressions from the SuppressionContext.
+ void Init(const SuppressionContext &supp);
+
+ // Must be called after a new dynamic library is loaded.
+ void OnLibraryLoaded(const char *name);
+
+ // Must be called after a dynamic library is unloaded.
+ void OnLibraryUnloaded();
+
+ // Checks whether the provided PC belongs to one of the ignored libraries.
+ bool IsIgnored(uptr pc) const;
+
+ private:
+ struct Lib {
+ char *templ;
+ char *name;
+ char *real_name; // target of symlink
+ bool loaded;
+ };
+
+ struct LibCodeRange {
+ uptr begin;
+ uptr end;
+ };
+
+ static const uptr kMaxLibs = 128;
+
+ // Hot part:
+ atomic_uintptr_t loaded_count_;
+ LibCodeRange code_ranges_[kMaxLibs];
+
+ // Cold part:
+ BlockingMutex mutex_;
+ uptr count_;
+ Lib libs_[kMaxLibs];
+
+ // Disallow copying of LibIgnore objects.
+ LibIgnore(const LibIgnore&); // not implemented
+ void operator = (const LibIgnore&); // not implemented
+};
+
+inline bool LibIgnore::IsIgnored(uptr pc) const {
+ const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+ return true;
+ }
+ return false;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_LIBIGNORE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc
index ddc65465ef7..69c9c1063f0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc
@@ -77,7 +77,8 @@ namespace __sanitizer {
uptr internal_mmap(void *addr, uptr length, int prot, int flags,
int fd, u64 offset) {
#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
- return internal_syscall(__NR_mmap, (uptr)addr, length, prot, flags, fd, offset);
+ return internal_syscall(__NR_mmap, (uptr)addr, length, prot, flags, fd,
+ offset);
#else
return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
#endif
@@ -216,7 +217,8 @@ uptr GetTid() {
}
u64 NanoTime() {
- kernel_timeval tv = {};
+ kernel_timeval tv;
+ internal_memset(&tv, 0, sizeof(tv));
internal_syscall(__NR_gettimeofday, (uptr)&tv, 0);
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
@@ -309,7 +311,8 @@ void PrepareForSandboxing() {
MemoryMappingLayout::CacheMemoryMappings();
// Same for /proc/self/exe in the symbolizer.
#if !SANITIZER_GO
- getSymbolizer()->PrepareForSandboxing();
+ if (Symbolizer *sym = Symbolizer::GetOrNull())
+ sym->PrepareForSandboxing();
#endif
}
@@ -572,7 +575,8 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data) {
}
uptr internal_waitpid(int pid, int *status, int options) {
- return internal_syscall(__NR_wait4, pid, (uptr)status, options, 0 /* rusage */);
+ return internal_syscall(__NR_wait4, pid, (uptr)status, options,
+ 0 /* rusage */);
}
uptr internal_getpid() {
@@ -600,6 +604,31 @@ uptr internal_sigaltstack(const struct sigaltstack *ss,
return internal_syscall(__NR_sigaltstack, (uptr)ss, (uptr)oss);
}
+uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact) {
+ return internal_syscall(__NR_rt_sigaction, signum, act, oldact,
+ sizeof(__sanitizer_kernel_sigset_t));
+}
+
+uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
+ __sanitizer_kernel_sigset_t *oldset) {
+ return internal_syscall(__NR_rt_sigprocmask, (uptr)how, &set->sig[0],
+ &oldset->sig[0], sizeof(__sanitizer_kernel_sigset_t));
+}
+
+void internal_sigfillset(__sanitizer_kernel_sigset_t *set) {
+ internal_memset(set, 0xff, sizeof(*set));
+}
+
+void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum) {
+ signum -= 1;
+ CHECK_GE(signum, 0);
+ CHECK_LT(signum, sizeof(*set) * 8);
+ const uptr idx = signum / (sizeof(set->sig[0]) * 8);
+ const uptr bit = signum % (sizeof(set->sig[0]) * 8);
+ set->sig[idx] &= ~(1 << bit);
+}
+
// ThreadLister implementation.
ThreadLister::ThreadLister(int pid)
: pid_(pid),
@@ -775,8 +804,8 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
((unsigned long long *)child_stack)[0] = (uptr)fn;
((unsigned long long *)child_stack)[1] = (uptr)arg;
- register void *r8 __asm__ ("r8") = newtls;
- register int *r10 __asm__ ("r10") = child_tidptr;
+ register void *r8 __asm__("r8") = newtls;
+ register int *r10 __asm__("r10") = child_tidptr;
__asm__ __volatile__(
/* %rax = syscall(%rax = __NR_clone,
* %rdi = flags,
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index 5bbf47904d8..6422df142e7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -15,6 +15,7 @@
#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
struct link_map; // Opaque type returned by dlopen().
struct sigaltstack;
@@ -29,6 +30,13 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
uptr internal_sigaltstack(const struct sigaltstack* ss,
struct sigaltstack* oss);
+uptr internal_sigaction(int signum, const __sanitizer_kernel_sigaction_t *act,
+ __sanitizer_kernel_sigaction_t *oldact);
+uptr internal_sigprocmask(int how, __sanitizer_kernel_sigset_t *set,
+ __sanitizer_kernel_sigset_t *oldset);
+void internal_sigfillset(__sanitizer_kernel_sigset_t *set);
+void internal_sigdelset(__sanitizer_kernel_sigset_t *set, int signum);
+
#ifdef __x86_64__
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
@@ -56,7 +64,7 @@ class ThreadLister {
int bytes_read_;
};
-void AdjustStackSizeLinux(void *attr, int verbosity);
+void AdjustStackSizeLinux(void *attr);
// Exposed for testing.
uptr ThreadDescriptorSize();
@@ -74,7 +82,6 @@ void CacheBinaryName();
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
-
} // namespace __sanitizer
#endif // SANITIZER_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
index 7d6c63918de..5b70a69abec 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -14,6 +14,7 @@
#if SANITIZER_LINUX
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_linux.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
@@ -30,6 +31,12 @@
#include <link.h>
#endif
+// This function is defined elsewhere if we intercepted pthread_attr_getstack.
+SANITIZER_WEAK_ATTRIBUTE
+int __sanitizer_pthread_attr_getstack(void *attr, void **addr, size_t *size) {
+ return pthread_attr_getstack((pthread_attr_t*)attr, addr, size);
+}
+
namespace __sanitizer {
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -71,7 +78,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
uptr stacksize = 0;
void *stackaddr = 0;
- pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
+ __sanitizer_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
pthread_attr_destroy(&attr);
CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
@@ -137,35 +144,33 @@ uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
#endif
}
+struct UnwindTraceArg {
+ StackTrace *stack;
+ uptr max_depth;
+};
+
_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
- StackTrace *b = (StackTrace*)param;
- CHECK(b->size < b->max_size);
+ UnwindTraceArg *arg = (UnwindTraceArg*)param;
+ CHECK_LT(arg->stack->size, arg->max_depth);
uptr pc = Unwind_GetIP(ctx);
- b->trace[b->size++] = pc;
- if (b->size == b->max_size) return UNWIND_STOP;
+ arg->stack->trace[arg->stack->size++] = pc;
+ if (arg->stack->size == arg->max_depth) return UNWIND_STOP;
return UNWIND_CONTINUE;
}
-static bool MatchPc(uptr cur_pc, uptr trace_pc) {
- return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
-}
-
void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
- this->size = 0;
- this->max_size = max_depth;
- if (max_depth > 1) {
- _Unwind_Backtrace(Unwind_Trace, this);
- // We need to pop a few frames so that pc is on top.
- // trace[0] belongs to the current function so we always pop it.
- int to_pop = 1;
- /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
- else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
- else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
- else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
- else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
- this->PopStackFrames(to_pop);
- }
- this->trace[0] = pc;
+ size = 0;
+ if (max_depth == 0)
+ return;
+ UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+ _Unwind_Backtrace(Unwind_Trace, &arg);
+ // We need to pop a few frames so that pc is on top.
+ uptr to_pop = LocatePcInTrace(pc);
+ // trace[0] belongs to the current function so we always pop it.
+ if (to_pop == 0)
+ to_pop = 1;
+ PopStackFrames(to_pop);
+ trace[0] = pc;
}
#endif // !SANITIZER_GO
@@ -265,11 +270,11 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif // SANITIZER_GO
}
-void AdjustStackSizeLinux(void *attr_, int verbosity) {
+void AdjustStackSizeLinux(void *attr_) {
pthread_attr_t *attr = (pthread_attr_t *)attr_;
uptr stackaddr = 0;
size_t stacksize = 0;
- pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
+ __sanitizer_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize);
// GLibC will return (0 - stacksize) as the stack address in the case when
// stacksize is set, but stackaddr is not.
bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);
@@ -277,7 +282,7 @@ void AdjustStackSizeLinux(void *attr_, int verbosity) {
const uptr minstacksize = GetTlsSize() + 128*1024;
if (stacksize < minstacksize) {
if (!stack_set) {
- if (verbosity && stacksize != 0)
+ if (common_flags()->verbosity && stacksize != 0)
Printf("Sanitizer: increasing stacksize %zu->%zu\n", stacksize,
minstacksize);
pthread_attr_setstacksize(attr, minstacksize);
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc
index fa146b5b4e8..288e31ca078 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc
@@ -143,7 +143,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
const char *GetEnv(const char *name) {
char ***env_ptr = _NSGetEnviron();
- CHECK(env_ptr);
+ if (!env_ptr) {
+ Report("_NSGetEnviron() returned NULL. Please make sure __asan_init() is "
+ "called after libSystem_initializer().\n");
+ CHECK(env_ptr);
+ }
char **environ = *env_ptr;
CHECK(environ);
uptr name_len = internal_strlen(name);
diff --git a/libsanitizer/sanitizer_common/sanitizer_mutex.h b/libsanitizer/sanitizer_common/sanitizer_mutex.h
index b3501146279..d78f43edaae 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mutex.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mutex.h
@@ -38,6 +38,10 @@ class StaticSpinMutex {
atomic_store(&state_, 0, memory_order_release);
}
+ void CheckLocked() {
+ CHECK_EQ(atomic_load(&state_, memory_order_relaxed), 1);
+ }
+
private:
atomic_uint8_t state_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_placement_new.h b/libsanitizer/sanitizer_common/sanitizer_placement_new.h
index 310327fd8f0..7231e96878d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_placement_new.h
+++ b/libsanitizer/sanitizer_common/sanitizer_placement_new.h
@@ -16,15 +16,7 @@
#include "sanitizer_internal_defs.h"
-namespace __sanitizer {
-#if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC
-typedef uptr operator_new_ptr_type;
-#else
-typedef u32 operator_new_ptr_type;
-#endif
-} // namespace __sanitizer
-
-inline void *operator new(__sanitizer::operator_new_ptr_type sz, void *p) {
+inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) {
return p;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index 2270709449b..7693fe7ff17 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -23,8 +23,15 @@
#if defined(__APPLE__)
# define SANITIZER_MAC 1
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# define SANITIZER_IOS 1
+# else
+# define SANITIZER_IOS 0
+# endif
#else
# define SANITIZER_MAC 0
+# define SANITIZER_IOS 0
#endif
#if defined(_WIN32)
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index e0199482f10..b6dcbe9e808 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -39,6 +39,12 @@
# define SI_MAC 0
#endif
+#if SANITIZER_IOS
+# define SI_IOS 1
+#else
+# define SI_IOS 0
+#endif
+
# define SANITIZER_INTERCEPT_STRCMP 1
# define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
@@ -61,6 +67,7 @@
# define SANITIZER_INTERCEPT_PRCTL SI_LINUX
# define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX
@@ -111,6 +118,7 @@
# define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
# define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
# define SANITIZER_INTERCEPT_SCANDIR SI_LINUX_NOT_ANDROID
# define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
# define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
@@ -124,5 +132,41 @@
# define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
+# define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_STATFS64 \
+ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_SHMCTL \
+ (SI_LINUX_NOT_ANDROID && SANITIZER_WORDSIZE == 64)
+# define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
+ SI_MAC || SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_SINCOS SI_LINUX
+# define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX
+# define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID
+# define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS
+
+// FIXME: getline seems to be available on OSX 10.7
+# define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID
+
+# define SANITIZER_INTERCEPT__EXIT SI_LINUX
+
+# define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_PTHREAD_COND SI_NOT_WINDOWS
+# define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
index a69b11f89fe..01de9c936c7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc
@@ -14,34 +14,88 @@
// userspace headers.
// Most "normal" includes go in sanitizer_platform_limits_posix.cc
-#ifdef SYSCALL_INTERCEPTION
#include "sanitizer_platform.h"
#if SANITIZER_LINUX
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_posix.h"
+
+// For offsetof -> __builtin_offsetof definition.
+#include <stddef.h>
+
+// With old kernels (and even new kernels on powerpc) asm/stat.h uses types that
+// are not defined anywhere in userspace headers. Fake them. This seems to work
+// fine with newer headers, too.
+#include <asm/posix_types.h>
+#define ino_t __kernel_ino_t
+#define mode_t __kernel_mode_t
+#define nlink_t __kernel_nlink_t
+#define uid_t __kernel_uid_t
+#define gid_t __kernel_gid_t
+#define off_t __kernel_off_t
// This header seems to contain the definitions of _kernel_ stat* structs.
#include <asm/stat.h>
+#undef ino_t
+#undef mode_t
+#undef nlink_t
+#undef uid_t
+#undef gid_t
+#undef off_t
+
#include <linux/aio_abi.h>
+#if SANITIZER_ANDROID
+#include <asm/statfs.h>
+#else
+#include <sys/statfs.h>
+#endif
+
#if !SANITIZER_ANDROID
#include <linux/perf_event.h>
#endif
namespace __sanitizer {
- unsigned struct___old_kernel_stat_sz = sizeof(struct __old_kernel_stat);
- unsigned struct_kernel_stat_sz = sizeof(struct stat);
- unsigned struct_io_event_sz = sizeof(struct io_event);
- unsigned struct_iocb_sz = sizeof(struct iocb);
+ unsigned struct_statfs64_sz = sizeof(struct statfs64);
+} // namespace __sanitizer
-#if !defined(_LP64) && !defined(__x86_64__)
- unsigned struct_kernel_stat64_sz = sizeof(struct stat64);
-#else
- unsigned struct_kernel_stat64_sz = 0;
+#if !defined(__powerpc64__)
+COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat));
+#endif
+
+COMPILER_CHECK(struct_kernel_stat_sz == sizeof(struct stat));
+
+#if defined(__i386__)
+COMPILER_CHECK(struct_kernel_stat64_sz == sizeof(struct stat64));
#endif
+CHECK_TYPE_SIZE(io_event);
+CHECK_SIZE_AND_OFFSET(io_event, data);
+CHECK_SIZE_AND_OFFSET(io_event, obj);
+CHECK_SIZE_AND_OFFSET(io_event, res);
+CHECK_SIZE_AND_OFFSET(io_event, res2);
+
#if !SANITIZER_ANDROID
- unsigned struct_perf_event_attr_sz = sizeof(struct perf_event_attr);
+COMPILER_CHECK(sizeof(struct __sanitizer_perf_event_attr) <=
+ sizeof(struct perf_event_attr));
+CHECK_SIZE_AND_OFFSET(perf_event_attr, type);
+CHECK_SIZE_AND_OFFSET(perf_event_attr, size);
#endif
-} // namespace __sanitizer
-#endif // SANITIZER_LINUX
+COMPILER_CHECK(iocb_cmd_pread == IOCB_CMD_PREAD);
+COMPILER_CHECK(iocb_cmd_pwrite == IOCB_CMD_PWRITE);
+#if !SANITIZER_ANDROID
+COMPILER_CHECK(iocb_cmd_preadv == IOCB_CMD_PREADV);
+COMPILER_CHECK(iocb_cmd_pwritev == IOCB_CMD_PWRITEV);
#endif
+
+CHECK_TYPE_SIZE(iocb);
+CHECK_SIZE_AND_OFFSET(iocb, aio_data);
+// Skip aio_key, it's weird.
+CHECK_SIZE_AND_OFFSET(iocb, aio_lio_opcode);
+CHECK_SIZE_AND_OFFSET(iocb, aio_reqprio);
+CHECK_SIZE_AND_OFFSET(iocb, aio_fildes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_buf);
+CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes);
+CHECK_SIZE_AND_OFFSET(iocb, aio_offset);
+
+#endif // SANITIZER_LINUX
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
index 950ab58cca5..058f40acf23 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -19,6 +19,7 @@
#include <arpa/inet.h>
#include <dirent.h>
+#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <net/if.h>
@@ -42,6 +43,8 @@
#include <wchar.h>
#if SANITIZER_LINUX
+#include <mntent.h>
+#include <netinet/ether.h>
#include <utime.h>
#include <sys/mount.h>
#include <sys/ptrace.h>
@@ -75,6 +78,7 @@
#include <sys/mtio.h>
#include <sys/kd.h>
#include <sys/shm.h>
+#include <sys/statvfs.h>
#include <sys/timex.h>
#include <sys/user.h>
#include <sys/ustat.h>
@@ -87,6 +91,8 @@
#include <linux/scc.h>
#include <linux/serial.h>
#include <sys/msg.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
#if SANITIZER_ANDROID
@@ -100,20 +106,22 @@
#include <link.h>
#include <sys/vfs.h>
#include <sys/epoll.h>
-// #include <asm/stat.h>
#include <linux/capability.h>
#endif // SANITIZER_LINUX
#if SANITIZER_MAC
-#include <netinet/ip_mroute.h>
+#include <net/ethernet.h>
#include <sys/filio.h>
+#include <sys/mount.h>
#include <sys/sockio.h>
#endif
namespace __sanitizer {
unsigned struct_utsname_sz = sizeof(struct utsname);
unsigned struct_stat_sz = sizeof(struct stat);
+#if !SANITIZER_IOS
unsigned struct_stat64_sz = sizeof(struct stat64);
+#endif // !SANITIZER_IOS
unsigned struct_rusage_sz = sizeof(struct rusage);
unsigned struct_tm_sz = sizeof(struct tm);
unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -122,6 +130,7 @@ namespace __sanitizer {
unsigned struct_sigaction_sz = sizeof(struct sigaction);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
+ unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
unsigned pid_t_sz = sizeof(pid_t);
unsigned timeval_sz = sizeof(timeval);
unsigned uid_t_sz = sizeof(uid_t);
@@ -131,6 +140,11 @@ namespace __sanitizer {
unsigned struct_tms_sz = sizeof(struct tms);
unsigned struct_sigevent_sz = sizeof(struct sigevent);
unsigned struct_sched_param_sz = sizeof(struct sched_param);
+ unsigned struct_statfs_sz = sizeof(struct statfs);
+
+#if SANITIZER_MAC && !SANITIZER_IOS
+ unsigned struct_statfs64_sz = sizeof(struct statfs64);
+#endif // SANITIZER_MAC && !SANITIZER_IOS
#if !SANITIZER_ANDROID
unsigned ucontext_t_sz = sizeof(ucontext_t);
@@ -138,7 +152,6 @@ namespace __sanitizer {
#if SANITIZER_LINUX
unsigned struct_rlimit_sz = sizeof(struct rlimit);
- unsigned struct_statfs_sz = sizeof(struct statfs);
unsigned struct_epoll_event_sz = sizeof(struct epoll_event);
unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
unsigned struct_timespec_sz = sizeof(struct timespec);
@@ -155,11 +168,11 @@ namespace __sanitizer {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
- unsigned struct_statfs64_sz = sizeof(struct statfs64);
unsigned struct_timex_sz = sizeof(struct timex);
unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
- unsigned struct_shmid_ds_sz = sizeof(struct shmid_ds);
unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+ unsigned struct_statvfs_sz = sizeof(struct statvfs);
+ unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
uptr sig_ign = (uptr)SIG_IGN;
@@ -170,6 +183,16 @@ namespace __sanitizer {
int e_tabsz = (int)E_TABSZ;
#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ unsigned struct_shminfo_sz = sizeof(struct shminfo);
+ unsigned struct_shm_info_sz = sizeof(struct shm_info);
+ int shmctl_ipc_stat = (int)IPC_STAT;
+ int shmctl_ipc_info = (int)IPC_INFO;
+ int shmctl_shm_info = (int)SHM_INFO;
+ int shmctl_shm_stat = (int)SHM_INFO;
+#endif
+
int af_inet = (int)AF_INET;
int af_inet6 = (int)AF_INET6;
@@ -197,6 +220,9 @@ namespace __sanitizer {
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
#endif
+ int ptrace_peektext = PTRACE_PEEKTEXT;
+ int ptrace_peekdata = PTRACE_PEEKDATA;
+ int ptrace_peekuser = PTRACE_PEEKUSER;
int ptrace_getregs = PTRACE_GETREGS;
int ptrace_setregs = PTRACE_SETREGS;
int ptrace_getfpregs = PTRACE_GETFPREGS;
@@ -295,7 +321,7 @@ namespace __sanitizer {
unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
#endif
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_MAC
unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
#endif
@@ -346,7 +372,7 @@ namespace __sanitizer {
unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
unsigned IOCTL_TIOCSTI = TIOCSTI;
unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
#endif
@@ -733,24 +759,9 @@ namespace __sanitizer {
unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
#endif
-} // namespace __sanitizer
-#define CHECK_TYPE_SIZE(TYPE) \
- COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
-
-#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \
- COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
- sizeof(((CLASS *) NULL)->MEMBER)); \
- COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \
- offsetof(CLASS, MEMBER))
-
-// For sigaction, which is a function and struct at the same time,
-// and thus requires explicit "struct" in sizeof() expression.
-#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \
- COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
- sizeof(((struct CLASS *) NULL)->MEMBER)); \
- COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
- offsetof(struct CLASS, MEMBER))
+ extern const int errno_EOWNERDEAD = EOWNERDEAD;
+} // namespace __sanitizer
COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
@@ -855,7 +866,6 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
#endif
-#ifdef SYSCALL_INTERCEPTION
#if SANITIZER_LINUX
CHECK_TYPE_SIZE(__sysctl_args);
CHECK_SIZE_AND_OFFSET(__sysctl_args, name);
@@ -873,7 +883,6 @@ CHECK_TYPE_SIZE(__kernel_off_t);
CHECK_TYPE_SIZE(__kernel_loff_t);
CHECK_TYPE_SIZE(__kernel_fd_set);
#endif
-#endif
#if !SANITIZER_ANDROID
CHECK_TYPE_SIZE(wordexp_t);
@@ -882,4 +891,52 @@ CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
#endif
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
+#if SANITIZER_LINUX
+CHECK_TYPE_SIZE(mntent);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_fsname);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_dir);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_type);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_opts);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_freq);
+CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
+#endif
+
+CHECK_TYPE_SIZE(ether_addr);
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+CHECK_TYPE_SIZE(ipc_perm);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
+CHECK_SIZE_AND_OFFSET(ipc_perm, __seq);
+
+CHECK_TYPE_SIZE(shmid_ds);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
+#endif
+
+CHECK_TYPE_SIZE(clock_t);
+
#endif // SANITIZER_LINUX || SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index 67c459caabb..3bb8dc1114a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -13,19 +13,22 @@
#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
#define SANITIZER_PLATFORM_LIMITS_POSIX_H
+#include "sanitizer_internal_defs.h"
#include "sanitizer_platform.h"
namespace __sanitizer {
extern unsigned struct_utsname_sz;
extern unsigned struct_stat_sz;
+#if !SANITIZER_IOS
extern unsigned struct_stat64_sz;
+#endif
extern unsigned struct_rusage_sz;
- extern unsigned struct_tm_sz;
extern unsigned struct_passwd_sz;
extern unsigned struct_group_sz;
extern unsigned siginfo_t_sz;
extern unsigned struct_itimerval_sz;
extern unsigned pthread_t_sz;
+ extern unsigned pthread_cond_t_sz;
extern unsigned pid_t_sz;
extern unsigned timeval_sz;
extern unsigned uid_t_sz;
@@ -35,30 +38,52 @@ namespace __sanitizer {
extern unsigned struct_itimerspec_sz;
extern unsigned struct_sigevent_sz;
extern unsigned struct_sched_param_sz;
+ extern unsigned struct_statfs_sz;
+ extern unsigned struct_statfs64_sz;
#if !SANITIZER_ANDROID
extern unsigned ucontext_t_sz;
#endif // !SANITIZER_ANDROID
#if SANITIZER_LINUX
- extern unsigned struct___old_kernel_stat_sz;
- extern unsigned struct_kernel_stat_sz;
- extern unsigned struct_kernel_stat64_sz;
- extern unsigned struct_io_event_sz;
- extern unsigned struct_iocb_sz;
+
+#if defined(__x86_64__)
+ const unsigned struct___old_kernel_stat_sz = 32;
+ const unsigned struct_kernel_stat_sz = 144;
+ const unsigned struct_kernel_stat64_sz = 0;
+#elif defined(__i386__)
+ const unsigned struct___old_kernel_stat_sz = 32;
+ const unsigned struct_kernel_stat_sz = 64;
+ const unsigned struct_kernel_stat64_sz = 96;
+#elif defined(__arm__)
+ const unsigned struct___old_kernel_stat_sz = 32;
+ const unsigned struct_kernel_stat_sz = 64;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+ const unsigned struct___old_kernel_stat_sz = 32;
+ const unsigned struct_kernel_stat_sz = 72;
+ const unsigned struct_kernel_stat64_sz = 104;
+#elif defined(__powerpc64__)
+ const unsigned struct___old_kernel_stat_sz = 0;
+ const unsigned struct_kernel_stat_sz = 144;
+ const unsigned struct_kernel_stat64_sz = 104;
+#endif
+ struct __sanitizer_perf_event_attr {
+ unsigned type;
+ unsigned size;
+ // More fields that vary with the kernel version.
+ };
+
extern unsigned struct_utimbuf_sz;
extern unsigned struct_new_utsname_sz;
extern unsigned struct_old_utsname_sz;
extern unsigned struct_oldold_utsname_sz;
extern unsigned struct_msqid_ds_sz;
- extern unsigned struct_shmid_ds_sz;
extern unsigned struct_mq_attr_sz;
- extern unsigned struct_perf_event_attr_sz;
extern unsigned struct_timex_sz;
extern unsigned struct_ustat_sz;
extern unsigned struct_rlimit_sz;
- extern unsigned struct_statfs_sz;
extern unsigned struct_epoll_event_sz;
extern unsigned struct_sysinfo_sz;
extern unsigned struct_timespec_sz;
@@ -67,6 +92,32 @@ namespace __sanitizer {
const unsigned old_sigset_t_sz = sizeof(unsigned long);
const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
+ struct __sanitizer_iocb {
+ u64 aio_data;
+ u32 aio_key_or_aio_reserved1; // Simply crazy.
+ u32 aio_reserved1_or_aio_key; // Luckily, we don't need these.
+ u16 aio_lio_opcode;
+ s16 aio_reqprio;
+ u32 aio_fildes;
+ u64 aio_buf;
+ u64 aio_nbytes;
+ s64 aio_offset;
+ u64 aio_reserved2;
+ u64 aio_reserved3;
+ };
+
+ struct __sanitizer_io_event {
+ u64 data;
+ u64 obj;
+ u64 res;
+ u64 res2;
+ };
+
+ const unsigned iocb_cmd_pread = 0;
+ const unsigned iocb_cmd_pwrite = 1;
+ const unsigned iocb_cmd_preadv = 7;
+ const unsigned iocb_cmd_pwritev = 8;
+
struct __sanitizer___sysctl_args {
int *name;
int nlen;
@@ -80,8 +131,55 @@ namespace __sanitizer {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
extern unsigned struct_rlimit64_sz;
- extern unsigned struct_statfs64_sz;
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned struct_statvfs_sz;
+ extern unsigned struct_statvfs64_sz;
+
+ struct __sanitizer_ipc_perm {
+ int __key;
+ int uid;
+ int gid;
+ int cuid;
+ int cgid;
+#ifdef __powerpc64__
+ unsigned mode;
+ unsigned __seq;
+#else
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short __seq;
+ unsigned short __pad2;
+#endif
+ uptr __unused1;
+ uptr __unused2;
+ };
+
+ struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ #ifndef __powerpc__
+ uptr shm_segsz;
+ #endif
+ uptr shm_atime;
+ #ifndef _LP64
+ uptr __unused1;
+ #endif
+ uptr shm_dtime;
+ #ifndef _LP64
+ uptr __unused2;
+ #endif
+ uptr shm_ctime;
+ #ifndef _LP64
+ uptr __unused3;
+ #endif
+ #ifdef __powerpc__
+ uptr shm_segsz;
+ #endif
+ int shm_cpid;
+ int shm_lpid;
+ uptr shm_nattch;
+ uptr __unused4;
+ uptr __unused5;
+ };
+ #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
struct __sanitizer_iovec {
void *iov_base;
@@ -94,6 +192,35 @@ namespace __sanitizer {
typedef unsigned __sanitizer_pthread_key_t;
#endif
+ struct __sanitizer_ether_addr {
+ u8 octet[6];
+ };
+
+ struct __sanitizer_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+ long int tm_gmtoff;
+ const char *tm_zone;
+ };
+
+#if SANITIZER_LINUX
+ struct __sanitizer_mntent {
+ char *mnt_fsname;
+ char *mnt_dir;
+ char *mnt_type;
+ char *mnt_opts;
+ int mnt_freq;
+ int mnt_passno;
+ };
+#endif
+
#if SANITIZER_ANDROID || SANITIZER_MAC
struct __sanitizer_msghdr {
void *msg_name;
@@ -158,6 +285,8 @@ namespace __sanitizer {
};
#endif
+ typedef long __sanitizer_clock_t;
+
#if SANITIZER_LINUX
#if defined(_LP64) || defined(__x86_64__)
typedef unsigned __sanitizer___kernel_uid_t;
@@ -168,8 +297,15 @@ namespace __sanitizer {
typedef unsigned short __sanitizer___kernel_gid_t;
typedef long __sanitizer___kernel_off_t;
#endif
+
+#if defined(__powerpc64__)
+ typedef unsigned int __sanitizer___kernel_old_uid_t;
+ typedef unsigned int __sanitizer___kernel_old_gid_t;
+#else
typedef unsigned short __sanitizer___kernel_old_uid_t;
typedef unsigned short __sanitizer___kernel_old_gid_t;
+#endif
+
typedef long long __sanitizer___kernel_loff_t;
typedef struct {
unsigned long fds_bits[1024 / (8 * sizeof(long))];
@@ -207,6 +343,20 @@ namespace __sanitizer {
#endif
};
+ struct __sanitizer_kernel_sigset_t {
+ u8 sig[8];
+ };
+
+ struct __sanitizer_kernel_sigaction_t {
+ union {
+ void (*sigaction)(int signo, void *info, void *ctx);
+ void (*handler)(int signo);
+ };
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ __sanitizer_kernel_sigset_t sa_mask;
+ };
+
extern uptr sig_ign;
extern uptr sig_dfl;
extern uptr sa_siginfo;
@@ -297,6 +447,9 @@ namespace __sanitizer {
extern unsigned struct_user_fpregs_struct_sz;
extern unsigned struct_user_fpxregs_struct_sz;
+ extern int ptrace_peektext;
+ extern int ptrace_peekdata;
+ extern int ptrace_peekuser;
extern int ptrace_getregs;
extern int ptrace_setregs;
extern int ptrace_getfpregs;
@@ -309,6 +462,15 @@ namespace __sanitizer {
extern int ptrace_setregset;
#endif
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ extern unsigned struct_shminfo_sz;
+ extern unsigned struct_shm_info_sz;
+ extern int shmctl_ipc_stat;
+ extern int shmctl_ipc_info;
+ extern int shmctl_shm_info;
+ extern int shmctl_shm_stat;
+#endif
+
// ioctl arguments
struct __sanitizer_ifconf {
int ifc_len;
@@ -390,7 +552,7 @@ namespace __sanitizer {
extern unsigned struct_unimapinit_sz;
#endif
-#if !SANITIZER_ANDROID
+#if !SANITIZER_ANDROID && !SANITIZER_MAC
extern unsigned struct_sioc_sg_req_sz;
extern unsigned struct_sioc_vif_req_sz;
#endif
@@ -445,7 +607,7 @@ namespace __sanitizer {
extern unsigned IOCTL_TIOCSPGRP;
extern unsigned IOCTL_TIOCSTI;
extern unsigned IOCTL_TIOCSWINSZ;
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_MAC
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID)
extern unsigned IOCTL_SIOCGETSGCNT;
extern unsigned IOCTL_SIOCGETVIFCNT;
#endif
@@ -807,6 +969,25 @@ namespace __sanitizer {
extern unsigned IOCTL_TIOCSERSETMULTI;
extern unsigned IOCTL_TIOCSSERIAL;
#endif
+
+ extern const int errno_EOWNERDEAD;
} // namespace __sanitizer
+#define CHECK_TYPE_SIZE(TYPE) \
+ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
+
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \
+ offsetof(CLASS, MEMBER))
+
+// For sigaction, which is a function and struct at the same time,
+// and thus requires explicit "struct" in sizeof() expression.
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
+ sizeof(((struct CLASS *) NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
+ offsetof(struct CLASS, MEMBER))
+
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
index 3d4f92db581..ae782ac39cb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -87,28 +87,6 @@ int internal_isatty(fd_t fd) {
return isatty(fd);
}
-#ifndef SANITIZER_GO
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast) {
-#if !SANITIZER_CAN_FAST_UNWIND
- fast = false;
-#endif
-#if SANITIZER_MAC
- // Always unwind fast on Mac.
- (void)fast;
-#else
- if (!fast)
- return stack->SlowUnwindStack(pc, max_s);
-#endif // SANITIZER_MAC
- stack->size = 0;
- stack->trace[0] = pc;
- if (max_s > 1) {
- stack->max_size = max_s;
- stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
- }
-}
-#endif // SANITIZER_GO
-
} // namespace __sanitizer
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc
index d7ce9736b24..08951c7e247 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc
@@ -193,17 +193,22 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
PrintfAndReportCallback = callback;
}
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
// Can be overriden in frontend.
+#if SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void OnPrint(const char *str) {
+ (void)str;
+}
+#elif defined(SANITIZER_GO) && defined(TSAN_EXTERNAL_HOOKS)
void OnPrint(const char *str);
+#else
+void OnPrint(const char *str) {
+ (void)str;
+}
#endif
static void CallPrintfAndReportCallback(const char *str) {
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
- if (&OnPrint != NULL)
- OnPrint(str);
-#endif
+ OnPrint(str);
if (PrintfAndReportCallback)
PrintfAndReportCallback(str);
}
@@ -287,4 +292,13 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
return needed_length;
}
+void InternalScopedString::append(const char *format, ...) {
+ CHECK_LT(length_, size());
+ va_list args;
+ va_start(args, format);
+ VSNPrintf(data() + length_, size() - length_, format, args);
+ va_end(args);
+ length_ += internal_strlen(data() + length_);
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_quarantine.h b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
index 7f567f97d7c..1e8d056a187 100644
--- a/libsanitizer/sanitizer_common/sanitizer_quarantine.h
+++ b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
@@ -24,13 +24,15 @@ namespace __sanitizer {
template<typename Node> class QuarantineCache;
struct QuarantineBatch {
- static const uptr kSize = 1024;
+ static const uptr kSize = 1021;
QuarantineBatch *next;
uptr size;
uptr count;
void *batch[kSize];
};
+COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb.
+
// The callback interface is:
// void Callback::Recycle(Node *ptr);
// void *cb.Allocate(uptr size);
@@ -121,8 +123,10 @@ class QuarantineCache {
}
void Enqueue(Callback cb, void *ptr, uptr size) {
- if (list_.empty() || list_.back()->count == QuarantineBatch::kSize)
+ if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) {
AllocBatch(cb);
+ size += sizeof(QuarantineBatch); // Count the batch in Quarantine size.
+ }
QuarantineBatch *b = list_.back();
b->batch[b->count++] = ptr;
b->size += size;
@@ -145,9 +149,7 @@ class QuarantineCache {
return 0;
QuarantineBatch *b = list_.front();
list_.pop_front();
- // FIXME: should probably add SizeSub method?
- // See https://code.google.com/p/thread-sanitizer/issues/detail?id=20
- SizeAdd(0 - b->size);
+ SizeSub(b->size);
return b;
}
@@ -158,6 +160,9 @@ class QuarantineCache {
void SizeAdd(uptr add) {
atomic_store(&size_, Size() + add, memory_order_relaxed);
}
+ void SizeSub(uptr sub) {
+ atomic_store(&size_, Size() - sub, memory_order_relaxed);
+ }
NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
index 4e7972424dc..3a9e902537a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
@@ -10,21 +10,13 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-const char *StripPathPrefix(const char *filepath,
- const char *strip_file_prefix) {
- if (filepath == 0) return 0;
- const char *prefix_beg = internal_strstr(filepath, strip_file_prefix);
- if (prefix_beg)
- return prefix_beg + internal_strlen(strip_file_prefix);
- return filepath;
-}
-// ----------------------- StackTrace ----------------------------- {{{1
uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
#ifdef __arm__
// Cancel Thumb bit.
@@ -40,32 +32,21 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
#endif
}
-static void PrintStackFramePrefix(uptr frame_num, uptr pc) {
- Printf(" #%zu 0x%zx", frame_num, pc);
-}
-
-static void PrintSourceLocation(const char *file, int line, int column,
- const char *strip_file_prefix) {
- CHECK(file);
- Printf(" %s", StripPathPrefix(file, strip_file_prefix));
- if (line > 0) {
- Printf(":%d", line);
- if (column > 0)
- Printf(":%d", column);
- }
-}
-
-static void PrintModuleAndOffset(const char *module, uptr offset,
- const char *strip_file_prefix) {
- Printf(" (%s+0x%zx)", StripPathPrefix(module, strip_file_prefix), offset);
+static void PrintStackFramePrefix(InternalScopedString *buffer, uptr frame_num,
+ uptr pc) {
+ buffer->append(" #%zu 0x%zx", frame_num, pc);
}
void StackTrace::PrintStack(const uptr *addr, uptr size,
- bool symbolize, const char *strip_file_prefix,
- SymbolizeCallback symbolize_callback ) {
+ SymbolizeCallback symbolize_callback) {
+ if (addr == 0 || size == 0) {
+ Printf(" <empty stack>\n\n");
+ return;
+ }
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
InternalScopedBuffer<char> buff(GetPageSizeCached() * 2);
InternalScopedBuffer<AddressInfo> addr_frames(64);
+ InternalScopedString frame_desc(GetPageSizeCached() * 2);
uptr frame_num = 0;
for (uptr i = 0; i < size && addr[i]; i++) {
// PCs in stack traces are actually the return addresses, that is,
@@ -76,50 +57,60 @@ void StackTrace::PrintStack(const uptr *addr, uptr size,
if (symbolize_callback) {
if (symbolize_callback((void*)pc, buff.data(), buff.size())) {
addr_frames_num = 1;
- PrintStackFramePrefix(frame_num, pc);
+ frame_desc.clear();
+ PrintStackFramePrefix(&frame_desc, frame_num, pc);
// We can't know anything about the string returned by external
// symbolizer, but if it starts with filename, try to strip path prefix
// from it.
- Printf(" %s\n", StripPathPrefix(buff.data(), strip_file_prefix));
+ frame_desc.append(
+ " %s",
+ StripPathPrefix(buff.data(), common_flags()->strip_path_prefix));
+ Printf("%s\n", frame_desc.data());
frame_num++;
}
}
- if (symbolize && addr_frames_num == 0 && &getSymbolizer) {
+ if (common_flags()->symbolize && addr_frames_num == 0) {
// Use our own (online) symbolizer, if necessary.
- addr_frames_num = getSymbolizer()->SymbolizeCode(
- pc, addr_frames.data(), addr_frames.size());
+ if (Symbolizer *sym = Symbolizer::GetOrNull())
+ addr_frames_num =
+ sym->SymbolizeCode(pc, addr_frames.data(), addr_frames.size());
for (uptr j = 0; j < addr_frames_num; j++) {
AddressInfo &info = addr_frames[j];
- PrintStackFramePrefix(frame_num, pc);
+ frame_desc.clear();
+ PrintStackFramePrefix(&frame_desc, frame_num, pc);
if (info.function) {
- Printf(" in %s", info.function);
+ frame_desc.append(" in %s", info.function);
}
if (info.file) {
- PrintSourceLocation(info.file, info.line, info.column,
- strip_file_prefix);
+ frame_desc.append(" ");
+ PrintSourceLocation(&frame_desc, info.file, info.line, info.column);
} else if (info.module) {
- PrintModuleAndOffset(info.module, info.module_offset,
- strip_file_prefix);
+ frame_desc.append(" ");
+ PrintModuleAndOffset(&frame_desc, info.module, info.module_offset);
}
- Printf("\n");
- info.Clear();
+ Printf("%s\n", frame_desc.data());
frame_num++;
+ info.Clear();
}
}
if (addr_frames_num == 0) {
// If online symbolization failed, try to output at least module and
// offset for instruction.
- PrintStackFramePrefix(frame_num, pc);
+ frame_desc.clear();
+ PrintStackFramePrefix(&frame_desc, frame_num, pc);
uptr offset;
if (proc_maps.GetObjectNameAndOffset(pc, &offset,
buff.data(), buff.size(),
/* protection */0)) {
- PrintModuleAndOffset(buff.data(), offset, strip_file_prefix);
+ frame_desc.append(" ");
+ PrintModuleAndOffset(&frame_desc, buff.data(), offset);
}
- Printf("\n");
+ Printf("%s\n", frame_desc.data());
frame_num++;
}
}
+ // Always print a trailing empty line after stack trace.
+ Printf("\n");
}
uptr StackTrace::GetCurrentPc() {
@@ -127,8 +118,13 @@ uptr StackTrace::GetCurrentPc() {
}
void StackTrace::FastUnwindStack(uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom) {
- CHECK(size == 0 && trace[0] == pc);
+ uptr stack_top, uptr stack_bottom,
+ uptr max_depth) {
+ if (max_depth == 0) {
+ size = 0;
+ return;
+ }
+ trace[0] = pc;
size = 1;
uhwptr *frame = (uhwptr *)bp;
uhwptr *prev_frame = frame - 1;
@@ -138,7 +134,7 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp,
frame < (uhwptr *)stack_top - 2 &&
frame > (uhwptr *)stack_bottom &&
IsAligned((uptr)frame, sizeof(*frame)) &&
- size < max_size) {
+ size < max_depth) {
uhwptr pc1 = frame[1];
if (pc1 != pc) {
trace[size++] = (uptr) pc1;
@@ -156,111 +152,19 @@ void StackTrace::PopStackFrames(uptr count) {
}
}
-// On 32-bits we don't compress stack traces.
-// On 64-bits we compress stack traces: if a given pc differes slightly from
-// the previous one, we record a 31-bit offset instead of the full pc.
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr StackTrace::CompressStack(StackTrace *stack, u32 *compressed, uptr size) {
-#if SANITIZER_WORDSIZE == 32
- // Don't compress, just copy.
- uptr res = 0;
- for (uptr i = 0; i < stack->size && i < size; i++) {
- compressed[i] = stack->trace[i];
- res++;
- }
- if (stack->size < size)
- compressed[stack->size] = 0;
-#else // 64 bits, compress.
- uptr prev_pc = 0;
- const uptr kMaxOffset = (1ULL << 30) - 1;
- uptr c_index = 0;
- uptr res = 0;
- for (uptr i = 0, n = stack->size; i < n; i++) {
- uptr pc = stack->trace[i];
- if (!pc) break;
- if ((s64)pc < 0) break;
- // Printf("C pc[%zu] %zx\n", i, pc);
- if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) {
- uptr offset = (s64)(pc - prev_pc);
- offset |= (1U << 31);
- if (c_index >= size) break;
- // Printf("C co[%zu] offset %zx\n", i, offset);
- compressed[c_index++] = offset;
- } else {
- uptr hi = pc >> 32;
- uptr lo = (pc << 32) >> 32;
- CHECK_EQ((hi & (1 << 31)), 0);
- if (c_index + 1 >= size) break;
- // Printf("C co[%zu] hi/lo: %zx %zx\n", c_index, hi, lo);
- compressed[c_index++] = hi;
- compressed[c_index++] = lo;
- }
- res++;
- prev_pc = pc;
- }
- if (c_index < size)
- compressed[c_index] = 0;
- if (c_index + 1 < size)
- compressed[c_index + 1] = 0;
-#endif // SANITIZER_WORDSIZE
-
- // debug-only code
-#if 0
- StackTrace check_stack;
- UncompressStack(&check_stack, compressed, size);
- if (res < check_stack.size) {
- Printf("res %zu check_stack.size %zu; c_size %zu\n", res,
- check_stack.size, size);
- }
- // |res| may be greater than check_stack.size, because
- // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames.
- CHECK(res >= check_stack.size);
- CHECK_EQ(0, REAL(memcmp)(check_stack.trace, stack->trace,
- check_stack.size * sizeof(uptr)));
-#endif
-
- return res;
+static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
+ return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
}
-SANITIZER_INTERFACE_ATTRIBUTE
-void StackTrace::UncompressStack(StackTrace *stack,
- u32 *compressed, uptr size) {
-#if SANITIZER_WORDSIZE == 32
- // Don't uncompress, just copy.
- stack->size = 0;
- for (uptr i = 0; i < size && i < kStackTraceMax; i++) {
- if (!compressed[i]) break;
- stack->size++;
- stack->trace[i] = compressed[i];
- }
-#else // 64 bits, uncompress
- uptr prev_pc = 0;
- stack->size = 0;
- for (uptr i = 0; i < size && stack->size < kStackTraceMax; i++) {
- u32 x = compressed[i];
- uptr pc = 0;
- if (x & (1U << 31)) {
- // Printf("U co[%zu] offset: %x\n", i, x);
- // this is an offset
- s32 offset = x;
- offset = (offset << 1) >> 1; // remove the 31-byte and sign-extend.
- pc = prev_pc + offset;
- CHECK(pc);
- } else {
- // CHECK(i + 1 < size);
- if (i + 1 >= size) break;
- uptr hi = x;
- uptr lo = compressed[i+1];
- // Printf("U co[%zu] hi/lo: %zx %zx\n", i, hi, lo);
- i++;
- pc = (hi << 32) | lo;
- if (!pc) break;
- }
- // Printf("U pc[%zu] %zx\n", stack->size, pc);
- stack->trace[stack->size++] = pc;
- prev_pc = pc;
+uptr StackTrace::LocatePcInTrace(uptr pc) {
+ // Use threshold to find PC in stack trace, as PC we want to unwind from may
+ // slightly differ from return address in the actual unwinded stack trace.
+ const int kPcThreshold = 192;
+ for (uptr i = 0; i < size; ++i) {
+ if (MatchPc(pc, trace[i], kPcThreshold))
+ return i;
}
-#endif // SANITIZER_WORDSIZE
+ return 0;
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index 1f05753d207..d06db5ffa7a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -21,58 +21,55 @@ static const uptr kStackTraceMax = 256;
defined(__powerpc__) || defined(__powerpc64__) || \
defined(__sparc__) || \
defined(__mips__))
-#define SANITIZER_CAN_FAST_UNWIND 0
+# define SANITIZER_CAN_FAST_UNWIND 0
+#elif SANITIZER_WINDOWS
+# define SANITIZER_CAN_FAST_UNWIND 0
#else
-#define SANITIZER_CAN_FAST_UNWIND 1
+# define SANITIZER_CAN_FAST_UNWIND 1
#endif
struct StackTrace {
typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
int out_size);
+ uptr top_frame_bp;
uptr size;
- uptr max_size;
uptr trace[kStackTraceMax];
+
+ // Prints a symbolized stacktrace, followed by an empty line.
static void PrintStack(const uptr *addr, uptr size,
- bool symbolize, const char *strip_file_prefix,
- SymbolizeCallback symbolize_callback);
- void CopyTo(uptr *dst, uptr dst_size) {
- for (uptr i = 0; i < size && i < dst_size; i++)
- dst[i] = trace[i];
- for (uptr i = size; i < dst_size; i++)
- dst[i] = 0;
- }
+ SymbolizeCallback symbolize_callback = 0);
- void CopyFrom(uptr *src, uptr src_size) {
+ void CopyFrom(const uptr *src, uptr src_size) {
+ top_frame_bp = 0;
size = src_size;
if (size > kStackTraceMax) size = kStackTraceMax;
- for (uptr i = 0; i < size; i++) {
+ for (uptr i = 0; i < size; i++)
trace[i] = src[i];
- }
}
- void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom);
- void SlowUnwindStack(uptr pc, uptr max_depth);
+ static bool WillUseFastUnwind(bool request_fast_unwind) {
+ // Check if fast unwind is available. Fast unwind is the only option on Mac.
+ if (!SANITIZER_CAN_FAST_UNWIND)
+ return false;
+ else if (SANITIZER_MAC)
+ return true;
+ return request_fast_unwind;
+ }
- void PopStackFrames(uptr count);
+ void Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
+ uptr stack_bottom, bool request_fast_unwind);
static uptr GetCurrentPc();
static uptr GetPreviousInstructionPc(uptr pc);
- SANITIZER_INTERFACE_ATTRIBUTE
- static uptr CompressStack(StackTrace *stack,
- u32 *compressed, uptr size);
- SANITIZER_INTERFACE_ATTRIBUTE
- static void UncompressStack(StackTrace *stack,
- u32 *compressed, uptr size);
+ private:
+ void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
+ uptr max_depth);
+ void SlowUnwindStack(uptr pc, uptr max_depth);
+ void PopStackFrames(uptr count);
+ uptr LocatePcInTrace(uptr pc);
};
-
-const char *StripPathPrefix(const char *filepath,
- const char *strip_file_prefix);
-
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast);
-
} // namespace __sanitizer
// Use this macro if you want to print stack trace with the caller
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
new file mode 100644
index 00000000000..ea2f9d07771
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -0,0 +1,26 @@
+//===-- sanitizer_stacktrace_libcdep.cc -----------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_stacktrace.h"
+
+namespace __sanitizer {
+
+void StackTrace::Unwind(uptr max_depth, uptr pc, uptr bp, uptr stack_top,
+ uptr stack_bottom, bool request_fast_unwind) {
+ if (!WillUseFastUnwind(request_fast_unwind))
+ SlowUnwindStack(pc, max_depth);
+ else
+ FastUnwindStack(pc, bp, stack_top, stack_bottom, max_depth);
+
+ top_frame_bp = size ? bp : 0;
+}
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 4f44a036982..2b3dd29591e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -16,6 +16,8 @@
#include "sanitizer_stoptheworld.h"
+#include "sanitizer_platform_limits_posix.h"
+
#include <errno.h>
#include <sched.h> // for CLONE_* definitions
#include <stddef.h>
@@ -29,7 +31,16 @@
#endif
#include <sys/wait.h> // for signal-related stuff
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
#include "sanitizer_common.h"
+#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_linux.h"
#include "sanitizer_mutex.h"
@@ -45,30 +56,14 @@
// clone() interface (we want to share the address space with the caller
// process, so we prefer clone() over fork()).
//
-// We avoid the use of libc for two reasons:
+// We don't use any libc functions, relying instead on direct syscalls. There
+// are two reasons for this:
// 1. calling a library function while threads are suspended could cause a
// deadlock, if one of the treads happens to be holding a libc lock;
// 2. it's generally not safe to call libc functions from the tracer task,
// because clone() does not set up a thread-local storage for it. Any
// thread-local variables used by libc will be shared between the tracer task
// and the thread which spawned it.
-//
-// We deal with this by replacing libc calls with calls to our own
-// implementations defined in sanitizer_libc.h and sanitizer_linux.h. However,
-// there are still some libc functions which are used here:
-//
-// * All of the system calls ultimately go through the libc syscall() function.
-// We're operating under the assumption that syscall()'s implementation does
-// not acquire any locks or use any thread-local data (except for the errno
-// variable, which we handle separately).
-//
-// * We lack custom implementations of sigfillset() and sigaction(), so we use
-// the libc versions instead. The same assumptions as above apply.
-//
-// * It is safe to call libc functions before the cloned thread is spawned or
-// after it has exited. The following functions are used in this manner:
-// sigdelset()
-// sigprocmask()
COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
@@ -103,10 +98,11 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
- Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
+ if (common_flags()->verbosity)
+ Report("Could not attach to thread %d (errno %d).\n", thread_id, pterrno);
return false;
} else {
- if (SanitizerVerbosity > 0)
+ if (common_flags()->verbosity)
Report("Attached to thread %d.\n", thread_id);
// The thread is not guaranteed to stop before ptrace returns, so we must
// wait on it.
@@ -116,8 +112,9 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
if (internal_iserror(waitpid_status, &wperrno)) {
// Got a ECHILD error. I don't think this situation is possible, but it
// doesn't hurt to report it.
- Report("Waiting on thread %d failed, detaching (errno %d).\n", thread_id,
- wperrno);
+ if (common_flags()->verbosity)
+ Report("Waiting on thread %d failed, detaching (errno %d).\n",
+ thread_id, wperrno);
internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
return false;
}
@@ -132,13 +129,14 @@ void ThreadSuspender::ResumeAllThreads() {
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL),
&pterrno)) {
- if (SanitizerVerbosity > 0)
+ if (common_flags()->verbosity)
Report("Detached from thread %d.\n", tid);
} else {
// Either the thread is dead, or we are already detached.
// The latter case is possible, for instance, if this function was called
// from a signal handler.
- Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
+ if (common_flags()->verbosity)
+ Report("Could not detach from thread %d (errno %d).\n", tid, pterrno);
}
}
}
@@ -183,15 +181,16 @@ static const int kUnblockedSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV,
struct TracerThreadArgument {
StopTheWorldCallback callback;
void *callback_argument;
- // The tracer thread waits on this mutex while the parent finished its
+ // The tracer thread waits on this mutex while the parent finishes its
// preparations.
BlockingMutex mutex;
+ uptr parent_pid;
};
static DieCallbackType old_die_callback;
// Signal handler to wake up suspended threads when the tracer thread dies.
-void TracerThreadSignalHandler(int signum, siginfo_t *siginfo, void *) {
+void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
if (thread_suspender_instance != NULL) {
if (signum == SIGABRT)
thread_suspender_instance->KillAllThreads();
@@ -222,6 +221,11 @@ static int TracerThread(void* argument) {
TracerThreadArgument *tracer_thread_argument =
(TracerThreadArgument *)argument;
+ internal_prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
+ // Check if parent is already dead.
+ if (internal_getppid() != tracer_thread_argument->parent_pid)
+ internal__exit(4);
+
// Wait for the parent thread to finish preparations.
tracer_thread_argument->mutex.Lock();
tracer_thread_argument->mutex.Unlock();
@@ -244,17 +248,18 @@ static int TracerThread(void* argument) {
// the mask we inherited from the caller thread.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- struct sigaction new_sigaction;
+ __sanitizer_kernel_sigaction_t new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_sigaction = TracerThreadSignalHandler;
+ new_sigaction.sigaction = TracerThreadSignalHandler;
new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
+ internal_sigfillset(&new_sigaction.sa_mask);
+ internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction, NULL);
}
int exit_code = 0;
if (!thread_suspender.SuspendAllThreads()) {
- Report("Failed suspending threads.\n");
+ if (common_flags()->verbosity)
+ Report("Failed suspending threads.\n");
exit_code = 3;
} else {
tracer_thread_argument->callback(thread_suspender.suspended_threads_list(),
@@ -292,44 +297,36 @@ class ScopedStackSpaceWithGuard {
uptr guard_start_;
};
-NOINLINE static void WipeStack() {
- char arr[256];
- internal_memset(arr, 0, sizeof(arr));
-}
-
// We have a limitation on the stack frame size, so some stuff had to be moved
// into globals.
-static sigset_t blocked_sigset;
-static sigset_t old_sigset;
-static struct sigaction old_sigactions[ARRAY_SIZE(kUnblockedSignals)];
+static __sanitizer_kernel_sigset_t blocked_sigset;
+static __sanitizer_kernel_sigset_t old_sigset;
+static __sanitizer_kernel_sigaction_t old_sigactions
+ [ARRAY_SIZE(kUnblockedSignals)];
class StopTheWorldScope {
public:
StopTheWorldScope() {
- // Glibc's sigaction() has a side-effect where it copies garbage stack
- // values into oldact, which can cause false negatives in LSan. As a quick
- // workaround we zero some stack space here.
- WipeStack();
// Block all signals that can be blocked safely, and install
// default handlers for the remaining signals.
// We cannot allow user-defined handlers to run while the ThreadSuspender
// thread is active, because they could conceivably call some libc functions
// which modify errno (which is shared between the two threads).
- sigfillset(&blocked_sigset);
+ internal_sigfillset(&blocked_sigset);
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
// Remove the signal from the set of blocked signals.
- sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
+ internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
// Install the default handler.
- struct sigaction new_sigaction;
+ __sanitizer_kernel_sigaction_t new_sigaction;
internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sa_handler = SIG_DFL;
- sigfillset(&new_sigaction.sa_mask);
- sigaction(kUnblockedSignals[signal_index], &new_sigaction,
+ new_sigaction.handler = SIG_DFL;
+ internal_sigfillset(&new_sigaction.sa_mask);
+ internal_sigaction(kUnblockedSignals[signal_index], &new_sigaction,
&old_sigactions[signal_index]);
}
int sigprocmask_status =
- sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+ internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
// Make this process dumpable. Processes that are not dumpable cannot be
// attached to.
@@ -347,10 +344,10 @@ class StopTheWorldScope {
// Restore the signal handlers.
for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
signal_index++) {
- sigaction(kUnblockedSignals[signal_index],
+ internal_sigaction(kUnblockedSignals[signal_index],
&old_sigactions[signal_index], NULL);
}
- sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
+ internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
private:
@@ -363,6 +360,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
struct TracerThreadArgument tracer_thread_argument;
tracer_thread_argument.callback = callback;
tracer_thread_argument.callback_argument = argument;
+ tracer_thread_argument.parent_pid = internal_getpid();
const uptr kTracerStackSize = 2 * 1024 * 1024;
ScopedStackSpaceWithGuard tracer_stack(kTracerStackSize);
// Block the execution of TracerThread until after we have set ptrace
@@ -375,7 +373,8 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
/* child_tidptr */);
int local_errno = 0;
if (internal_iserror(tracer_pid, &local_errno)) {
- Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
+ if (common_flags()->verbosity)
+ Report("Failed spawning a tracer thread (errno %d).\n", local_errno);
tracer_thread_argument.mutex.Unlock();
} else {
// On some systems we have to explicitly declare that we want to be traced
@@ -390,8 +389,11 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
// At this point, any signal will either be blocked or kill us, so waitpid
// should never return (and set errno) while the tracer thread is alive.
uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL);
- if (internal_iserror(waitpid_status, &local_errno))
- Report("Waiting on the tracer thread failed (errno %d).\n", local_errno);
+ if (internal_iserror(waitpid_status, &local_errno)) {
+ if (common_flags()->verbosity)
+ Report("Waiting on the tracer thread failed (errno %d).\n",
+ local_errno);
+ }
}
}
@@ -432,7 +434,8 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, &regs),
&pterrno)) {
- Report("Could not get registers from thread %d (errno %d).\n",
+ if (common_flags()->verbosity)
+ Report("Could not get registers from thread %d (errno %d).\n",
tid, pterrno);
return -1;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
index d8e8976a4b2..14f13e62081 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
@@ -18,7 +18,7 @@
namespace __sanitizer {
static const char *const kTypeStrings[SuppressionTypeCount] = {
- "none", "race", "mutex", "thread", "signal", "leak"
+ "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib"
};
bool TemplateMatch(char *templ, const char *str) {
@@ -127,10 +127,15 @@ void SuppressionContext::Parse(const char *str) {
}
}
-uptr SuppressionContext::SuppressionCount() {
+uptr SuppressionContext::SuppressionCount() const {
return suppressions_.size();
}
+const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
+ CHECK_LT(i, suppressions_.size());
+ return &suppressions_[i];
+}
+
void SuppressionContext::GetMatched(
InternalMmapVector<Suppression *> *matched) {
for (uptr i = 0; i < suppressions_.size(); i++)
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.h b/libsanitizer/sanitizer_common/sanitizer_suppressions.h
index 9a0d87b383e..b4c719cb187 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.h
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.h
@@ -23,6 +23,7 @@ enum SuppressionType {
SuppressionThread,
SuppressionSignal,
SuppressionLeak,
+ SuppressionLib,
SuppressionTypeCount
};
@@ -38,7 +39,8 @@ class SuppressionContext {
SuppressionContext() : suppressions_(1), can_parse_(true) {}
void Parse(const char *str);
bool Match(const char* str, SuppressionType type, Suppression **s);
- uptr SuppressionCount();
+ uptr SuppressionCount() const;
+ const Suppression *SuppressionAt(uptr i) const;
void GetMatched(InternalMmapVector<Suppression *> *matched);
private:
@@ -50,7 +52,6 @@ class SuppressionContext {
const char *SuppressionTypeString(SuppressionType t);
-// Exposed for testing.
bool TemplateMatch(char *templ, const char *str);
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
new file mode 100644
index 00000000000..f417b087ae2
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
@@ -0,0 +1,61 @@
+//===-- sanitizer_symbolizer.cc -------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_placement_new.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+Symbolizer *Symbolizer::symbolizer_;
+StaticSpinMutex Symbolizer::init_mu_;
+LowLevelAllocator Symbolizer::symbolizer_allocator_;
+
+Symbolizer *Symbolizer::GetOrNull() {
+ SpinMutexLock l(&init_mu_);
+ return symbolizer_;
+}
+
+Symbolizer *Symbolizer::Get() {
+ SpinMutexLock l(&init_mu_);
+ RAW_CHECK_MSG(symbolizer_ != 0, "Using uninitialized symbolizer!");
+ return symbolizer_;
+}
+
+Symbolizer *Symbolizer::Disable() {
+ CHECK_EQ(0, symbolizer_);
+ // Initialize a dummy symbolizer.
+ symbolizer_ = new(symbolizer_allocator_) Symbolizer;
+ return symbolizer_;
+}
+
+void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
+ Symbolizer::EndSymbolizationHook end_hook) {
+ CHECK(start_hook_ == 0 && end_hook_ == 0);
+ start_hook_ = start_hook;
+ end_hook_ = end_hook;
+}
+
+Symbolizer::Symbolizer() : start_hook_(0), end_hook_(0) {}
+
+Symbolizer::SymbolizerScope::SymbolizerScope(const Symbolizer *sym)
+ : sym_(sym) {
+ if (sym_->start_hook_)
+ sym_->start_hook_();
+}
+
+Symbolizer::SymbolizerScope::~SymbolizerScope() {
+ if (sym_->end_hook_)
+ sym_->end_hook_();
+}
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index 2c84773eebc..af93de75081 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -5,19 +5,14 @@
//
//===----------------------------------------------------------------------===//
//
-// Symbolizer is intended to be used by both
-// AddressSanitizer and ThreadSanitizer to symbolize a given
-// address. It is an analogue of addr2line utility and allows to map
-// instruction address to a location in source code at run-time.
+// Symbolizer is used by sanitizers to map instruction address to a location in
+// source code at run-time. Symbolizer either uses __sanitizer_symbolize_*
+// defined in the program, or (if they are missing) tries to find and
+// launch "llvm-symbolizer" commandline tool in a separate process and
+// communicate with it.
//
-// Symbolizer is planned to use debug information (in DWARF format)
-// in a binary via interface defined in "llvm/DebugInfo/DIContext.h"
-//
-// Symbolizer code should be called from the run-time library of
-// dynamic tools, and generally should not call memory allocation
-// routines or other system library functions intercepted by those tools.
-// Instead, Symbolizer code should use their replacements, defined in
-// "compiler-rt/lib/sanitizer_common/sanitizer_libc.h".
+// Generally we should try to avoid calling system library functions during
+// symbolization (and use their replacements from sanitizer_libc.h instead).
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_SYMBOLIZER_H
#define SANITIZER_SYMBOLIZER_H
@@ -25,7 +20,6 @@
#include "sanitizer_allocator_internal.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
-// WARNING: Do not include system headers here. See details above.
namespace __sanitizer {
@@ -67,8 +61,24 @@ struct DataInfo {
uptr size;
};
-class SymbolizerInterface {
+class Symbolizer {
public:
+ /// Returns platform-specific implementation of Symbolizer. The symbolizer
+ /// must be initialized (with init or disable) before calling this function.
+ static Symbolizer *Get();
+ /// Returns platform-specific implementation of Symbolizer, or null if not
+ /// initialized.
+ static Symbolizer *GetOrNull();
+ /// Returns platform-specific implementation of Symbolizer. Will
+ /// automatically initialize symbolizer as if by calling Init(0) if needed.
+ static Symbolizer *GetOrInit();
+ /// Initialize and return the symbolizer, given an optional path to an
+ /// external symbolizer. The path argument is only required for legacy
+ /// reasons as this function will check $PATH for an external symbolizer. Not
+ /// thread safe.
+ static Symbolizer *Init(const char* path_to_external = 0);
+ /// Initialize the symbolizer in a disabled state. Not thread safe.
+ static Symbolizer *Disable();
// Fills at most "max_frames" elements of "frames" with descriptions
// for a given address (in all inlined functions). Returns the number
// of descriptions actually filled.
@@ -82,6 +92,9 @@ class SymbolizerInterface {
virtual bool IsAvailable() {
return false;
}
+ virtual bool IsExternalAvailable() {
+ return false;
+ }
// Release internal caches (if any).
virtual void Flush() {}
// Attempts to demangle the provided C++ mangled name.
@@ -89,17 +102,42 @@ class SymbolizerInterface {
return name;
}
virtual void PrepareForSandboxing() {}
- // Starts external symbolizer program in a subprocess. Sanitizer communicates
- // with external symbolizer via pipes. If path_to_symbolizer is NULL or empty,
- // tries to look for llvm-symbolizer in PATH.
- virtual bool InitializeExternal(const char *path_to_symbolizer) {
- return false;
- }
-};
-// Returns platform-specific implementation of SymbolizerInterface. It can't be
-// used from multiple threads simultaneously.
-SANITIZER_WEAK_ATTRIBUTE SymbolizerInterface *getSymbolizer();
+ // Allow user to install hooks that would be called before/after Symbolizer
+ // does the actual file/line info fetching. Specific sanitizers may need this
+ // to distinguish system library calls made in user code from calls made
+ // during in-process symbolization.
+ typedef void (*StartSymbolizationHook)();
+ typedef void (*EndSymbolizationHook)();
+ // May be called at most once.
+ void AddHooks(StartSymbolizationHook start_hook,
+ EndSymbolizationHook end_hook);
+
+ private:
+ /// Platform-specific function for creating a Symbolizer object.
+ static Symbolizer *PlatformInit(const char *path_to_external);
+ /// Create a symbolizer and store it to symbolizer_ without checking if one
+ /// already exists. Not thread safe.
+ static Symbolizer *CreateAndStore(const char *path_to_external);
+
+ static Symbolizer *symbolizer_;
+ static StaticSpinMutex init_mu_;
+
+ protected:
+ Symbolizer();
+
+ static LowLevelAllocator symbolizer_allocator_;
+
+ StartSymbolizationHook start_hook_;
+ EndSymbolizationHook end_hook_;
+ class SymbolizerScope {
+ public:
+ explicit SymbolizerScope(const Symbolizer *sym);
+ ~SymbolizerScope();
+ private:
+ const Symbolizer *sym_;
+ };
+};
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
new file mode 100644
index 00000000000..5654d1de7d4
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -0,0 +1,144 @@
+//===-- sanitizer_symbolizer_libbacktrace.cc ------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Libbacktrace implementation of symbolizer parts.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
+
+#if SANITIZER_LIBBACKTRACE
+# include "backtrace-supported.h"
+# if SANITIZER_POSIX && BACKTRACE_SUPPORTED && !BACKTRACE_USES_MALLOC
+# include "backtrace.h"
+# else
+# define SANITIZER_LIBBACKTRACE 0
+# endif
+#endif
+
+namespace __sanitizer {
+
+#if SANITIZER_LIBBACKTRACE
+
+namespace {
+
+struct SymbolizeCodeData {
+ AddressInfo *frames;
+ uptr n_frames;
+ uptr max_frames;
+ const char *module_name;
+ uptr module_offset;
+};
+
+extern "C" {
+static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
+ const char *filename, int lineno,
+ const char *function) {
+ SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
+ if (function) {
+ AddressInfo *info = &cdata->frames[cdata->n_frames++];
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = internal_strdup(function);
+ if (filename)
+ info->file = internal_strdup(filename);
+ info->line = lineno;
+ if (cdata->n_frames == cdata->max_frames)
+ return 1;
+ }
+ return 0;
+}
+
+static void SymbolizeCodeCallback(void *vdata, uintptr_t addr,
+ const char *symname, uintptr_t, uintptr_t) {
+ SymbolizeCodeData *cdata = (SymbolizeCodeData *)vdata;
+ if (symname) {
+ AddressInfo *info = &cdata->frames[0];
+ info->Clear();
+ info->FillAddressAndModuleInfo(addr, cdata->module_name,
+ cdata->module_offset);
+ info->function = internal_strdup(symname);
+ cdata->n_frames = 1;
+ }
+}
+
+static void SymbolizeDataCallback(void *vdata, uintptr_t, const char *symname,
+ uintptr_t symval, uintptr_t symsize) {
+ DataInfo *info = (DataInfo *)vdata;
+ if (symname && symval) {
+ info->name = internal_strdup(symname);
+ info->start = symval;
+ info->size = symsize;
+ }
+}
+
+static void ErrorCallback(void *, const char *, int) {}
+} // extern "C"
+
+} // namespace
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ // State created in backtrace_create_state is leaked.
+ void *state = (void *)(backtrace_create_state("/proc/self/exe", 0,
+ ErrorCallback, NULL));
+ if (!state)
+ return 0;
+ return new(*alloc) LibbacktraceSymbolizer(state);
+}
+
+uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
+ uptr max_frames,
+ const char *module_name,
+ uptr module_offset) {
+ SymbolizeCodeData data;
+ data.frames = frames;
+ data.n_frames = 0;
+ data.max_frames = max_frames;
+ data.module_name = module_name;
+ data.module_offset = module_offset;
+ backtrace_pcinfo((backtrace_state *)state_, addr, SymbolizeCodePCInfoCallback,
+ ErrorCallback, &data);
+ if (data.n_frames)
+ return data.n_frames;
+ backtrace_syminfo((backtrace_state *)state_, addr, SymbolizeCodeCallback,
+ ErrorCallback, &data);
+ return data.n_frames;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+ backtrace_syminfo((backtrace_state *)state_, info->address,
+ SymbolizeDataCallback, ErrorCallback, info);
+ return true;
+}
+
+#else // SANITIZER_LIBBACKTRACE
+
+LibbacktraceSymbolizer *LibbacktraceSymbolizer::get(LowLevelAllocator *alloc) {
+ return 0;
+}
+
+uptr LibbacktraceSymbolizer::SymbolizeCode(uptr addr, AddressInfo *frames,
+ uptr max_frames,
+ const char *module_name,
+ uptr module_offset) {
+ (void)state_;
+ return 0;
+}
+
+bool LibbacktraceSymbolizer::SymbolizeData(DataInfo *info) {
+ return false;
+}
+
+#endif // SANITIZER_LIBBACKTRACE
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
new file mode 100644
index 00000000000..f09cea51268
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_symbolizer_libbacktrace.h -------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+// Header for libbacktrace symbolizer.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+
+#ifndef SANITIZER_LIBBACKTRACE
+# define SANITIZER_LIBBACKTRACE 0
+#endif
+
+namespace __sanitizer {
+
+class LibbacktraceSymbolizer {
+ public:
+ static LibbacktraceSymbolizer *get(LowLevelAllocator *alloc);
+
+ uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames,
+ const char *module_name, uptr module_offset);
+
+ bool SymbolizeData(DataInfo *info);
+
+ private:
+ explicit LibbacktraceSymbolizer(void *state) : state_(state) {}
+
+ void *state_; // Leaked.
+};
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
new file mode 100644
index 00000000000..2d9caaf4e85
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -0,0 +1,37 @@
+//===-- sanitizer_symbolizer_libcdep.cc -----------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+Symbolizer *Symbolizer::CreateAndStore(const char *path_to_external) {
+ Symbolizer *platform_symbolizer = PlatformInit(path_to_external);
+ if (!platform_symbolizer)
+ return Disable();
+ symbolizer_ = platform_symbolizer;
+ return platform_symbolizer;
+}
+
+Symbolizer *Symbolizer::Init(const char *path_to_external) {
+ CHECK_EQ(0, symbolizer_);
+ return CreateAndStore(path_to_external);
+}
+
+Symbolizer *Symbolizer::GetOrInit() {
+ SpinMutexLock l(&init_mu_);
+ if (symbolizer_ == 0)
+ return CreateAndStore(0);
+ return symbolizer_;
+}
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index 34063081c77..9f34b646217 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -19,6 +19,7 @@
#include "sanitizer_placement_new.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
#include <errno.h>
#include <stdlib.h>
@@ -203,19 +204,49 @@ static const char *ExtractUptr(const char *str, const char *delims,
// <file_name>:<line_number>:<column_number>
// ...
// <empty line>
+// ExternalSymbolizer may not be used from two threads simultaneously.
class ExternalSymbolizer {
public:
- ExternalSymbolizer(const char *path, int input_fd, int output_fd)
+ explicit ExternalSymbolizer(const char *path)
: path_(path),
- input_fd_(input_fd),
- output_fd_(output_fd),
- times_restarted_(0) {
+ input_fd_(kInvalidFd),
+ output_fd_(kInvalidFd),
+ times_restarted_(0),
+ failed_to_start_(false) {
CHECK(path_);
- CHECK_NE(input_fd_, kInvalidFd);
- CHECK_NE(output_fd_, kInvalidFd);
+ CHECK_NE(path[0], '\0');
}
char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
+ // Start or restart symbolizer if we failed to send command to it.
+ if (char *res = SendCommandImpl(is_data, module_name, module_offset))
+ return res;
+ Restart();
+ }
+ if (!failed_to_start_) {
+ Report("WARNING: Failed to use and restart external symbolizer!\n");
+ failed_to_start_ = true;
+ }
+ return 0;
+ }
+
+ void Flush() {
+ }
+
+ private:
+ bool Restart() {
+ if (input_fd_ != kInvalidFd)
+ internal_close(input_fd_);
+ if (output_fd_ != kInvalidFd)
+ internal_close(output_fd_);
+ return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
+ }
+
+ char *SendCommandImpl(bool is_data, const char *module_name,
+ uptr module_offset) {
+ if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd)
+ return 0;
CHECK(module_name);
internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
is_data ? "DATA " : "", module_name, module_offset);
@@ -226,18 +257,6 @@ class ExternalSymbolizer {
return buffer_;
}
- bool Restart() {
- if (times_restarted_ >= kMaxTimesRestarted) return false;
- times_restarted_++;
- internal_close(input_fd_);
- internal_close(output_fd_);
- return StartSymbolizerSubprocess(path_, &input_fd_, &output_fd_);
- }
-
- void Flush() {
- }
-
- private:
bool readFromSymbolizer(char *buffer, uptr max_length) {
if (max_length == 0)
return true;
@@ -281,10 +300,9 @@ class ExternalSymbolizer {
static const uptr kMaxTimesRestarted = 5;
uptr times_restarted_;
+ bool failed_to_start_;
};
-static LowLevelAllocator symbolizer_allocator; // Linker initialized.
-
#if SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
@@ -304,11 +322,10 @@ class InternalSymbolizer {
public:
typedef bool (*SanitizerSymbolizeFn)(const char*, u64, char*, int);
- static InternalSymbolizer *get() {
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) {
if (__sanitizer_symbolize_code != 0 &&
__sanitizer_symbolize_data != 0) {
- void *mem = symbolizer_allocator.Allocate(sizeof(InternalSymbolizer));
- return new(mem) InternalSymbolizer();
+ return new(*alloc) InternalSymbolizer();
}
return 0;
}
@@ -355,7 +372,7 @@ class InternalSymbolizer {
class InternalSymbolizer {
public:
- static InternalSymbolizer *get() { return 0; }
+ static InternalSymbolizer *get(LowLevelAllocator *alloc) { return 0; }
char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
return 0;
}
@@ -365,11 +382,18 @@ class InternalSymbolizer {
#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
-class Symbolizer : public SymbolizerInterface {
- // This class has no constructor, as global constructors are forbidden in
- // sanitizer_common. It should be linker initialized instead.
+class POSIXSymbolizer : public Symbolizer {
public:
+ POSIXSymbolizer(ExternalSymbolizer *external_symbolizer,
+ InternalSymbolizer *internal_symbolizer,
+ LibbacktraceSymbolizer *libbacktrace_symbolizer)
+ : Symbolizer(),
+ external_symbolizer_(external_symbolizer),
+ internal_symbolizer_(internal_symbolizer),
+ libbacktrace_symbolizer_(libbacktrace_symbolizer) {}
+
uptr SymbolizeCode(uptr addr, AddressInfo *frames, uptr max_frames) {
+ BlockingMutexLock l(&mu_);
if (max_frames == 0)
return 0;
LoadedModule *module = FindModuleForAddress(addr);
@@ -377,9 +401,17 @@ class Symbolizer : public SymbolizerInterface {
return 0;
const char *module_name = module->full_name();
uptr module_offset = addr - module->base_address();
+ // First, try to use libbacktrace symbolizer (if it's available).
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ uptr res = libbacktrace_symbolizer_->SymbolizeCode(
+ addr, frames, max_frames, module_name, module_offset);
+ if (res > 0)
+ return res;
+ }
const char *str = SendCommand(false, module_name, module_offset);
if (str == 0) {
- // External symbolizer was not initialized or failed. Fill only data
+ // Symbolizer was not initialized or failed. Fill only data
// about module name and offset.
AddressInfo *info = &frames[0];
info->Clear();
@@ -430,6 +462,7 @@ class Symbolizer : public SymbolizerInterface {
}
bool SymbolizeData(uptr addr, DataInfo *info) {
+ BlockingMutexLock l(&mu_);
LoadedModule *module = FindModuleForAddress(addr);
if (module == 0)
return false;
@@ -439,6 +472,11 @@ class Symbolizer : public SymbolizerInterface {
info->address = addr;
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
+ if (libbacktrace_symbolizer_ != 0) {
+ mu_.CheckLocked();
+ if (libbacktrace_symbolizer_->SymbolizeData(info))
+ return true;
+ }
const char *str = SendCommand(true, module_name, module_offset);
if (str == 0)
return true;
@@ -449,42 +487,38 @@ class Symbolizer : public SymbolizerInterface {
return true;
}
- bool InitializeExternal(const char *path_to_symbolizer) {
- if (!path_to_symbolizer || path_to_symbolizer[0] == '\0') {
- path_to_symbolizer = FindPathToBinary("llvm-symbolizer");
- if (!path_to_symbolizer)
- return false;
- }
- int input_fd, output_fd;
- if (!StartSymbolizerSubprocess(path_to_symbolizer, &input_fd, &output_fd))
- return false;
- void *mem = symbolizer_allocator.Allocate(sizeof(ExternalSymbolizer));
- external_symbolizer_ = new(mem) ExternalSymbolizer(path_to_symbolizer,
- input_fd, output_fd);
- return true;
+ bool IsAvailable() {
+ return internal_symbolizer_ != 0 || external_symbolizer_ != 0 ||
+ libbacktrace_symbolizer_ != 0;
}
- bool IsAvailable() {
- if (internal_symbolizer_ == 0)
- internal_symbolizer_ = InternalSymbolizer::get();
- return internal_symbolizer_ || external_symbolizer_;
+ bool IsExternalAvailable() {
+ return external_symbolizer_ != 0;
}
void Flush() {
- if (internal_symbolizer_)
+ BlockingMutexLock l(&mu_);
+ if (internal_symbolizer_ != 0) {
+ SymbolizerScope sym_scope(this);
internal_symbolizer_->Flush();
- if (external_symbolizer_)
+ }
+ if (external_symbolizer_ != 0)
external_symbolizer_->Flush();
}
const char *Demangle(const char *name) {
- if (IsAvailable() && internal_symbolizer_ != 0)
+ BlockingMutexLock l(&mu_);
+ // Run hooks even if we don't use internal symbolizer, as cxxabi
+ // demangle may call system functions.
+ SymbolizerScope sym_scope(this);
+ if (internal_symbolizer_ != 0)
return internal_symbolizer_->Demangle(name);
return DemangleCXXABI(name);
}
void PrepareForSandboxing() {
#if SANITIZER_LINUX && !SANITIZER_ANDROID
+ BlockingMutexLock l(&mu_);
// Cache /proc/self/exe on Linux.
CacheBinaryName();
#endif
@@ -492,41 +526,26 @@ class Symbolizer : public SymbolizerInterface {
private:
char *SendCommand(bool is_data, const char *module_name, uptr module_offset) {
+ mu_.CheckLocked();
// First, try to use internal symbolizer.
- if (!IsAvailable()) {
- return 0;
- }
if (internal_symbolizer_) {
+ SymbolizerScope sym_scope(this);
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 "
- "symbolizer is not initialized!\n");
- return 0;
- }
- for (;;) {
- char *reply = external_symbolizer_->SendCommand(is_data, module_name,
- module_offset);
- if (reply)
- return reply;
- // Try to restart symbolizer subprocess. If we don't succeed, forget
- // about it and don't try to use it later.
- if (!external_symbolizer_->Restart()) {
- ReportExternalSymbolizerError(
- "WARNING: Failed to use and restart external symbolizer!\n");
- external_symbolizer_ = 0;
- return 0;
- }
+ if (external_symbolizer_) {
+ return external_symbolizer_->SendCommand(is_data, module_name,
+ module_offset);
}
+ return 0;
}
LoadedModule *FindModuleForAddress(uptr address) {
+ mu_.CheckLocked();
bool modules_were_reloaded = false;
if (modules_ == 0 || !modules_fresh_) {
- modules_ = (LoadedModule*)(symbolizer_allocator.Allocate(
+ modules_ = (LoadedModule*)(symbolizer_allocator_.Allocate(
kMaxNumberOfModuleContexts * sizeof(LoadedModule)));
CHECK(modules_);
n_modules_ = GetListOfModules(modules_, kMaxNumberOfModuleContexts,
@@ -553,41 +572,40 @@ class Symbolizer : public SymbolizerInterface {
return 0;
}
- void ReportExternalSymbolizerError(const char *msg) {
- // Don't use atomics here for now, as SymbolizeCode can't be called
- // from multiple threads anyway.
- static bool reported;
- if (!reported) {
- Report(msg);
- reported = true;
- }
- }
-
// 16K loaded modules should be enough for everyone.
static const uptr kMaxNumberOfModuleContexts = 1 << 14;
LoadedModule *modules_; // Array of module descriptions is leaked.
uptr n_modules_;
// If stale, need to reload the modules before looking up addresses.
bool modules_fresh_;
+ BlockingMutex mu_;
- ExternalSymbolizer *external_symbolizer_; // Leaked.
- InternalSymbolizer *internal_symbolizer_; // Leaked.
+ ExternalSymbolizer *external_symbolizer_; // Leaked.
+ InternalSymbolizer *const internal_symbolizer_; // Leaked.
+ LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked.
};
-static ALIGNED(64) char symbolizer_placeholder[sizeof(Symbolizer)];
-static Symbolizer *symbolizer;
-
-SymbolizerInterface *getSymbolizer() {
- static atomic_uint8_t initialized;
- static StaticSpinMutex init_mu;
- if (atomic_load(&initialized, memory_order_acquire) == 0) {
- SpinMutexLock l(&init_mu);
- if (atomic_load(&initialized, memory_order_relaxed) == 0) {
- symbolizer = new(symbolizer_placeholder) Symbolizer();
- atomic_store(&initialized, 1, memory_order_release);
+Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) {
+ InternalSymbolizer* internal_symbolizer =
+ InternalSymbolizer::get(&symbolizer_allocator_);
+ ExternalSymbolizer *external_symbolizer = 0;
+ LibbacktraceSymbolizer *libbacktrace_symbolizer = 0;
+
+ if (!internal_symbolizer) {
+ libbacktrace_symbolizer =
+ LibbacktraceSymbolizer::get(&symbolizer_allocator_);
+ if (!libbacktrace_symbolizer) {
+ // Find path to llvm-symbolizer if it's not provided.
+ if (!path_to_external)
+ path_to_external = FindPathToBinary("llvm-symbolizer");
+ if (path_to_external && path_to_external[0] != '\0')
+ external_symbolizer = new(symbolizer_allocator_)
+ ExternalSymbolizer(path_to_external);
}
}
- return symbolizer;
+
+ return new(symbolizer_allocator_) POSIXSymbolizer(
+ external_symbolizer, internal_symbolizer, libbacktrace_symbolizer);
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
index 44801f39b31..446de8af293 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -12,16 +12,11 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
-#include "sanitizer_internal_defs.h"
#include "sanitizer_symbolizer.h"
namespace __sanitizer {
-static SymbolizerInterface win_symbolizer; // Linker initialized.
-
-SymbolizerInterface *getSymbolizer() {
- return &win_symbolizer;
-}
+Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { return 0; }
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
index 4f405d92b05..8810c7faa4b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_syscall_linux_x86_64.inc
@@ -11,7 +11,8 @@
static uptr internal_syscall(u64 nr) {
u64 retval;
- asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11");
+ asm volatile("syscall" : "=a"(retval) : "a"(nr) : "rcx", "r11",
+ "memory", "cc");
return retval;
}
@@ -19,7 +20,7 @@ template <typename T1>
static uptr internal_syscall(u64 nr, T1 arg1) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1) :
- "rcx", "r11");
+ "rcx", "r11", "memory", "cc");
return retval;
}
@@ -27,7 +28,7 @@ template <typename T1, typename T2>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
- "S"((u64)arg2) : "rcx", "r11");
+ "S"((u64)arg2) : "rcx", "r11", "memory", "cc");
return retval;
}
@@ -35,7 +36,7 @@ template <typename T1, typename T2, typename T3>
static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3) {
u64 retval;
asm volatile("syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
- "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11");
+ "S"((u64)arg2), "d"((u64)arg3) : "rcx", "r11", "memory", "cc");
return retval;
}
@@ -45,7 +46,7 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {
asm volatile("mov %5, %%r10;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4) :
- "rcx", "r11", "r10");
+ "rcx", "r11", "r10", "memory", "cc");
return retval;
}
@@ -57,7 +58,7 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
"mov %6, %%r8;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5) :
- "rcx", "r11", "r10", "r8");
+ "rcx", "r11", "r10", "r8", "memory", "cc");
return retval;
}
@@ -71,7 +72,8 @@ static uptr internal_syscall(u64 nr, T1 arg1, T2 arg2, T3 arg3, T4 arg4,
"mov %7, %%r9;"
"syscall" : "=a"(retval) : "a"(nr), "D"((u64)arg1),
"S"((u64)arg2), "d"((u64)arg3), "r"((u64)arg4), "r"((u64)arg5),
- "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9");
+ "r"((u64)arg6) : "rcx", "r11", "r10", "r8", "r9",
+ "memory", "cc");
return retval;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
index e639430f73a..666955f6c9a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
@@ -198,6 +198,18 @@ void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
tctx->SetName(name);
}
+void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) {
+ BlockingMutexLock l(&mtx_);
+ for (u32 tid = 0; tid < n_contexts_; tid++) {
+ ThreadContextBase *tctx = threads_[tid];
+ if (tctx != 0 && tctx->user_id == user_id &&
+ tctx->status != ThreadStatusInvalid) {
+ tctx->SetName(name);
+ return;
+ }
+ }
+}
+
void ThreadRegistry::DetachThread(u32 tid) {
BlockingMutexLock l(&mtx_);
CHECK_LT(tid, n_contexts_);
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
index 1ae47b800ca..81c270945d3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
@@ -107,6 +107,7 @@ class ThreadRegistry {
ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id);
void SetThreadName(u32 tid, const char *name);
+ void SetThreadNameByUserId(uptr user_id, const char *name);
void DetachThread(u32 tid);
void JoinThread(u32 tid, void *arg);
void FinishThread(u32 tid);
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc
index 0a5fe81ae45..c48274e3642 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cc
@@ -213,7 +213,7 @@ u64 NanoTime() {
void Abort() {
abort();
- _exit(-1); // abort is not NORETURN on Windows.
+ internal__exit(-1); // abort is not NORETURN on Windows.
}
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
@@ -303,7 +303,7 @@ uptr internal_sched_yield() {
}
void internal__exit(int exitcode) {
- _exit(exitcode);
+ ExitProcess(exitcode);
}
// ---------------------- BlockingMutex ---------------- {{{1
@@ -374,31 +374,15 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
#endif
}
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- uptr stack_top, uptr stack_bottom, bool fast) {
- (void)fast;
- (void)stack_top;
- (void)stack_bottom;
- stack->max_size = max_s;
- void *tmp[kStackTraceMax];
-
+void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
// FIXME: CaptureStackBackTrace might be too slow for us.
// FIXME: Compare with StackWalk64.
// FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
- uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
- uptr offset = 0;
+ size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
+ (void**)trace, 0);
// Skip the RTL frames by searching for the PC in the stacktrace.
- // FIXME: this doesn't work well for the malloc/free stacks yet.
- for (uptr i = 0; i < cs_ret; i++) {
- if (pc != (uptr)tmp[i])
- continue;
- offset = i;
- break;
- }
-
- stack->size = cs_ret - offset;
- for (uptr i = 0; i < stack->size; i++)
- stack->trace[i] = (uptr)tmp[i + offset];
+ uptr pc_location = LocatePcInTrace(pc);
+ PopStackFrames(pc_location);
}
void MaybeOpenReportFile() {
diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am
index 9b039d229d7..ca41550f5c6 100644
--- a/libsanitizer/tsan/Makefile.am
+++ b/libsanitizer/tsan/Makefile.am
@@ -23,6 +23,7 @@ tsan_files = \
tsan_rtl.cc \
tsan_stat.cc \
tsan_sync.cc \
+ tsan_ignoreset.cc \
tsan_interceptors.cc \
tsan_md5.cc \
tsan_platform_mac.cc \
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index eb5c7e7a84b..0bd16082693 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -84,12 +84,12 @@ libtsan_la_DEPENDENCIES = \
am__objects_1 = tsan_clock.lo tsan_interface_atomic.lo tsan_mutex.lo \
tsan_report.lo tsan_rtl_thread.lo tsan_symbolize.lo \
tsan_flags.lo tsan_interface.lo tsan_platform_linux.lo \
- tsan_rtl.lo tsan_stat.lo tsan_sync.lo tsan_interceptors.lo \
- tsan_md5.lo tsan_platform_mac.lo tsan_rtl_mutex.lo \
- tsan_suppressions.lo tsan_interface_ann.lo tsan_mman.lo \
- tsan_rtl_report.lo tsan_fd.lo tsan_interface_java.lo \
- tsan_mutexset.lo tsan_symbolize_addr2line_linux.lo \
- tsan_rtl_amd64.lo
+ tsan_rtl.lo tsan_stat.lo tsan_sync.lo tsan_ignoreset.lo \
+ tsan_interceptors.lo tsan_md5.lo tsan_platform_mac.lo \
+ tsan_rtl_mutex.lo tsan_suppressions.lo tsan_interface_ann.lo \
+ tsan_mman.lo tsan_rtl_report.lo tsan_fd.lo \
+ tsan_interface_java.lo tsan_mutexset.lo \
+ tsan_symbolize_addr2line_linux.lo tsan_rtl_amd64.lo
am_libtsan_la_OBJECTS = $(am__objects_1)
libtsan_la_OBJECTS = $(am_libtsan_la_OBJECTS)
libtsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -283,6 +283,7 @@ tsan_files = \
tsan_rtl.cc \
tsan_stat.cc \
tsan_sync.cc \
+ tsan_ignoreset.cc \
tsan_interceptors.cc \
tsan_md5.cc \
tsan_platform_mac.cc \
@@ -417,6 +418,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_clock.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_fd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_flags.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_ignoreset.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interceptors.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_interface_ann.Plo@am__quote@
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index 68936e02e4b..3f20797ff4b 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -39,10 +39,8 @@ const int kTidBits = 13;
const unsigned kMaxTid = 1 << kTidBits;
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
const int kClkBits = 42;
-#ifndef TSAN_GO
-const int kShadowStackSize = 4 * 1024;
-const int kTraceStackSize = 256;
-#endif
+const uptr kShadowStackSize = 64 * 1024;
+const uptr kTraceStackSize = 256;
#ifdef TSAN_SHADOW_COUNT
# if TSAN_SHADOW_COUNT == 2 \
@@ -154,6 +152,7 @@ struct MD5Hash {
MD5Hash md5_hash(const void *data, uptr size);
struct ThreadState;
+class ThreadContext;
struct Context;
struct ReportStack;
class ReportDesc;
diff --git a/libsanitizer/tsan/tsan_fd.cc b/libsanitizer/tsan/tsan_fd.cc
index de852b185a6..b7ac3111c89 100644
--- a/libsanitizer/tsan/tsan_fd.cc
+++ b/libsanitizer/tsan/tsan_fd.cc
@@ -40,6 +40,11 @@ struct FdContext {
static FdContext fdctx;
+static bool bogusfd(int fd) {
+ // Apparently a bogus fd value.
+ return fd < 0 || fd >= kTableSize;
+}
+
static FdSync *allocsync() {
FdSync *s = (FdSync*)internal_alloc(MBlockFD, sizeof(FdSync));
atomic_store(&s->rc, 1, memory_order_relaxed);
@@ -67,6 +72,7 @@ static void unref(ThreadState *thr, uptr pc, FdSync *s) {
}
static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
+ CHECK_GE(fd, 0);
CHECK_LT(fd, kTableSize);
atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2];
uptr l1 = atomic_load(pl1, memory_order_consume);
@@ -146,6 +152,8 @@ bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) {
}
void FdAcquire(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
FdSync *s = d->sync;
DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
@@ -155,6 +163,8 @@ void FdAcquire(ThreadState *thr, uptr pc, int fd) {
}
void FdRelease(ThreadState *thr, uptr pc, int fd) {
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
FdSync *s = d->sync;
DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
@@ -165,12 +175,16 @@ void FdRelease(ThreadState *thr, uptr pc, int fd) {
void FdAccess(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
MemoryRead(thr, pc, (uptr)d, kSizeLog8);
}
void FdClose(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
FdDesc *d = fddesc(thr, pc, fd);
// To catch races between fd usage and close.
MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
@@ -185,11 +199,15 @@ void FdClose(ThreadState *thr, uptr pc, int fd) {
void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, &fdctx.filesync);
}
void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
+ if (bogusfd(oldfd) || bogusfd(newfd))
+ return;
// Ignore the case when user dups not yet connected socket.
FdDesc *od = fddesc(thr, pc, oldfd);
MemoryRead(thr, pc, (uptr)od, kSizeLog8);
@@ -207,32 +225,44 @@ void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, allocsync());
}
void FdSignalCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, 0);
}
void FdInotifyCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, 0);
}
void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, allocsync());
}
void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
// It can be a UDP socket.
init(thr, pc, fd, &fdctx.socksync);
}
void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd);
+ if (bogusfd(fd))
+ return;
// Synchronize connect->accept.
Acquire(thr, pc, (uptr)&fdctx.connectsync);
init(thr, pc, newfd, &fdctx.socksync);
@@ -240,12 +270,16 @@ void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
// Synchronize connect->accept.
Release(thr, pc, (uptr)&fdctx.connectsync);
}
void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd);
+ if (bogusfd(fd))
+ return;
init(thr, pc, fd, &fdctx.socksync);
}
diff --git a/libsanitizer/tsan/tsan_flags.cc b/libsanitizer/tsan/tsan_flags.cc
index dbde4212c59..5bcf42e39ea 100644
--- a/libsanitizer/tsan/tsan_flags.cc
+++ b/libsanitizer/tsan/tsan_flags.cc
@@ -24,13 +24,43 @@ Flags *flags() {
// Can be overriden in frontend.
#ifdef TSAN_EXTERNAL_HOOKS
void OverrideFlags(Flags *f);
+extern "C" const char* __tsan_default_options();
#else
-SANITIZER_INTERFACE_ATTRIBUTE
void WEAK OverrideFlags(Flags *f) {
(void)f;
}
+extern "C" const char *WEAK __tsan_default_options() {
+ return "";
+}
#endif
+static void ParseFlags(Flags *f, const char *env) {
+ ParseFlag(env, &f->enable_annotations, "enable_annotations");
+ ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks");
+ ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses");
+ ParseFlag(env, &f->suppress_java, "suppress_java");
+ ParseFlag(env, &f->report_bugs, "report_bugs");
+ ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
+ ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
+ ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
+ ParseFlag(env, &f->report_atomic_races, "report_atomic_races");
+ ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics");
+ ParseFlag(env, &f->suppressions, "suppressions");
+ ParseFlag(env, &f->print_suppressions, "print_suppressions");
+ ParseFlag(env, &f->print_benign, "print_benign");
+ ParseFlag(env, &f->exitcode, "exitcode");
+ ParseFlag(env, &f->halt_on_error, "halt_on_error");
+ ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
+ ParseFlag(env, &f->profile_memory, "profile_memory");
+ ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
+ ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms");
+ ParseFlag(env, &f->memory_limit_mb, "memory_limit_mb");
+ ParseFlag(env, &f->stop_on_start, "stop_on_start");
+ ParseFlag(env, &f->running_on_valgrind, "running_on_valgrind");
+ ParseFlag(env, &f->history_size, "history_size");
+ ParseFlag(env, &f->io_sync, "io_sync");
+}
+
void InitializeFlags(Flags *f, const char *env) {
internal_memset(f, 0, sizeof(*f));
@@ -45,57 +75,35 @@ void InitializeFlags(Flags *f, const char *env) {
f->report_signal_unsafe = true;
f->report_atomic_races = true;
f->force_seq_cst_atomics = false;
- f->strip_path_prefix = "";
f->suppressions = "";
f->print_suppressions = false;
f->print_benign = false;
f->exitcode = 66;
f->halt_on_error = false;
- f->log_path = "stderr";
f->atexit_sleep_ms = 1000;
- f->verbosity = 0;
f->profile_memory = "";
f->flush_memory_ms = 0;
f->flush_symbolizer_ms = 5000;
+ f->memory_limit_mb = 0;
f->stop_on_start = false;
f->running_on_valgrind = false;
- f->external_symbolizer_path = "";
f->history_size = kGoMode ? 1 : 2; // There are a lot of goroutines in Go.
f->io_sync = 1;
- f->allocator_may_return_null = false;
+
+ SetCommonFlagsDefaults(f);
// Let a frontend override.
OverrideFlags(f);
-
+ ParseFlags(f, __tsan_default_options());
+ ParseCommonFlagsFromString(f, __tsan_default_options());
// Override from command line.
- ParseFlag(env, &f->enable_annotations, "enable_annotations");
- ParseFlag(env, &f->suppress_equal_stacks, "suppress_equal_stacks");
- ParseFlag(env, &f->suppress_equal_addresses, "suppress_equal_addresses");
- ParseFlag(env, &f->suppress_java, "suppress_java");
- ParseFlag(env, &f->report_bugs, "report_bugs");
- ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks");
- ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked");
- ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe");
- 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");
- ParseFlag(env, &f->print_suppressions, "print_suppressions");
- ParseFlag(env, &f->print_benign, "print_benign");
- ParseFlag(env, &f->exitcode, "exitcode");
- ParseFlag(env, &f->halt_on_error, "halt_on_error");
- ParseFlag(env, &f->log_path, "log_path");
- ParseFlag(env, &f->atexit_sleep_ms, "atexit_sleep_ms");
- ParseFlag(env, &f->verbosity, "verbosity");
- ParseFlag(env, &f->profile_memory, "profile_memory");
- ParseFlag(env, &f->flush_memory_ms, "flush_memory_ms");
- ParseFlag(env, &f->flush_symbolizer_ms, "flush_symbolizer_ms");
- ParseFlag(env, &f->stop_on_start, "stop_on_start");
- ParseFlag(env, &f->external_symbolizer_path, "external_symbolizer_path");
- ParseFlag(env, &f->history_size, "history_size");
- ParseFlag(env, &f->io_sync, "io_sync");
- ParseFlag(env, &f->allocator_may_return_null, "allocator_may_return_null");
+ ParseFlags(f, env);
+ ParseCommonFlagsFromString(f, env);
+
+ // Copy back to common flags.
+ *common_flags() = *f;
+ // Sanity check.
if (!f->report_bugs) {
f->report_thread_leaks = false;
f->report_destroy_locked = false;
@@ -113,8 +121,6 @@ void InitializeFlags(Flags *f, const char *env) {
" (must be [0..2])\n");
Die();
}
-
- common_flags()->allocator_may_return_null = f->allocator_may_return_null;
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_flags.h b/libsanitizer/tsan/tsan_flags.h
index a7571c92b5e..05d11a451c6 100644
--- a/libsanitizer/tsan/tsan_flags.h
+++ b/libsanitizer/tsan/tsan_flags.h
@@ -18,9 +18,11 @@
// header may be included in the user code, and shouldn't include
// other headers from TSan or common sanitizer runtime.
+#include "sanitizer_common/sanitizer_flags.h"
+
namespace __tsan {
-struct Flags {
+struct Flags : CommonFlags {
// Enable dynamic annotations, otherwise they are no-ops.
bool enable_annotations;
// Supress a race report if we've already output another race report
@@ -46,8 +48,6 @@ struct Flags {
// If set, all atomics are effectively sequentially consistent (seq_cst),
// regardless of what user actually specified.
bool force_seq_cst_atomics;
- // Strip that prefix from file paths in reports.
- const char *strip_path_prefix;
// Suppressions filename.
const char *suppressions;
// Print matched suppressions at exit.
@@ -58,27 +58,22 @@ struct Flags {
int exitcode;
// Exit after first reported error.
bool halt_on_error;
- // Write logs to "log_path.pid".
- // The special values are "stdout" and "stderr".
- // The default is "stderr".
- const char *log_path;
// Sleep in main thread before exiting for that many ms
// (useful to catch "at exit" races).
int atexit_sleep_ms;
- // Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).
- int verbosity;
// If set, periodically write memory profile to that file.
const char *profile_memory;
// Flush shadow memory every X ms.
int flush_memory_ms;
// Flush symbolizer caches every X ms.
int flush_symbolizer_ms;
+ // Resident memory limit in MB to aim at.
+ // If the process consumes more memory, then TSan will flush shadow memory.
+ int memory_limit_mb;
// Stops on start until __tsan_resume() is called (for debugging).
bool stop_on_start;
// Controls whether RunningOnValgrind() returns true or false.
bool running_on_valgrind;
- // Path to external symbolizer.
- const char *external_symbolizer_path;
// Per-thread history size, controls how many previous memory accesses
// are remembered per thread. Possible values are [0..7].
// history_size=0 amounts to 32K memory accesses. Each next value doubles
@@ -90,8 +85,6 @@ struct Flags {
// 1 - reasonable level of synchronization (write->read)
// 2 - global synchronization of all IO operations
int io_sync;
- // If false, the allocator will crash instead of returning 0 on out-of-memory.
- bool allocator_may_return_null;
};
Flags *flags();
diff --git a/libsanitizer/tsan/tsan_ignoreset.cc b/libsanitizer/tsan/tsan_ignoreset.cc
new file mode 100644
index 00000000000..f0aec42eb61
--- /dev/null
+++ b/libsanitizer/tsan/tsan_ignoreset.cc
@@ -0,0 +1,45 @@
+//===-- tsan_ignoreset.cc -------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_ignoreset.h"
+
+namespace __tsan {
+
+const uptr IgnoreSet::kMaxSize;
+
+IgnoreSet::IgnoreSet()
+ : size_() {
+}
+
+void IgnoreSet::Add(u32 stack_id) {
+ if (size_ == kMaxSize)
+ return;
+ for (uptr i = 0; i < size_; i++) {
+ if (stacks_[i] == stack_id)
+ return;
+ }
+ stacks_[size_++] = stack_id;
+}
+
+void IgnoreSet::Reset() {
+ size_ = 0;
+}
+
+uptr IgnoreSet::Size() const {
+ return size_;
+}
+
+u32 IgnoreSet::At(uptr i) const {
+ CHECK_LT(i, size_);
+ CHECK_LE(size_, kMaxSize);
+ return stacks_[i];
+}
+
+} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_ignoreset.h b/libsanitizer/tsan/tsan_ignoreset.h
new file mode 100644
index 00000000000..5a250b75af5
--- /dev/null
+++ b/libsanitizer/tsan/tsan_ignoreset.h
@@ -0,0 +1,36 @@
+//===-- tsan_ignoreset.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 ThreadSanitizer (TSan), a race detector.
+//
+// IgnoreSet holds a set of stack traces where ignores were enabled.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_IGNORESET_H
+#define TSAN_IGNORESET_H
+
+#include "tsan_defs.h"
+
+namespace __tsan {
+
+class IgnoreSet {
+ public:
+ static const uptr kMaxSize = 16;
+
+ IgnoreSet();
+ void Add(u32 stack_id);
+ void Reset();
+ uptr Size() const;
+ u32 At(uptr i) const;
+
+ private:
+ uptr size_;
+ u32 stacks_[kMaxSize];
+};
+
+} // namespace __tsan
+
+#endif // TSAN_IGNORESET_H
diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc
index eaaf9e3ebf6..0574beb91df 100644
--- a/libsanitizer/tsan/tsan_interceptors.cc
+++ b/libsanitizer/tsan/tsan_interceptors.cc
@@ -20,6 +20,7 @@
#include "interception/interception.h"
#include "tsan_interface.h"
#include "tsan_platform.h"
+#include "tsan_suppressions.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_fd.h"
@@ -40,9 +41,8 @@ struct ucontext_t {
extern "C" int pthread_attr_init(void *attr);
extern "C" int pthread_attr_destroy(void *attr);
-extern "C" int pthread_attr_getdetachstate(void *attr, int *v);
+DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
-extern "C" int pthread_attr_getstacksize(void *attr, uptr *stacksize);
extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
extern "C" int pthread_setspecific(unsigned key, const void *v);
extern "C" int pthread_mutexattr_gettype(void *a, int *type);
@@ -64,6 +64,7 @@ const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
const int EINVAL = 22;
const int EBUSY = 16;
+const int EOWNERDEAD = 130;
const int EPOLL_CTL_ADD = 1;
const int SIGILL = 4;
const int SIGABRT = 6;
@@ -124,18 +125,16 @@ struct SignalContext {
SignalDesc pending_signals[kSigCount];
};
-// Used to ignore interceptors coming directly from libjvm.so.
-atomic_uintptr_t libjvm_begin;
-atomic_uintptr_t libjvm_end;
+// The object is 64-byte aligned, because we want hot data to be located in
+// a single cache line if possible (it's accessed in every interceptor).
+static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+static LibIgnore *libignore() {
+ return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+}
-static bool libjvm_check(uptr pc) {
- uptr begin = atomic_load(&libjvm_begin, memory_order_relaxed);
- if (begin != 0 && pc >= begin) {
- uptr end = atomic_load(&libjvm_end, memory_order_relaxed);
- if (end != 0 && pc < end)
- return true;
- }
- return false;
+void InitializeLibIgnore() {
+ libignore()->Init(*GetSuppressionContext());
+ libignore()->OnLibraryLoaded(0);
}
} // namespace __tsan
@@ -159,13 +158,17 @@ class ScopedInterceptor {
~ScopedInterceptor();
private:
ThreadState *const thr_;
+ const uptr pc_;
const int in_rtl_;
+ bool in_ignored_lib_;
};
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
: thr_(thr)
- , in_rtl_(thr->in_rtl) {
+ , pc_(pc)
+ , in_rtl_(thr->in_rtl)
+ , in_ignored_lib_(false) {
if (thr_->in_rtl == 0) {
Initialize(thr);
FuncEntry(thr, pc);
@@ -174,9 +177,18 @@ ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
} else {
thr_->in_rtl++;
}
+ if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
+ in_ignored_lib_ = true;
+ thr_->in_ignored_lib = true;
+ ThreadIgnoreBegin(thr_, pc_);
+ }
}
ScopedInterceptor::~ScopedInterceptor() {
+ if (in_ignored_lib_) {
+ thr_->in_ignored_lib = false;
+ ThreadIgnoreEnd(thr_, pc_);
+ }
thr_->in_rtl--;
if (thr_->in_rtl == 0) {
FuncExit(thr_);
@@ -201,7 +213,7 @@ ScopedInterceptor::~ScopedInterceptor() {
Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
Die(); \
} \
- if (thr->in_rtl > 1 || libjvm_check(pc)) \
+ if (thr->in_rtl > 1 || thr->in_ignored_lib) \
return REAL(func)(__VA_ARGS__); \
/**/
@@ -244,6 +256,28 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
return res;
}
+TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
+ SCOPED_INTERCEPTOR_RAW(dlopen, filename, flag);
+ // dlopen will execute global constructors, so it must be not in rtl.
+ CHECK_EQ(thr->in_rtl, 1);
+ thr->in_rtl = 0;
+ void *res = REAL(dlopen)(filename, flag);
+ thr->in_rtl = 1;
+ libignore()->OnLibraryLoaded(filename);
+ return res;
+}
+
+TSAN_INTERCEPTOR(int, dlclose, void *handle) {
+ SCOPED_INTERCEPTOR_RAW(dlclose, handle);
+ // dlclose will execute global destructors, so it must be not in rtl.
+ CHECK_EQ(thr->in_rtl, 1);
+ thr->in_rtl = 0;
+ int res = REAL(dlclose)(handle);
+ thr->in_rtl = 1;
+ libignore()->OnLibraryUnloaded();
+ return res;
+}
+
class AtExitContext {
public:
AtExitContext()
@@ -326,9 +360,9 @@ TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
if (dso) {
// Memory allocation in __cxa_atexit will race with free during exit,
// because we do not see synchronization around atexit callback list.
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
int res = REAL(__cxa_atexit)(f, arg, dso);
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
return res;
}
return atexit_ctx->atexit(thr, pc, false, (void(*)())f, arg);
@@ -439,7 +473,7 @@ TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) {
}
TSAN_INTERCEPTOR(void*, malloc, uptr size) {
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+ if (cur_thread()->in_symbolizer)
return __libc_malloc(size);
void *p = 0;
{
@@ -456,7 +490,7 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
}
TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+ if (cur_thread()->in_symbolizer)
return __libc_calloc(size, n);
if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n))
return AllocatorReturnNull();
@@ -472,7 +506,7 @@ TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
}
TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+ if (cur_thread()->in_symbolizer)
return __libc_realloc(p, size);
if (p)
invoke_free_hook(p);
@@ -487,7 +521,7 @@ TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
TSAN_INTERCEPTOR(void, free, void *p) {
if (p == 0)
return;
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+ if (cur_thread()->in_symbolizer)
return __libc_free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(free, p);
@@ -497,7 +531,7 @@ TSAN_INTERCEPTOR(void, free, void *p) {
TSAN_INTERCEPTOR(void, cfree, void *p) {
if (p == 0)
return;
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC()))
+ if (cur_thread()->in_symbolizer)
return __libc_free(p);
invoke_free_hook(p);
SCOPED_INTERCEPTOR_RAW(cfree, p);
@@ -506,13 +540,11 @@ TSAN_INTERCEPTOR(void, cfree, void *p) {
TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
- if (libjvm_check(pc))
- return malloc_usable_size(p);
return user_alloc_usable_size(thr, pc, p);
}
#define OPERATOR_NEW_BODY(mangled_name) \
- if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \
+ if (cur_thread()->in_symbolizer) \
return __libc_malloc(size); \
void *p = 0; \
{ \
@@ -548,7 +580,7 @@ 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 || libjvm_check(GET_CALLER_PC())) \
+ if (cur_thread()->in_symbolizer) \
return __libc_free(ptr); \
invoke_free_hook(ptr); \
SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \
@@ -682,15 +714,6 @@ TSAN_INTERCEPTOR(const char*, strstr, const char *s1, const char *s2) {
TSAN_INTERCEPTOR(char*, strdup, const char *str) {
SCOPED_TSAN_INTERCEPTOR(strdup, str);
- if (libjvm_check(pc)) {
- // The memory must come from libc malloc,
- // and we must not instrument accesses in this case.
- uptr n = internal_strlen(str) + 1;
- void *p = __libc_malloc(n);
- if (p == 0)
- return 0;
- return (char*)internal_memcpy(p, str, n);
- }
// strdup will call malloc, so no instrumentation is required here.
return REAL(strdup)(str);
}
@@ -745,23 +768,23 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
}
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(memalign, align, sz);
+ SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
return user_alloc(thr, pc, sz, align);
}
TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(valloc, sz);
+ SCOPED_INTERCEPTOR_RAW(valloc, sz);
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(pvalloc, sz);
+ SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
sz = RoundUp(sz, GetPageSizeCached());
return user_alloc(thr, pc, sz, GetPageSizeCached());
}
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
- SCOPED_TSAN_INTERCEPTOR(posix_memalign, memptr, align, sz);
+ SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
*memptr = user_alloc(thr, pc, sz, align);
return 0;
}
@@ -830,7 +853,8 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
{
ThreadState *thr = cur_thread();
ScopedInRtl in_rtl;
- if (pthread_setspecific(g_thread_finalize_key, (void*)4)) {
+ if (pthread_setspecific(g_thread_finalize_key,
+ (void *)kPthreadDestructorIterations)) {
Printf("ThreadSanitizer: failed to set thread key\n");
Die();
}
@@ -850,21 +874,15 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
TSAN_INTERCEPTOR(int, pthread_create,
void *th, void *attr, void *(*callback)(void*), void * param) {
- SCOPED_TSAN_INTERCEPTOR(pthread_create, th, attr, callback, param);
+ SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
__sanitizer_pthread_attr_t myattr;
if (attr == 0) {
pthread_attr_init(&myattr);
attr = &myattr;
}
int detached = 0;
- pthread_attr_getdetachstate(attr, &detached);
-
-#if defined(TSAN_DEBUG_OUTPUT)
- int verbosity = (TSAN_DEBUG_OUTPUT);
-#else
- int verbosity = 0;
-#endif
- AdjustStackSizeLinux(attr, verbosity);
+ REAL(pthread_attr_getdetachstate)(attr, &detached);
+ AdjustStackSizeLinux(attr);
ThreadParam p;
p.callback = callback;
@@ -884,7 +902,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
}
TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
- SCOPED_TSAN_INTERCEPTOR(pthread_join, th, ret);
+ SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
int tid = ThreadTid(thr, pc, (uptr)th);
int res = BLOCK_REAL(pthread_join)(th, ret);
if (res == 0) {
@@ -928,21 +946,13 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_mutex_lock, m);
- int res = REAL(pthread_mutex_lock)(m);
- if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
- }
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
int res = REAL(pthread_mutex_trylock)(m);
- if (res == 0) {
+ if (res == EOWNERDEAD)
+ MutexRepair(thr, pc, (uptr)m);
+ if (res == 0 || res == EOWNERDEAD)
MutexLock(thr, pc, (uptr)m);
- }
return res;
}
@@ -955,13 +965,6 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_mutex_unlock, m);
- MutexUnlock(thr, pc, (uptr)m);
- int res = REAL(pthread_mutex_unlock)(m);
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
int res = REAL(pthread_spin_init)(m, pshared);
@@ -1084,13 +1087,6 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, c, a);
- MemoryWrite(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_init)(c, a);
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) {
SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, c);
MemoryWrite(thr, pc, (uptr)c, kSizeLog1);
@@ -1098,29 +1094,6 @@ TSAN_INTERCEPTOR(int, pthread_cond_destroy, void *c) {
return res;
}
-TSAN_INTERCEPTOR(int, pthread_cond_signal, void *c) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, c);
- MemoryRead(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_signal)(c);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, c);
- MemoryRead(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_broadcast)(c);
- return res;
-}
-
-TSAN_INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
- SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, c, m);
- MutexUnlock(thr, pc, (uptr)m);
- MemoryRead(thr, pc, (uptr)c, kSizeLog1);
- int res = REAL(pthread_cond_wait)(c, m);
- MutexLock(thr, pc, (uptr)m);
- return res;
-}
-
TSAN_INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m,
void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, c, m, abstime);
@@ -1158,7 +1131,9 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
}
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
- SCOPED_TSAN_INTERCEPTOR(pthread_once, o, f);
+ SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
+ // Using SCOPED_INTERCEPTOR_RAW, because if we are called from an ignored lib,
+ // the user callback must be executed with thr->in_rtl == 0.
if (o == 0 || f == 0)
return EINVAL;
atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
@@ -1170,14 +1145,16 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
(*f)();
CHECK_EQ(thr->in_rtl, 0);
thr->in_rtl = old_in_rtl;
- Release(thr, pc, (uptr)o);
+ if (!thr->in_ignored_lib)
+ Release(thr, pc, (uptr)o);
atomic_store(a, 2, memory_order_release);
} else {
while (v != 2) {
pthread_yield();
v = atomic_load(a, memory_order_acquire);
}
- Acquire(thr, pc, (uptr)o);
+ if (!thr->in_ignored_lib)
+ Acquire(thr, pc, (uptr)o);
}
return 0;
}
@@ -1496,22 +1473,28 @@ TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
TSAN_INTERCEPTOR(long_t, send, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(send, fd, buf, len, flags);
- if (fd >= 0)
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
FdRelease(thr, pc, fd);
+ }
int res = REAL(send)(fd, buf, len, flags);
return res;
}
TSAN_INTERCEPTOR(long_t, sendmsg, int fd, void *msg, int flags) {
SCOPED_TSAN_INTERCEPTOR(sendmsg, fd, msg, flags);
- if (fd >= 0)
+ if (fd >= 0) {
+ FdAccess(thr, pc, fd);
FdRelease(thr, pc, fd);
+ }
int res = REAL(sendmsg)(fd, msg, flags);
return res;
}
TSAN_INTERCEPTOR(long_t, recv, int fd, void *buf, long_t len, int flags) {
SCOPED_TSAN_INTERCEPTOR(recv, fd, buf, len, flags);
+ if (fd >= 0)
+ FdAccess(thr, pc, fd);
int res = REAL(recv)(fd, buf, len, flags);
if (res >= 0 && fd >= 0) {
FdAcquire(thr, pc, fd);
@@ -1556,6 +1539,7 @@ TSAN_INTERCEPTOR(void*, freopen, char *path, char *mode, void *stream) {
}
TSAN_INTERCEPTOR(int, fclose, void *stream) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fclose, stream);
if (stream) {
@@ -1568,6 +1552,7 @@ TSAN_INTERCEPTOR(int, fclose, void *stream) {
}
TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f);
MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true);
@@ -1576,6 +1561,7 @@ TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
}
TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
+ // libc file streams can call user-supplied functions, see fopencookie.
{
SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f);
MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false);
@@ -1584,7 +1570,10 @@ TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
}
TSAN_INTERCEPTOR(int, fflush, void *stream) {
- SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+ // libc file streams can call user-supplied functions, see fopencookie.
+ {
+ SCOPED_TSAN_INTERCEPTOR(fflush, stream);
+ }
return REAL(fflush)(stream);
}
@@ -1617,21 +1606,23 @@ TSAN_INTERCEPTOR(void*, opendir, char *path) {
TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
- if (op == EPOLL_CTL_ADD && epfd >= 0) {
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
+ if (epfd >= 0 && fd >= 0)
+ FdAccess(thr, pc, fd);
+ if (op == EPOLL_CTL_ADD && epfd >= 0)
FdRelease(thr, pc, epfd);
- }
int res = REAL(epoll_ctl)(epfd, op, fd, ev);
- if (fd >= 0)
- FdAccess(thr, pc, fd);
return res;
}
TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
+ if (epfd >= 0)
+ FdAccess(thr, pc, epfd);
int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout);
- if (res > 0 && epfd >= 0) {
+ if (res > 0 && epfd >= 0)
FdAcquire(thr, pc, epfd);
- }
return res;
}
@@ -1777,13 +1768,13 @@ TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
// We miss atomic synchronization in getaddrinfo,
// and can report false race between malloc and free
// inside of getaddrinfo. So ignore memory accesses.
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
// getaddrinfo calls fopen, which can be intercepted by user.
thr->in_rtl--;
CHECK_EQ(thr->in_rtl, 0);
int res = REAL(getaddrinfo)(node, service, hints, rv);
thr->in_rtl++;
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
return res;
}
@@ -1818,7 +1809,7 @@ TSAN_INTERCEPTOR(int, munlockall, void) {
}
TSAN_INTERCEPTOR(int, fork, int fake) {
- SCOPED_TSAN_INTERCEPTOR(fork, fake);
+ SCOPED_INTERCEPTOR_RAW(fork, fake);
int pid = REAL(fork)(fake);
if (pid == 0) {
// child
@@ -1829,12 +1820,26 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
return pid;
}
+static int OnExit(ThreadState *thr) {
+ int status = Finalize(thr);
+ REAL(fflush)(0);
+ return status;
+}
+
struct TsanInterceptorContext {
ThreadState *thr;
const uptr caller_pc;
const uptr pc;
};
+static void HandleRecvmsg(ThreadState *thr, uptr pc,
+ __sanitizer_msghdr *msg) {
+ int fds[64];
+ int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds));
+ for (int i = 0; i < cnt; i++)
+ FdEventCreate(thr, pc, fds[i]);
+}
+
#include "sanitizer_common/sanitizer_platform_interceptors.h"
// Causes interceptor recursion (getpwuid_r() calls fopen())
#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
@@ -1845,31 +1850,66 @@ struct TsanInterceptorContext {
// Causes interceptor recursion (glob64() calls lstat64())
#undef SANITIZER_INTERCEPT_GLOB
+#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
do { \
} while (false)
+
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
MemoryAccessRange(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)ptr, size, \
true)
+
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
MemoryAccessRange(((TsanInterceptorContext *) ctx)->thr, \
((TsanInterceptorContext *) ctx)->pc, (uptr) ptr, size, \
false)
+
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
SCOPED_TSAN_INTERCEPTOR(func, __VA_ARGS__); \
TsanInterceptorContext _ctx = {thr, caller_pc, pc}; \
ctx = (void *)&_ctx; \
(void) ctx;
+
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
+#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \
+ FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd)
+
#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd)
+
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
+
+#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
+ CTX()->thread_registry->SetThreadNameByUserId(thread, name)
+
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
+
+#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
+ OnExit(((TsanInterceptorContext *) ctx)->thr)
+
+#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \
+ MutexLock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \
+ MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \
+ MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
+ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, msg)
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define TSAN_SYSCALL() \
@@ -1899,10 +1939,33 @@ static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
MemoryAccessRange(thr, pc, p, s, write);
}
+static void syscall_acquire(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ Acquire(thr, pc, addr);
+ Printf("syscall_acquire(%p)\n", addr);
+}
+
+static void syscall_release(uptr pc, uptr addr) {
+ TSAN_SYSCALL();
+ Printf("syscall_release(%p)\n", addr);
+ Release(thr, pc, addr);
+}
+
static void syscall_fd_close(uptr pc, int fd) {
TSAN_SYSCALL();
- if (fd >= 0)
- FdClose(thr, pc, fd);
+ FdClose(thr, pc, fd);
+}
+
+static USED void syscall_fd_acquire(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ FdAcquire(thr, pc, fd);
+ Printf("syscall_fd_acquire(%p)\n", fd);
+}
+
+static USED void syscall_fd_release(uptr pc, int fd) {
+ TSAN_SYSCALL();
+ Printf("syscall_fd_release(%p)\n", fd);
+ FdRelease(thr, pc, fd);
}
static void syscall_pre_fork(uptr pc) {
@@ -1921,22 +1984,54 @@ static void syscall_post_fork(uptr pc, int res) {
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
+
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
+
#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
- do { } while (false)
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
- do { } while (false)
-#define COMMON_SYSCALL_FD_CLOSE(fd) \
- syscall_fd_close(GET_CALLER_PC(), fd)
+ do { \
+ (void)(p); \
+ (void)(s); \
+ } while (false)
+
+#define COMMON_SYSCALL_ACQUIRE(addr) \
+ syscall_acquire(GET_CALLER_PC(), (uptr)(addr))
+
+#define COMMON_SYSCALL_RELEASE(addr) \
+ syscall_release(GET_CALLER_PC(), (uptr)(addr))
+
+#define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd)
+
+#define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd)
+
#define COMMON_SYSCALL_PRE_FORK() \
syscall_pre_fork(GET_CALLER_PC())
+
#define COMMON_SYSCALL_POST_FORK(res) \
syscall_post_fork(GET_CALLER_PC(), res)
+
#include "sanitizer_common/sanitizer_common_syscalls.inc"
namespace __tsan {
+static void finalize(void *arg) {
+ ThreadState *thr = cur_thread();
+ uptr pc = 0;
+ atexit_ctx->exit(thr, pc);
+ int status = Finalize(thr);
+ REAL(fflush)(0);
+ if (status)
+ REAL(_exit)(status);
+}
+
void ProcessPendingSignals(ThreadState *thr) {
CHECK_EQ(thr->in_rtl, 0);
SignalContext *sctx = SigCtx(thr);
@@ -1986,16 +2081,6 @@ void ProcessPendingSignals(ThreadState *thr) {
thr->in_signal_handler = false;
}
-static void finalize(void *arg) {
- ThreadState * thr = cur_thread();
- uptr pc = 0;
- atexit_ctx->exit(thr, pc);
- int status = Finalize(cur_thread());
- REAL(fflush)(0);
- if (status)
- _exit(status);
-}
-
static void unreachable() {
Printf("FATAL: ThreadSanitizer: unreachable called\n");
Die();
@@ -2015,10 +2100,14 @@ void InitializeInterceptors() {
SANITIZER_COMMON_INTERCEPTORS_INIT;
- TSAN_INTERCEPT(setjmp);
- TSAN_INTERCEPT(_setjmp);
- TSAN_INTERCEPT(sigsetjmp);
- TSAN_INTERCEPT(__sigsetjmp);
+ // We can not use TSAN_INTERCEPT to get setjmp addr,
+ // because it does &setjmp and setjmp is not present in some versions of libc.
+ using __interception::GetRealFunctionAddress;
+ GetRealFunctionAddress("setjmp", (uptr*)&REAL(setjmp), 0, 0);
+ GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
+ GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0);
+ GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
+
TSAN_INTERCEPT(longjmp);
TSAN_INTERCEPT(siglongjmp);
@@ -2057,10 +2146,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_mutex_init);
TSAN_INTERCEPT(pthread_mutex_destroy);
- TSAN_INTERCEPT(pthread_mutex_lock);
TSAN_INTERCEPT(pthread_mutex_trylock);
TSAN_INTERCEPT(pthread_mutex_timedlock);
- TSAN_INTERCEPT(pthread_mutex_unlock);
TSAN_INTERCEPT(pthread_spin_init);
TSAN_INTERCEPT(pthread_spin_destroy);
@@ -2078,12 +2165,8 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
TSAN_INTERCEPT(pthread_rwlock_unlock);
- INTERCEPT_FUNCTION_VER(pthread_cond_init, GLIBC_2.3.2);
- INTERCEPT_FUNCTION_VER(pthread_cond_destroy, GLIBC_2.3.2);
- INTERCEPT_FUNCTION_VER(pthread_cond_signal, GLIBC_2.3.2);
- INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, GLIBC_2.3.2);
- INTERCEPT_FUNCTION_VER(pthread_cond_wait, GLIBC_2.3.2);
- INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, GLIBC_2.3.2);
+ INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
+ INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
TSAN_INTERCEPT(pthread_barrier_init);
TSAN_INTERCEPT(pthread_barrier_destroy);
@@ -2172,8 +2255,11 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(munlockall);
TSAN_INTERCEPT(fork);
+ TSAN_INTERCEPT(dlopen);
+ TSAN_INTERCEPT(dlclose);
TSAN_INTERCEPT(on_exit);
TSAN_INTERCEPT(__cxa_atexit);
+ TSAN_INTERCEPT(_exit);
// 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.
@@ -2195,9 +2281,15 @@ void InitializeInterceptors() {
}
void internal_start_thread(void(*func)(void *arg), void *arg) {
+ // Start the thread with signals blocked, otherwise it can steal users
+ // signals.
+ __sanitizer_kernel_sigset_t set, old;
+ internal_sigfillset(&set);
+ internal_sigprocmask(SIG_SETMASK, &set, &old);
void *th;
REAL(pthread_create)(&th, 0, (void*(*)(void *arg))func, arg);
REAL(pthread_detach)(th);
+ internal_sigprocmask(SIG_SETMASK, &old, 0);
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_interface_ann.cc b/libsanitizer/tsan/tsan_interface_ann.cc
index 46d9e3ec1af..38224f429cd 100644
--- a/libsanitizer/tsan/tsan_interface_ann.cc
+++ b/libsanitizer/tsan/tsan_interface_ann.cc
@@ -53,11 +53,11 @@ class ScopedAnnotation {
if (!flags()->enable_annotations) \
return; \
ThreadState *thr = cur_thread(); \
- const uptr pc = (uptr)__builtin_return_address(0); \
+ const uptr caller_pc = (uptr)__builtin_return_address(0); \
StatInc(thr, StatAnnotation); \
StatInc(thr, Stat##typ); \
- ScopedAnnotation sa(thr, __FUNCTION__, f, l, \
- (uptr)__builtin_return_address(0)); \
+ ScopedAnnotation sa(thr, __FUNCTION__, f, l, caller_pc); \
+ const uptr pc = __sanitizer::StackTrace::GetCurrentPc(); \
(void)pc; \
/**/
@@ -381,22 +381,32 @@ void INTERFACE_ATTRIBUTE AnnotateBenignRace(
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
- ThreadIgnoreBegin(thr);
+ ThreadIgnoreBegin(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
- ThreadIgnoreEnd(thr);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
+ ThreadIgnoreSyncBegin(thr, pc);
+}
+
+void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
+ SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
+ ThreadIgnoreSyncEnd(thr, pc);
}
void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
@@ -429,7 +439,7 @@ void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
char *f, int l, uptr mem, uptr sz, char *desc) {
SCOPED_ANNOTATION(AnnotateBenignRaceSized);
- BenignRaceImpl(f, l, mem, 1, desc);
+ BenignRaceImpl(f, l, mem, sz, desc);
}
int INTERFACE_ATTRIBUTE RunningOnValgrind() {
diff --git a/libsanitizer/tsan/tsan_interface_atomic.cc b/libsanitizer/tsan/tsan_interface_atomic.cc
index 02ebb47e6af..180d87b7993 100644
--- a/libsanitizer/tsan/tsan_interface_atomic.cc
+++ b/libsanitizer/tsan/tsan_interface_atomic.cc
@@ -249,11 +249,10 @@ static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
// Assume the access is atomic.
if (!IsAcquireOrder(mo) && sizeof(T) <= sizeof(a)) {
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
- return *a;
+ return *a; // as if atomic
}
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, false);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
T v = *a;
s->mtx.ReadUnlock();
__sync_synchronize();
@@ -271,13 +270,15 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
// Strictly saying even relaxed store cuts off release sequence,
// so must reset the clock.
if (!IsReleaseOrder(mo) && sizeof(T) <= sizeof(a)) {
- *a = v;
+ *a = v; // as if atomic
return;
}
__sync_synchronize();
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.ReleaseStore(&s->clock);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(thr, pc, &s->clock);
*a = v;
s->mtx.Unlock();
// Trainling memory barrier to provide sequential consistency
@@ -291,13 +292,15 @@ static T AtomicRMW(ThreadState *thr, uptr pc, volatile T *a, T v, morder mo) {
SyncVar *s = 0;
if (mo != mo_relaxed) {
s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
if (IsAcqRelOrder(mo))
- thr->clock.acq_rel(&s->clock);
+ AcquireReleaseImpl(thr, pc, &s->clock);
else if (IsReleaseOrder(mo))
- thr->clock.release(&s->clock);
+ ReleaseImpl(thr, pc, &s->clock);
else if (IsAcquireOrder(mo))
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
}
v = F(a, v);
if (s)
@@ -355,13 +358,15 @@ static bool AtomicCAS(ThreadState *thr, uptr pc,
SyncVar *s = 0;
if (mo != mo_relaxed) {
s = CTX()->synctab.GetOrCreateAndLock(thr, pc, (uptr)a, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
if (IsAcqRelOrder(mo))
- thr->clock.acq_rel(&s->clock);
+ AcquireReleaseImpl(thr, pc, &s->clock);
else if (IsReleaseOrder(mo))
- thr->clock.release(&s->clock);
+ ReleaseImpl(thr, pc, &s->clock);
else if (IsAcquireOrder(mo))
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
}
T cc = *c;
T pr = func_cas(a, cc, v);
diff --git a/libsanitizer/tsan/tsan_interface_java.cc b/libsanitizer/tsan/tsan_interface_java.cc
index 7cc72577977..70b5e5fcc65 100644
--- a/libsanitizer/tsan/tsan_interface_java.cc
+++ b/libsanitizer/tsan/tsan_interface_java.cc
@@ -94,8 +94,6 @@ class ScopedJavaFunc {
static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1];
static JavaContext *jctx;
-extern atomic_uintptr_t libjvm_begin;
-extern atomic_uintptr_t libjvm_end;
static BlockDesc *getblock(uptr addr) {
uptr i = (addr - jctx->heap_begin) / kHeapAlignment;
@@ -164,17 +162,6 @@ SyncVar* GetAndRemoveJavaSync(ThreadState *thr, uptr pc, uptr addr) {
ScopedJavaFunc scoped(thr, caller_pc); \
/**/
-void __tsan_java_preinit(const char *libjvm_path) {
- SCOPED_JAVA_FUNC(__tsan_java_preinit);
- if (libjvm_path) {
- uptr begin, end;
- if (GetCodeRangeForFile(libjvm_path, &begin, &end)) {
- atomic_store(&libjvm_begin, begin, memory_order_relaxed);
- atomic_store(&libjvm_end, end, memory_order_relaxed);
- }
- }
-}
-
void __tsan_java_init(jptr heap_begin, jptr heap_size) {
SCOPED_JAVA_FUNC(__tsan_java_init);
DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size);
diff --git a/libsanitizer/tsan/tsan_interface_java.h b/libsanitizer/tsan/tsan_interface_java.h
index 818c07b97d4..885ff289751 100644
--- a/libsanitizer/tsan/tsan_interface_java.h
+++ b/libsanitizer/tsan/tsan_interface_java.h
@@ -32,11 +32,7 @@ extern "C" {
typedef unsigned long jptr; // NOLINT
-// Must be called before any other callback from Java, right after dlopen
-// of JVM shared lib. If libjvm_path is specified, then all interceptors
-// coming directly from JVM will be ignored.
-void __tsan_java_preinit(const char *libjvm_path) INTERFACE_ATTRIBUTE;
-// Must be called after __tsan_java_preinit but before any other callback.
+// Must be called before any other callback from Java.
void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE;
// Must be called when the application exits.
// Not necessary the last callback (concurrently running threads are OK).
diff --git a/libsanitizer/tsan/tsan_mutexset.h b/libsanitizer/tsan/tsan_mutexset.h
index ef60bd47db2..df36b462c60 100644
--- a/libsanitizer/tsan/tsan_mutexset.h
+++ b/libsanitizer/tsan/tsan_mutexset.h
@@ -60,4 +60,4 @@ MutexSet::Desc MutexSet::Get(uptr i) const { return Desc(); }
} // namespace __tsan
-#endif // TSAN_REPORT_H
+#endif // TSAN_MUTEXSET_H
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index ac36c5ab67a..164ee45d6c6 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -132,17 +132,24 @@ static inline uptr AlternativeAddress(uptr addr) {
void FlushShadowMemory();
void WriteMemoryProfile(char *buf, uptr buf_size);
+uptr GetRSS();
const char *InitializePlatform();
void FinalizePlatform();
+
+// The additional page is to catch shadow stack overflow as paging fault.
+const uptr kTotalTraceSize = (kTraceSize * sizeof(Event) + sizeof(Trace) + 4096
+ + 4095) & ~4095;
+
uptr ALWAYS_INLINE GetThreadTrace(int tid) {
- uptr p = kTraceMemBegin + (uptr)(tid * 2) * kTraceSize * sizeof(Event);
+ uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize;
DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
return p;
}
uptr ALWAYS_INLINE GetThreadTraceHeader(int tid) {
- uptr p = kTraceMemBegin + (uptr)(tid * 2 + 1) * kTraceSize * sizeof(Event);
+ uptr p = kTraceMemBegin + (uptr)tid * kTotalTraceSize
+ + kTraceSize * sizeof(Event);
DCHECK_LT(p, kTraceMemBegin + kTraceMemSize);
return p;
}
@@ -153,6 +160,7 @@ void internal_start_thread(void(*func)(void*), void *arg);
// Guesses with high probability, may yield both false positives and negatives.
bool IsGlobalVar(uptr addr);
int ExtractResolvFDs(void *state, int *fds, int nfd);
+int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc
index f13e3c893b3..fe69430b711 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cc
+++ b/libsanitizer/tsan/tsan_platform_linux.cc
@@ -17,6 +17,7 @@
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
@@ -31,6 +32,7 @@
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
+#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -43,6 +45,14 @@
#include <resolv.h>
#include <malloc.h>
+#ifdef sa_handler
+# undef sa_handler
+#endif
+
+#ifdef sa_sigaction
+# undef sa_sigaction
+#endif
+
extern "C" struct mallinfo __libc_mallinfo();
namespace __tsan {
@@ -104,10 +114,23 @@ void WriteMemoryProfile(char *buf, uptr buf_size) {
mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
}
-void FlushShadowMemory() {
+uptr GetRSS() {
+ uptr mem[7] = {};
+ __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
+ return mem[6];
+}
+
+
+void FlushShadowMemoryCallback(
+ const SuspendedThreadsList &suspended_threads_list,
+ void *argument) {
FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
}
+void FlushShadowMemory() {
+ StopTheWorld(FlushShadowMemoryCallback, 0);
+}
+
#ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) {
ScopedInRtl in_rtl;
@@ -323,6 +346,9 @@ bool IsGlobalVar(uptr addr) {
}
#ifndef TSAN_GO
+// Extract file descriptors passed to glibc internal __res_iclose function.
+// This is required to properly "close" the fds, because we do not see internal
+// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
int cnt = 0;
__res_state *statp = (__res_state*)state;
@@ -332,6 +358,26 @@ int ExtractResolvFDs(void *state, int *fds, int nfd) {
}
return cnt;
}
+
+// Extract file descriptors passed via UNIX domain sockets.
+// This is requried to properly handle "open" of these fds.
+// see 'man recvmsg' and 'man 3 cmsg'.
+int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
+ int res = 0;
+ msghdr *msg = (msghdr*)msgp;
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+ for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
+ continue;
+ int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
+ for (int i = 0; i < n; i++) {
+ fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
+ if (res == nfd)
+ return res;
+ }
+ }
+ return res;
+}
#endif
diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc
index 15ab22b4ba7..f2484166e81 100644
--- a/libsanitizer/tsan/tsan_report.cc
+++ b/libsanitizer/tsan/tsan_report.cc
@@ -132,7 +132,7 @@ static void PrintLocation(const ReportLocation *loc) {
bool print_stack = false;
Printf("%s", d.Location());
if (loc->type == ReportLocationGlobal) {
- Printf(" Location is global '%s' of size %zu at %zx (%s+%p)\n\n",
+ Printf(" Location is global '%s' of size %zu at %p (%s+%p)\n\n",
loc->name, loc->size, loc->addr, loc->module, loc->offset);
} else if (loc->type == ReportLocationHeap) {
char thrbuf[kThreadBufSize];
diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc
index 7f18064e957..a0f32673fbb 100644
--- a/libsanitizer/tsan/tsan_rtl.cc
+++ b/libsanitizer/tsan/tsan_rtl.cc
@@ -37,9 +37,13 @@ THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
// Can be overriden by a front-end.
-bool CPP_WEAK OnFinalize(bool failed) {
+#ifdef TSAN_EXTERNAL_HOOKS
+bool OnFinalize(bool failed);
+#else
+bool WEAK OnFinalize(bool failed) {
return failed;
}
+#endif
static Context *ctx;
Context *CTX() {
@@ -84,7 +88,6 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
// they may be accessed before the ctor.
// , ignore_reads_and_writes()
// , in_rtl()
- , shadow_stack_pos(&shadow_stack[0])
#ifndef TSAN_GO
, jmp_bufs(MBlockJmpBuf)
#endif
@@ -128,17 +131,38 @@ static void BackgroundThread(void *arg) {
}
u64 last_flush = NanoTime();
+ uptr last_rss = 0;
for (int i = 0; ; i++) {
SleepForSeconds(1);
u64 now = NanoTime();
// Flush memory if requested.
- if (flags()->flush_memory_ms) {
+ if (flags()->flush_memory_ms > 0) {
if (last_flush + flags()->flush_memory_ms * kMs2Ns < now) {
+ if (flags()->verbosity > 0)
+ Printf("ThreadSanitizer: periodic memory flush\n");
FlushShadowMemory();
last_flush = NanoTime();
}
}
+ if (flags()->memory_limit_mb > 0) {
+ uptr rss = GetRSS();
+ uptr limit = uptr(flags()->memory_limit_mb) << 20;
+ if (flags()->verbosity > 0) {
+ Printf("ThreadSanitizer: memory flush check"
+ " RSS=%llu LAST=%llu LIMIT=%llu\n",
+ (u64)rss>>20, (u64)last_rss>>20, (u64)limit>>20);
+ }
+ if (2 * rss > limit + last_rss) {
+ if (flags()->verbosity > 0)
+ Printf("ThreadSanitizer: flushing memory due to RSS\n");
+ FlushShadowMemory();
+ rss = GetRSS();
+ if (flags()->verbosity > 0)
+ Printf("ThreadSanitizer: memory flushed RSS=%llu\n", (u64)rss>>20);
+ }
+ last_rss = rss;
+ }
// Write memory profile if requested.
if (mprof_fd != kInvalidFd)
@@ -174,8 +198,10 @@ void MapThreadTrace(uptr addr, uptr size) {
DPrintf("#0: Mapping trace at %p-%p(0x%zx)\n", addr, addr + size, size);
CHECK_GE(addr, kTraceMemBegin);
CHECK_LE(addr + size, kTraceMemBegin + kTraceMemSize);
- if (addr != (uptr)MmapFixedNoReserve(addr, size)) {
- Printf("FATAL: ThreadSanitizer can not mmap thread trace\n");
+ uptr addr1 = (uptr)MmapFixedNoReserve(addr, size);
+ if (addr1 != addr) {
+ Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n",
+ addr, size, addr1);
Die();
}
}
@@ -204,23 +230,21 @@ void Initialize(ThreadState *thr) {
#endif
InitializeFlags(&ctx->flags, env);
// Setup correct file descriptor for error reports.
- if (internal_strcmp(flags()->log_path, "stdout") == 0)
- __sanitizer_set_report_fd(kStdoutFd);
- else if (internal_strcmp(flags()->log_path, "stderr") == 0)
- __sanitizer_set_report_fd(kStderrFd);
- else
- __sanitizer_set_report_path(flags()->log_path);
+ __sanitizer_set_report_path(flags()->log_path);
InitializeSuppressions();
#ifndef TSAN_GO
+ InitializeLibIgnore();
// Initialize external symbolizer before internal threads are started.
const char *external_symbolizer = flags()->external_symbolizer_path;
- if (external_symbolizer != 0 && external_symbolizer[0] != '\0') {
- if (!getSymbolizer()->InitializeExternal(external_symbolizer)) {
- Printf("Failed to start external symbolizer: '%s'\n",
- external_symbolizer);
- Die();
- }
+ bool external_symbolizer_started =
+ Symbolizer::Init(external_symbolizer)->IsExternalAvailable();
+ if (external_symbolizer != 0 && external_symbolizer[0] != '\0' &&
+ !external_symbolizer_started) {
+ Printf("Failed to start external symbolizer: '%s'\n",
+ external_symbolizer);
+ Die();
}
+ Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
#endif
internal_start_thread(&BackgroundThread, 0);
@@ -636,9 +660,9 @@ void FuncEntry(ThreadState *thr, uptr pc) {
// Shadow stack maintenance can be replaced with
// stack unwinding during trace switch (which presumably must be faster).
- DCHECK_GE(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+ DCHECK_GE(thr->shadow_stack_pos, thr->shadow_stack);
#ifndef TSAN_GO
- DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#else
if (thr->shadow_stack_pos == thr->shadow_stack_end) {
const int sz = thr->shadow_stack_end - thr->shadow_stack;
@@ -664,26 +688,52 @@ void FuncExit(ThreadState *thr) {
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeFuncExit, 0);
- DCHECK_GT(thr->shadow_stack_pos, &thr->shadow_stack[0]);
+ DCHECK_GT(thr->shadow_stack_pos, thr->shadow_stack);
#ifndef TSAN_GO
- DCHECK_LT(thr->shadow_stack_pos, &thr->shadow_stack[kShadowStackSize]);
+ DCHECK_LT(thr->shadow_stack_pos, thr->shadow_stack_end);
#endif
thr->shadow_stack_pos--;
}
-void ThreadIgnoreBegin(ThreadState *thr) {
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
thr->ignore_reads_and_writes++;
- CHECK_GE(thr->ignore_reads_and_writes, 0);
+ CHECK_GT(thr->ignore_reads_and_writes, 0);
thr->fast_state.SetIgnoreBit();
+#ifndef TSAN_GO
+ thr->mop_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
}
-void ThreadIgnoreEnd(ThreadState *thr) {
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid);
thr->ignore_reads_and_writes--;
CHECK_GE(thr->ignore_reads_and_writes, 0);
- if (thr->ignore_reads_and_writes == 0)
+ if (thr->ignore_reads_and_writes == 0) {
thr->fast_state.ClearIgnoreBit();
+#ifndef TSAN_GO
+ thr->mop_ignore_set.Reset();
+#endif
+ }
+}
+
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
+ thr->ignore_sync++;
+ CHECK_GT(thr->ignore_sync, 0);
+#ifndef TSAN_GO
+ thr->sync_ignore_set.Add(CurrentStackId(thr, pc));
+#endif
+}
+
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
+ thr->ignore_sync--;
+ CHECK_GE(thr->ignore_sync, 0);
+#ifndef TSAN_GO
+ if (thr->ignore_sync == 0)
+ thr->mop_ignore_set.Reset();
+#endif
}
bool MD5Hash::operator==(const MD5Hash &other) const {
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index 2548f67b25c..45ed096efb8 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -27,6 +27,7 @@
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_libignore.h"
#include "sanitizer_common/sanitizer_suppressions.h"
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "tsan_clock.h"
@@ -38,6 +39,7 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_mutexset.h"
+#include "tsan_ignoreset.h"
#if SANITIZER_WORDSIZE != 64
# error "ThreadSanitizer is supported only on 64-bit platforms"
@@ -409,17 +411,19 @@ struct ThreadState {
// We do not distinguish beteween ignoring reads and writes
// for better performance.
int ignore_reads_and_writes;
- uptr *shadow_stack_pos;
- u64 *racy_shadow_addr;
- u64 racy_state[2];
+ int ignore_sync;
+ // Go does not support ignores.
#ifndef TSAN_GO
- // C/C++ uses embed shadow stack of fixed size.
- uptr shadow_stack[kShadowStackSize];
-#else
- // Go uses satellite shadow stack with dynamic size.
+ IgnoreSet mop_ignore_set;
+ IgnoreSet sync_ignore_set;
+#endif
+ // C/C++ uses fixed size shadow stack embed into Trace.
+ // Go uses malloc-allocated shadow stack with dynamic size.
uptr *shadow_stack;
uptr *shadow_stack_end;
-#endif
+ uptr *shadow_stack_pos;
+ u64 *racy_shadow_addr;
+ u64 racy_state[2];
MutexSet mset;
ThreadClock clock;
#ifndef TSAN_GO
@@ -432,6 +436,7 @@ struct ThreadState {
const int unique_id;
int in_rtl;
bool in_symbolizer;
+ bool in_ignored_lib;
bool is_alive;
bool is_freeing;
bool is_vptr_access;
@@ -439,6 +444,7 @@ struct ThreadState {
const uptr stk_size;
const uptr tls_addr;
const uptr tls_size;
+ ThreadContext *tctx;
DeadlockDetector deadlock_detector;
@@ -596,6 +602,7 @@ void MapThreadTrace(uptr addr, uptr size);
void DontNeedShadowFor(uptr addr, uptr size);
void InitializeShadowMemory();
void InitializeInterceptors();
+void InitializeLibIgnore();
void InitializeDynamicAnnotations();
void ReportRace(ThreadState *thr);
@@ -625,6 +632,7 @@ ReportStack *SkipTsanInternalFrames(ReportStack *ent);
#endif
u32 CurrentStackId(ThreadState *thr, uptr pc);
+ReportStack *SymbolizeStackId(u32 stack_id);
void PrintCurrentStack(ThreadState *thr, uptr pc);
void PrintCurrentStackSlow(); // uses libunwind
@@ -675,8 +683,11 @@ void ALWAYS_INLINE MemoryWriteAtomic(ThreadState *thr, uptr pc,
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);
-void ThreadIgnoreBegin(ThreadState *thr);
-void ThreadIgnoreEnd(ThreadState *thr);
+
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreEnd(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc);
void FuncEntry(ThreadState *thr, uptr pc);
void FuncExit(ThreadState *thr);
@@ -700,12 +711,17 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
void Acquire(ThreadState *thr, uptr pc, uptr addr);
void AcquireGlobal(ThreadState *thr, uptr pc);
void Release(ThreadState *thr, uptr pc, uptr addr);
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr);
void AfterSleep(ThreadState *thr, uptr pc);
+void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c);
+void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c);
// The hacky call uses custom calling convention and an assembly thunk.
// It is considerably faster that a normal call for the caller
@@ -718,11 +734,11 @@ void AfterSleep(ThreadState *thr, uptr pc);
// so we create a reserve stack frame for it (1024b must be enough).
#define HACKY_CALL(f) \
__asm__ __volatile__("sub $1024, %%rsp;" \
- "/*.cfi_adjust_cfa_offset 1024;*/" \
+ ".cfi_adjust_cfa_offset 1024;" \
".hidden " #f "_thunk;" \
"call " #f "_thunk;" \
"add $1024, %%rsp;" \
- "/*.cfi_adjust_cfa_offset -1024;*/" \
+ ".cfi_adjust_cfa_offset -1024;" \
::: "memory", "cc");
#else
#define HACKY_CALL(f) f()
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc
index d274a7a8cc5..d9a3a3baa3f 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cc
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cc
@@ -98,11 +98,8 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
}
if (s->recursion == 0) {
StatInc(thr, StatMutexLock);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
- StatInc(thr, StatSyncAcquire);
- thr->clock.acquire(&s->read_clock);
- StatInc(thr, StatSyncAcquire);
+ AcquireImpl(thr, pc, &s->clock);
+ AcquireImpl(thr, pc, &s->read_clock);
} else if (!s->is_recursive) {
StatInc(thr, StatMutexRecLock);
}
@@ -139,10 +136,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
s->owner_tid = SyncVar::kInvalidTid;
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseStoreImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
}
@@ -166,10 +160,8 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
addr);
PrintCurrentStack(thr, pc);
}
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
+ AcquireImpl(thr, pc, &s->clock);
s->last_lock = thr->fast_state.raw();
- StatInc(thr, StatSyncAcquire);
thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
s->mtx.ReadUnlock();
}
@@ -188,10 +180,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
addr);
PrintCurrentStack(thr, pc);
}
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&s->read_clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->read_clock);
s->mtx.Unlock();
thr->mset.Del(s->GetId(), false);
}
@@ -209,10 +198,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
StatInc(thr, StatMutexReadUnlock);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&s->read_clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->read_clock);
} else if (s->owner_tid == thr->tid) {
// Seems to be write unlock.
thr->fast_state.IncrementEpoch();
@@ -222,14 +208,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
s->owner_tid = SyncVar::kInvalidTid;
- // FIXME: Refactor me, plz.
- // The sequence of events is quite tricky and doubled in several places.
- // First, it's a bug to increment the epoch w/o writing to the trace.
- // Then, the acquire/release logic can be factored out as well.
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, pc, &s->clock);
} else {
StatInc(thr, StatMutexRecUnlock);
}
@@ -243,13 +222,23 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
}
+void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
+ Context *ctx = CTX();
+ CHECK_GT(thr->in_rtl, 0);
+ DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
+ SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
+ s->owner_tid = SyncVar::kInvalidTid;
+ s->recursion = 0;
+ s->mtx.Unlock();
+}
+
void Acquire(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, false);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.acquire(&s->clock);
- StatInc(thr, StatSyncAcquire);
+ AcquireImpl(thr, pc, &s->clock);
s->mtx.ReadUnlock();
}
@@ -263,6 +252,9 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
}
void AcquireGlobal(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: AcquireGlobal\n", thr->tid);
+ if (thr->ignore_sync)
+ return;
ThreadRegistryLock l(CTX()->thread_registry);
CTX()->thread_registry->RunCallbackForEachThreadLocked(
UpdateClockCallback, thr);
@@ -271,20 +263,26 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
void Release(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Release %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.release(&s->clock);
- StatInc(thr, StatSyncRelease);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseImpl(thr, pc, &s->clock);
s->mtx.Unlock();
}
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
+ if (thr->ignore_sync)
+ return;
SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->clock.ReleaseStore(&s->clock);
- StatInc(thr, StatSyncRelease);
+ thr->fast_state.IncrementEpoch();
+ // Can't increment epoch w/o writing to the trace as well.
+ TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
+ ReleaseStoreImpl(thr, pc, &s->clock);
s->mtx.Unlock();
}
@@ -299,6 +297,9 @@ static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
}
void AfterSleep(ThreadState *thr, uptr pc) {
+ DPrintf("#%d: AfterSleep %zx\n", thr->tid);
+ if (thr->ignore_sync)
+ return;
thr->last_sleep_stack_id = CurrentStackId(thr, pc);
ThreadRegistryLock l(CTX()->thread_registry);
CTX()->thread_registry->RunCallbackForEachThreadLocked(
@@ -306,4 +307,40 @@ void AfterSleep(ThreadState *thr, uptr pc) {
}
#endif
+void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->clock.acquire(c);
+ StatInc(thr, StatSyncAcquire);
+}
+
+void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.release(c);
+ StatInc(thr, StatSyncRelease);
+}
+
+void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.ReleaseStore(c);
+ StatInc(thr, StatSyncRelease);
+}
+
+void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
+ if (thr->ignore_sync)
+ return;
+ thr->clock.set(thr->tid, thr->fast_state.epoch());
+ thr->fast_synch_epoch = thr->fast_state.epoch();
+ thr->clock.acq_rel(c);
+ StatInc(thr, StatSyncAcquire);
+ StatInc(thr, StatSyncRelease);
+}
+
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc
index 7c0a0280071..f2248afeab2 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cc
+++ b/libsanitizer/tsan/tsan_rtl_report.cc
@@ -99,6 +99,18 @@ static void StackStripMain(ReportStack *stack) {
#endif
}
+#ifndef TSAN_GO
+ReportStack *SymbolizeStackId(u32 stack_id) {
+ uptr ssz = 0;
+ const uptr *stack = StackDepotGet(stack_id, &ssz);
+ if (stack == 0)
+ return 0;
+ StackTrace trace;
+ trace.Init(stack, ssz);
+ return SymbolizeStack(trace);
+}
+#endif
+
static ReportStack *SymbolizeStack(const StackTrace& trace) {
if (trace.IsEmpty())
return 0;
@@ -201,13 +213,7 @@ void ScopedReport::AddThread(const ThreadContext *tctx) {
#ifdef TSAN_GO
rt->stack = SymbolizeStack(tctx->creation_stack);
#else
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(tctx->creation_stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rt->stack = SymbolizeStack(trace);
- }
+ rt->stack = SymbolizeStackId(tctx->creation_stack_id);
#endif
}
@@ -270,13 +276,7 @@ void ScopedReport::AddMutex(const SyncVar *s) {
rm->destroyed = false;
rm->stack = 0;
#ifndef TSAN_GO
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(s->creation_stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rm->stack = SymbolizeStack(trace);
- }
+ rm->stack = SymbolizeStackId(s->creation_stack_id);
#endif
}
@@ -308,13 +308,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
loc->type = ReportLocationFD;
loc->fd = fd;
loc->tid = creat_tid;
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(creat_stack, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- loc->stack = SymbolizeStack(trace);
- }
+ loc->stack = SymbolizeStackId(creat_stack);
ThreadContext *tctx = FindThreadByUidLocked(creat_tid);
if (tctx)
AddThread(tctx);
@@ -335,13 +329,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
loc->file = 0;
loc->line = 0;
loc->stack = 0;
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(b->StackId(), &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- loc->stack = SymbolizeStack(trace);
- }
+ loc->stack = SymbolizeStackId(b->StackId());
if (tctx)
AddThread(tctx);
return;
@@ -365,13 +353,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
#ifndef TSAN_GO
void ScopedReport::AddSleep(u32 stack_id) {
- uptr ssz = 0;
- const uptr *stack = StackDepotGet(stack_id, &ssz);
- if (stack) {
- StackTrace trace;
- trace.Init(stack, ssz);
- rep_->sleep = SymbolizeStack(trace);
- }
+ rep_->sleep = SymbolizeStackId(stack_id);
}
#endif
@@ -408,7 +390,7 @@ void RestoreStack(int tid, const u64 epoch, StackTrace *stk, MutexSet *mset) {
const u64 ebegin = RoundDown(eend, kTracePartSize);
DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n",
tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx);
- InternalScopedBuffer<uptr> stack(1024); // FIXME: de-hardcode 1024
+ InternalScopedBuffer<uptr> stack(kShadowStackSize);
for (uptr i = 0; i < hdr->stack0.Size(); i++) {
stack[i] = hdr->stack0.Get(i);
DPrintf2(" #%02lu: pc=%zx\n", i, stack[i]);
@@ -724,8 +706,8 @@ void PrintCurrentStackSlow() {
#ifndef TSAN_GO
__sanitizer::StackTrace *ptrace = new(internal_alloc(MBlockStackTrace,
sizeof(__sanitizer::StackTrace))) __sanitizer::StackTrace;
- ptrace->SlowUnwindStack(__sanitizer::StackTrace::GetCurrentPc(),
- kStackTraceMax);
+ ptrace->Unwind(kStackTraceMax, __sanitizer::StackTrace::GetCurrentPc(),
+ 0, 0, 0, false);
for (uptr i = 0; i < ptrace->size / 2; i++) {
uptr tmp = ptrace->trace[i];
ptrace->trace[i] = ptrace->trace[ptrace->size - i - 1];
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc
index 9811e1c015f..dea66983535 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cc
+++ b/libsanitizer/tsan/tsan_rtl_thread.cc
@@ -39,8 +39,7 @@ void ThreadContext::OnDead() {
void ThreadContext::OnJoined(void *arg) {
ThreadState *caller_thr = static_cast<ThreadState *>(arg);
- caller_thr->clock.acquire(&sync);
- StatInc(caller_thr, StatSyncAcquire);
+ AcquireImpl(caller_thr, 0, &sync);
sync.Reset();
}
@@ -57,10 +56,7 @@ void ThreadContext::OnCreated(void *arg) {
args->thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
- args->thr->clock.set(args->thr->tid, args->thr->fast_state.epoch());
- args->thr->fast_synch_epoch = args->thr->fast_state.epoch();
- args->thr->clock.release(&sync);
- StatInc(args->thr, StatSyncRelease);
+ ReleaseImpl(args->thr, 0, &sync);
#ifdef TSAN_GO
creation_stack.ObtainCurrent(args->thr, args->pc);
#else
@@ -93,21 +89,23 @@ void ThreadContext::OnStarted(void *arg) {
epoch1 = (u64)-1;
new(thr) ThreadState(CTX(), tid, unique_id,
epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
-#ifdef TSAN_GO
+#ifndef TSAN_GO
+ thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
+ thr->shadow_stack_pos = thr->shadow_stack;
+ thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
+#else
// Setup dynamic shadow stack.
const int kInitStackSize = 8;
- args->thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
+ thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
kInitStackSize * sizeof(uptr));
- args->thr->shadow_stack_pos = thr->shadow_stack;
- args->thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
+ thr->shadow_stack_pos = thr->shadow_stack;
+ thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
#ifndef TSAN_GO
- AllocatorThreadStart(args->thr);
+ AllocatorThreadStart(thr);
#endif
- thr = args->thr;
thr->fast_synch_epoch = epoch0;
- thr->clock.set(tid, epoch0);
- thr->clock.acquire(&sync);
+ AcquireImpl(thr, 0, &sync);
thr->fast_state.SetHistorySize(flags()->history_size);
const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
Trace *thr_trace = ThreadTrace(thr->tid);
@@ -126,10 +124,7 @@ void ThreadContext::OnFinished() {
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
- thr->clock.set(thr->tid, thr->fast_state.epoch());
- thr->fast_synch_epoch = thr->fast_state.epoch();
- thr->clock.release(&sync);
- StatInc(thr, StatSyncRelease);
+ ReleaseImpl(thr, 0, &sync);
}
epoch1 = thr->fast_state.epoch();
@@ -163,13 +158,34 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
}
#endif
-static void ThreadCheckIgnore(ThreadState *thr) {
- if (thr->ignore_reads_and_writes) {
- Printf("ThreadSanitizer: thread T%d finished with ignores enabled.\n",
- thr->tid);
+#ifndef TSAN_GO
+static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
+ if (tctx->tid == 0) {
+ Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
+ } else {
+ Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
+ " created at:\n", tctx->tid, tctx->name);
+ PrintStack(SymbolizeStackId(tctx->creation_stack_id));
+ }
+ Printf(" One of the following ignores was not ended"
+ " (in order of probability)\n");
+ for (uptr i = 0; i < set->Size(); i++) {
+ Printf(" Ignore was enabled at:\n");
+ PrintStack(SymbolizeStackId(set->At(i)));
}
+ Die();
}
+static void ThreadCheckIgnore(ThreadState *thr) {
+ if (thr->ignore_reads_and_writes)
+ ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
+ if (thr->ignore_sync)
+ ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
+}
+#else
+static void ThreadCheckIgnore(ThreadState *thr) {}
+#endif
+
void ThreadFinalize(ThreadState *thr) {
CHECK_GT(thr->in_rtl, 0);
ThreadCheckIgnore(thr);
@@ -209,6 +225,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
}
void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
+ Context *ctx = CTX();
CHECK_GT(thr->in_rtl, 0);
uptr stk_addr = 0;
uptr stk_size = 0;
@@ -235,8 +252,13 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
}
}
+ ThreadRegistry *tr = ctx->thread_registry;
OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
- CTX()->thread_registry->StartThread(tid, os_id, &args);
+ tr->StartThread(tid, os_id, &args);
+
+ tr->Lock();
+ thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
+ tr->Unlock();
}
void ThreadFinish(ThreadState *thr) {
diff --git a/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc
index 3a3ac1172d8..cdd11ca22ae 100644
--- a/libsanitizer/tsan/tsan_stat.cc
+++ b/libsanitizer/tsan/tsan_stat.cc
@@ -140,6 +140,7 @@ void StatOutput(u64 *stat) {
name[StatInt_strcasecmp] = " strcasecmp ";
name[StatInt_strncasecmp] = " strncasecmp ";
name[StatInt_atexit] = " atexit ";
+ name[StatInt__exit] = " _exit ";
name[StatInt___cxa_guard_acquire] = " __cxa_guard_acquire ";
name[StatInt___cxa_guard_release] = " __cxa_guard_release ";
name[StatInt___cxa_guard_abort] = " __cxa_guard_abort ";
@@ -179,6 +180,7 @@ void StatOutput(u64 *stat) {
name[StatInt_pthread_barrier_wait] = " pthread_barrier_wait ";
name[StatInt_pthread_once] = " pthread_once ";
name[StatInt_pthread_getschedparam] = " pthread_getschedparam ";
+ name[StatInt_pthread_setname_np] = " pthread_setname_np ";
name[StatInt_sem_init] = " sem_init ";
name[StatInt_sem_destroy] = " sem_destroy ";
name[StatInt_sem_wait] = " sem_wait ";
@@ -288,6 +290,7 @@ void StatOutput(u64 *stat) {
name[StatInt_ctime_r] = " ctime_r ";
name[StatInt_asctime] = " asctime ";
name[StatInt_asctime_r] = " asctime_r ";
+ name[StatInt_strptime] = " strptime ";
name[StatInt_frexp] = " frexp ";
name[StatInt_frexpf] = " frexpf ";
name[StatInt_frexpl] = " frexpl ";
@@ -356,6 +359,7 @@ void StatOutput(u64 *stat) {
name[StatInt_sched_getaffinity] = " sched_getaffinity ";
name[StatInt_strerror] = " strerror ";
name[StatInt_strerror_r] = " strerror_r ";
+ name[StatInt___xpg_strerror_r] = " __xpg_strerror_r ";
name[StatInt_scandir] = " scandir ";
name[StatInt_scandir64] = " scandir64 ";
name[StatInt_getgroups] = " getgroups ";
@@ -369,6 +373,59 @@ void StatOutput(u64 *stat) {
name[StatInt_sigprocmask] = " sigprocmask ";
name[StatInt_backtrace] = " backtrace ";
name[StatInt_backtrace_symbols] = " backtrace_symbols ";
+ name[StatInt_dlopen] = " dlopen ";
+ name[StatInt_dlclose] = " dlclose ";
+ name[StatInt_getmntent] = " getmntent ";
+ name[StatInt_getmntent_r] = " getmntent_r ";
+ name[StatInt_statfs] = " statfs ";
+ name[StatInt_statfs64] = " statfs64 ";
+ name[StatInt_fstatfs] = " fstatfs ";
+ name[StatInt_fstatfs64] = " fstatfs64 ";
+ name[StatInt_statvfs] = " statvfs ";
+ name[StatInt_statvfs64] = " statvfs64 ";
+ name[StatInt_fstatvfs] = " fstatvfs ";
+ name[StatInt_fstatvfs64] = " fstatvfs64 ";
+ name[StatInt_initgroups] = " initgroups ";
+ name[StatInt_ether_ntoa] = " ether_ntoa ";
+ name[StatInt_ether_aton] = " ether_aton ";
+ name[StatInt_ether_ntoa_r] = " ether_ntoa_r ";
+ name[StatInt_ether_aton_r] = " ether_aton_r ";
+ name[StatInt_ether_ntohost] = " ether_ntohost ";
+ name[StatInt_ether_hostton] = " ether_hostton ";
+ name[StatInt_ether_line] = " ether_line ";
+ name[StatInt_shmctl] = " shmctl ";
+ name[StatInt_random_r] = " random_r ";
+ name[StatInt_tmpnam] = " tmpnam ";
+ name[StatInt_tmpnam_r] = " tmpnam_r ";
+ name[StatInt_tempnam] = " tempnam ";
+ name[StatInt_sincos] = " sincos ";
+ name[StatInt_sincosf] = " sincosf ";
+ name[StatInt_sincosl] = " sincosl ";
+ name[StatInt_remquo] = " remquo ";
+ name[StatInt_remquof] = " remquof ";
+ name[StatInt_remquol] = " remquol ";
+ name[StatInt_lgamma] = " lgamma ";
+ name[StatInt_lgammaf] = " lgammaf ";
+ name[StatInt_lgammal] = " lgammal ";
+ name[StatInt_lgamma_r] = " lgamma_r ";
+ name[StatInt_lgammaf_r] = " lgammaf_r ";
+ name[StatInt_lgammal_r] = " lgammal_r ";
+ name[StatInt_drand48_r] = " drand48_r ";
+ name[StatInt_lrand48_r] = " lrand48_r ";
+ name[StatInt_getline] = " getline ";
+ name[StatInt_getdelim] = " getdelim ";
+ name[StatInt_iconv] = " iconv ";
+ name[StatInt_times] = " times ";
+
+ name[StatInt_pthread_attr_getdetachstate] = " pthread_addr_getdetachstate "; // NOLINT
+ name[StatInt_pthread_attr_getguardsize] = " pthread_addr_getguardsize "; // NOLINT
+ name[StatInt_pthread_attr_getschedparam] = " pthread_addr_getschedparam "; // NOLINT
+ name[StatInt_pthread_attr_getschedpolicy] = " pthread_addr_getschedpolicy "; // NOLINT
+ name[StatInt_pthread_attr_getinheritsched] = " pthread_addr_getinheritsched "; // NOLINT
+ name[StatInt_pthread_attr_getscope] = " pthread_addr_getscope "; // NOLINT
+ name[StatInt_pthread_attr_getstacksize] = " pthread_addr_getstacksize "; // NOLINT
+ name[StatInt_pthread_attr_getstack] = " pthread_addr_getstack "; // NOLINT
+ name[StatInt_pthread_attr_getaffinity_np] = " pthread_addr_getaffinity_np "; // NOLINT
name[StatAnnotation] = "Dynamic annotations ";
name[StatAnnotateHappensBefore] = " HappensBefore ";
@@ -400,6 +457,8 @@ void StatOutput(u64 *stat) {
name[StatAnnotateIgnoreReadsEnd] = " IgnoreReadsEnd ";
name[StatAnnotateIgnoreWritesBegin] = " IgnoreWritesBegin ";
name[StatAnnotateIgnoreWritesEnd] = " IgnoreWritesEnd ";
+ name[StatAnnotateIgnoreSyncBegin] = " IgnoreSyncBegin ";
+ name[StatAnnotateIgnoreSyncEnd] = " IgnoreSyncEnd ";
name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange ";
name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange ";
name[StatAnnotateThreadName] = " ThreadName ";
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index e392ff62c63..998f1cd5e2e 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -137,6 +137,7 @@ enum StatType {
StatInt_strstr,
StatInt_strdup,
StatInt_atexit,
+ StatInt__exit,
StatInt___cxa_guard_acquire,
StatInt___cxa_guard_release,
StatInt___cxa_guard_abort,
@@ -174,6 +175,7 @@ enum StatType {
StatInt_pthread_barrier_wait,
StatInt_pthread_once,
StatInt_pthread_getschedparam,
+ StatInt_pthread_setname_np,
StatInt_sem_init,
StatInt_sem_destroy,
StatInt_sem_wait,
@@ -283,6 +285,7 @@ enum StatType {
StatInt_ctime_r,
StatInt_asctime,
StatInt_asctime_r,
+ StatInt_strptime,
StatInt_frexp,
StatInt_frexpf,
StatInt_frexpl,
@@ -351,6 +354,7 @@ enum StatType {
StatInt_sched_getaffinity,
StatInt_strerror,
StatInt_strerror_r,
+ StatInt___xpg_strerror_r,
StatInt_scandir,
StatInt_scandir64,
StatInt_getgroups,
@@ -364,6 +368,59 @@ enum StatType {
StatInt_sigprocmask,
StatInt_backtrace,
StatInt_backtrace_symbols,
+ StatInt_dlopen,
+ StatInt_dlclose,
+ StatInt_getmntent,
+ StatInt_getmntent_r,
+ StatInt_statfs,
+ StatInt_statfs64,
+ StatInt_fstatfs,
+ StatInt_fstatfs64,
+ StatInt_statvfs,
+ StatInt_statvfs64,
+ StatInt_fstatvfs,
+ StatInt_fstatvfs64,
+ StatInt_initgroups,
+ StatInt_ether_ntoa,
+ StatInt_ether_aton,
+ StatInt_ether_ntoa_r,
+ StatInt_ether_aton_r,
+ StatInt_ether_ntohost,
+ StatInt_ether_hostton,
+ StatInt_ether_line,
+ StatInt_shmctl,
+ StatInt_random_r,
+ StatInt_tmpnam,
+ StatInt_tmpnam_r,
+ StatInt_tempnam,
+ StatInt_sincos,
+ StatInt_sincosf,
+ StatInt_sincosl,
+ StatInt_remquo,
+ StatInt_remquof,
+ StatInt_remquol,
+ StatInt_lgamma,
+ StatInt_lgammaf,
+ StatInt_lgammal,
+ StatInt_lgamma_r,
+ StatInt_lgammaf_r,
+ StatInt_lgammal_r,
+ StatInt_drand48_r,
+ StatInt_lrand48_r,
+ StatInt_getline,
+ StatInt_getdelim,
+ StatInt_iconv,
+ StatInt_times,
+
+ StatInt_pthread_attr_getdetachstate,
+ StatInt_pthread_attr_getguardsize,
+ StatInt_pthread_attr_getschedparam,
+ StatInt_pthread_attr_getschedpolicy,
+ StatInt_pthread_attr_getinheritsched,
+ StatInt_pthread_attr_getscope,
+ StatInt_pthread_attr_getstacksize,
+ StatInt_pthread_attr_getstack,
+ StatInt_pthread_attr_getaffinity_np,
// Dynamic annotations.
StatAnnotation,
@@ -396,6 +453,8 @@ enum StatType {
StatAnnotateIgnoreReadsEnd,
StatAnnotateIgnoreWritesBegin,
StatAnnotateIgnoreWritesEnd,
+ StatAnnotateIgnoreSyncBegin,
+ StatAnnotateIgnoreSyncEnd,
StatAnnotatePublishMemoryRange,
StatAnnotateUnpublishMemoryRange,
StatAnnotateThreadName,
diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc
index 912b3834e87..fa0c30dc28c 100644
--- a/libsanitizer/tsan/tsan_suppressions.cc
+++ b/libsanitizer/tsan/tsan_suppressions.cc
@@ -85,6 +85,11 @@ void InitializeSuppressions() {
#endif
}
+SuppressionContext *GetSuppressionContext() {
+ CHECK_NE(g_ctx, 0);
+ return g_ctx;
+}
+
SuppressionType conv(ReportType typ) {
if (typ == ReportTypeRace)
return SuppressionRace;
diff --git a/libsanitizer/tsan/tsan_suppressions.h b/libsanitizer/tsan/tsan_suppressions.h
index e38d81ece85..2939e9a8b9f 100644
--- a/libsanitizer/tsan/tsan_suppressions.h
+++ b/libsanitizer/tsan/tsan_suppressions.h
@@ -20,6 +20,7 @@ void InitializeSuppressions();
void PrintMatchedSuppressions();
uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp);
uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp);
+SuppressionContext *GetSuppressionContext();
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_symbolize.cc b/libsanitizer/tsan/tsan_symbolize.cc
index 0c7efac7a26..c0e794be2d2 100644
--- a/libsanitizer/tsan/tsan_symbolize.cc
+++ b/libsanitizer/tsan/tsan_symbolize.cc
@@ -20,19 +20,17 @@
namespace __tsan {
-struct ScopedInSymbolizer {
- ScopedInSymbolizer() {
- ThreadState *thr = cur_thread();
- CHECK(!thr->in_symbolizer);
- thr->in_symbolizer = true;
- }
+void EnterSymbolizer() {
+ 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;
- }
-};
+void ExitSymbolizer() {
+ ThreadState *thr = cur_thread();
+ CHECK(thr->in_symbolizer);
+ thr->in_symbolizer = false;
+}
ReportStack *NewReportStackEntry(uptr addr) {
ReportStack *ent = (ReportStack*)internal_alloc(MBlockReportStack,
@@ -42,18 +40,6 @@ ReportStack *NewReportStackEntry(uptr addr) {
return ent;
}
-// Strip module path to make output shorter.
-static char *StripModuleName(const char *module) {
- if (module == 0)
- return 0;
- const char *short_module_name = internal_strrchr(module, '/');
- if (short_module_name)
- short_module_name += 1;
- else
- short_module_name = module;
- return internal_strdup(short_module_name);
-}
-
static ReportStack *NewReportStackEntry(const AddressInfo &info) {
ReportStack *ent = NewReportStackEntry(info.address);
ent->module = StripModuleName(info.module);
@@ -117,15 +103,14 @@ ReportStack *SymbolizeCode(uptr addr) {
ent->col = col;
return ent;
}
- if (!getSymbolizer()->IsAvailable())
+ if (!Symbolizer::Get()->IsAvailable())
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 =
- getSymbolizer()->SymbolizeCode(addr, addr_frames.data(), kMaxAddrFrames);
+ uptr addr_frames_num = Symbolizer::Get()->SymbolizeCode(
+ addr, addr_frames.data(), kMaxAddrFrames);
if (addr_frames_num == 0)
return NewReportStackEntry(addr);
ReportStack *top = 0;
@@ -144,11 +129,10 @@ ReportStack *SymbolizeCode(uptr addr) {
}
ReportLocation *SymbolizeData(uptr addr) {
- if (!getSymbolizer()->IsAvailable())
+ if (!Symbolizer::Get()->IsAvailable())
return 0;
- ScopedInSymbolizer in_symbolizer;
DataInfo info;
- if (!getSymbolizer()->SymbolizeData(addr, &info))
+ if (!Symbolizer::Get()->SymbolizeData(addr, &info))
return 0;
ReportLocation *ent = (ReportLocation*)internal_alloc(MBlockReportStack,
sizeof(ReportLocation));
@@ -164,10 +148,9 @@ ReportLocation *SymbolizeData(uptr addr) {
}
void SymbolizeFlush() {
- if (!getSymbolizer()->IsAvailable())
+ if (!Symbolizer::Get()->IsAvailable())
return;
- ScopedInSymbolizer in_symbolizer;
- getSymbolizer()->Flush();
+ Symbolizer::Get()->Flush();
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_symbolize.h b/libsanitizer/tsan/tsan_symbolize.h
index c610d1f5492..892c11c0667 100644
--- a/libsanitizer/tsan/tsan_symbolize.h
+++ b/libsanitizer/tsan/tsan_symbolize.h
@@ -16,6 +16,8 @@
namespace __tsan {
+void EnterSymbolizer();
+void ExitSymbolizer();
ReportStack *SymbolizeCode(uptr addr);
ReportLocation *SymbolizeData(uptr addr);
void SymbolizeFlush();
diff --git a/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc b/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc
index da0c87d297e..c278a42f317 100644
--- a/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc
+++ b/libsanitizer/tsan/tsan_symbolize_addr2line_linux.cc
@@ -58,7 +58,6 @@ static void NOINLINE InitModule(ModuleDesc *m) {
}
int pid = fork();
if (pid == 0) {
- __sanitizer_set_report_fd(STDERR_FILENO);
internal_close(STDOUT_FILENO);
internal_close(STDIN_FILENO);
internal_dup2(outfd[0], STDIN_FILENO);
diff --git a/libsanitizer/tsan/tsan_sync.cc b/libsanitizer/tsan/tsan_sync.cc
index 04fef615531..0c5be105f67 100644
--- a/libsanitizer/tsan/tsan_sync.cc
+++ b/libsanitizer/tsan/tsan_sync.cc
@@ -263,6 +263,11 @@ void StackTrace::ObtainCurrent(ThreadState *thr, uptr toppc) {
n_ = c_ - !!toppc;
}
} else {
+ // Cap potentially huge stacks.
+ if (n_ + !!toppc > kTraceStackSize) {
+ start = n_ - kTraceStackSize + !!toppc;
+ n_ = kTraceStackSize - !!toppc;
+ }
s_ = (uptr*)internal_alloc(MBlockStackTrace,
(n_ + !!toppc) * sizeof(s_[0]));
}
diff --git a/libsanitizer/tsan/tsan_trace.h b/libsanitizer/tsan/tsan_trace.h
index 69864838e26..93ed8d907e5 100644
--- a/libsanitizer/tsan/tsan_trace.h
+++ b/libsanitizer/tsan/tsan_trace.h
@@ -60,6 +60,11 @@ struct TraceHeader {
struct Trace {
TraceHeader headers[kTraceParts];
Mutex mtx;
+#ifndef TSAN_GO
+ // Must be last to catch overflow as paging fault.
+ // Go shadow stack is dynamically allocated.
+ uptr shadow_stack[kShadowStackSize];
+#endif
Trace()
: mtx(MutexTypeTrace, StatMtxTrace) {
diff --git a/libsanitizer/ubsan/ubsan_diag.cc b/libsanitizer/ubsan/ubsan_diag.cc
index c7378fdbda2..786ffa7254f 100644
--- a/libsanitizer/ubsan/ubsan_diag.cc
+++ b/libsanitizer/ubsan/ubsan_diag.cc
@@ -24,12 +24,21 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) {
return Location();
uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
+ return getFunctionLocation(Loc, 0);
+}
+
+Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) {
+ if (!Loc)
+ return Location();
AddressInfo Info;
- if (!getSymbolizer()->SymbolizeCode(Loc, &Info, 1) ||
+ if (!Symbolizer::GetOrInit()->SymbolizeCode(Loc, &Info, 1) ||
!Info.module || !*Info.module)
return Location(Loc);
+ if (FName && Info.function)
+ *FName = Info.function;
+
if (!Info.file)
return ModuleLocation(Info.module, Info.module_offset);
@@ -66,29 +75,29 @@ static void PrintHex(UIntMax Val) {
}
static void renderLocation(Location Loc) {
+ InternalScopedString LocBuffer(1024);
switch (Loc.getKind()) {
case Location::LK_Source: {
SourceLocation SLoc = Loc.getSourceLocation();
if (SLoc.isInvalid())
- Printf("<unknown>:");
- else {
- Printf("%s:%d:", SLoc.getFilename(), SLoc.getLine());
- if (SLoc.getColumn())
- Printf("%d:", SLoc.getColumn());
- }
+ LocBuffer.append("<unknown>");
+ else
+ PrintSourceLocation(&LocBuffer, SLoc.getFilename(), SLoc.getLine(),
+ SLoc.getColumn());
break;
}
case Location::LK_Module:
- Printf("%s:0x%zx:", Loc.getModuleLocation().getModuleName(),
- Loc.getModuleLocation().getOffset());
+ PrintModuleAndOffset(&LocBuffer, Loc.getModuleLocation().getModuleName(),
+ Loc.getModuleLocation().getOffset());
break;
case Location::LK_Memory:
- Printf("%p:", Loc.getMemoryLocation());
+ LocBuffer.append("%p", Loc.getMemoryLocation());
break;
case Location::LK_Null:
- Printf("<unknown>:");
+ LocBuffer.append("<unknown>");
break;
}
+ Printf("%s:", LocBuffer.data());
}
static void renderText(const char *Message, const Diag::Arg *Args) {
@@ -108,7 +117,7 @@ static void renderText(const char *Message, const Diag::Arg *Args) {
Printf("%s", A.String);
break;
case Diag::AK_Mangled: {
- Printf("'%s'", getSymbolizer()->Demangle(A.String));
+ Printf("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
break;
}
case Diag::AK_SInt:
diff --git a/libsanitizer/ubsan/ubsan_diag.h b/libsanitizer/ubsan/ubsan_diag.h
index 969d51cb677..04503687568 100644
--- a/libsanitizer/ubsan/ubsan_diag.h
+++ b/libsanitizer/ubsan/ubsan_diag.h
@@ -78,6 +78,12 @@ public:
/// an invalid location or a module location for the caller.
Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
+/// Try to obtain a location for the given function pointer. This might fail,
+/// and produce either an invalid location or a module location for the caller.
+/// If FName is non-null and the name of the function is known, set *FName to
+/// the function name, otherwise *FName is unchanged.
+Location getFunctionLocation(uptr Loc, const char **FName);
+
/// A diagnostic severity level.
enum DiagLevel {
DL_Error, ///< An error.
diff --git a/libsanitizer/ubsan/ubsan_handlers.cc b/libsanitizer/ubsan/ubsan_handlers.cc
index 5947c2a5101..dd2e7bbf3e5 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cc
+++ b/libsanitizer/ubsan/ubsan_handlers.cc
@@ -244,15 +244,36 @@ void __ubsan::__ubsan_handle_float_cast_overflow_abort(
void __ubsan::__ubsan_handle_load_invalid_value(InvalidValueData *Data,
ValueHandle Val) {
- // TODO: Add deduplication once a SourceLocation is generated for this check.
- Diag(getCallerLocation(), DL_Error,
+ SourceLocation Loc = Data->Loc.acquire();
+ if (Loc.isDisabled())
+ return;
+
+ Diag(Loc, DL_Error,
"load of value %0, which is not a valid value for type %1")
<< Value(Data->Type, Val) << Data->Type;
}
void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
ValueHandle Val) {
- Diag(getCallerLocation(), DL_Error,
- "load of value %0, which is not a valid value for type %1")
- << Value(Data->Type, Val) << Data->Type;
+ __ubsan_handle_load_invalid_value(Data, Val);
+ Die();
+}
+
+void __ubsan::__ubsan_handle_function_type_mismatch(
+ FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ const char *FName = "(unknown)";
+
+ Location Loc = getFunctionLocation(Function, &FName);
+
+ Diag(Data->Loc, DL_Error,
+ "call to function %0 through pointer to incorrect function type %1")
+ << FName << Data->Type;
+ Diag(Loc, DL_Note, "%0 defined here") << FName;
+}
+
+void __ubsan::__ubsan_handle_function_type_mismatch_abort(
+ FunctionTypeMismatchData *Data,
+ ValueHandle Function) {
+ __ubsan_handle_function_type_mismatch(Data, Function);
Die();
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index 034edf59021..226faadc287 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -103,13 +103,22 @@ struct FloatCastOverflowData {
RECOVERABLE(float_cast_overflow, FloatCastOverflowData *Data, ValueHandle From)
struct InvalidValueData {
- // FIXME: SourceLocation Loc;
+ SourceLocation Loc;
const TypeDescriptor &Type;
};
/// \brief Handle a load of an invalid value for the type.
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
+struct FunctionTypeMismatchData {
+ SourceLocation Loc;
+ const TypeDescriptor &Type;
+};
+
+RECOVERABLE(function_type_mismatch,
+ FunctionTypeMismatchData *Data,
+ ValueHandle Val)
+
}
#endif // UBSAN_HANDLERS_H
diff --git a/libsanitizer/ubsan/ubsan_type_hash.cc b/libsanitizer/ubsan/ubsan_type_hash.cc
index 440d3ad89c6..d01009426db 100644
--- a/libsanitizer/ubsan/ubsan_type_hash.cc
+++ b/libsanitizer/ubsan/ubsan_type_hash.cc
@@ -83,16 +83,18 @@ namespace abi = __cxxabiv1;
// reused as needed. The second caching layer is a large hash table with open
// chaining. We can freely evict from either layer since this is just a cache.
//
-// FIXME: Make these hash table accesses thread-safe. The races here are benign
-// (worst-case, we could miss a bug or see a slowdown) but we should
-// avoid upsetting race detectors.
+// FIXME: Make these hash table accesses thread-safe. The races here are benign:
+// assuming the unsequenced loads and stores don't misbehave too badly,
+// the worst case is false negatives or poor cache behavior, not false
+// positives or crashes.
/// Find a bucket to store the given hash value in.
static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
static const unsigned HashTableSize = 65537;
- static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize] = { 1 };
+ static __ubsan::HashValue __ubsan_vptr_hash_set[HashTableSize];
- unsigned Probe = V & 65535;
+ unsigned First = (V & 65535) ^ 1;
+ unsigned Probe = First;
for (int Tries = 5; Tries; --Tries) {
if (!__ubsan_vptr_hash_set[Probe] || __ubsan_vptr_hash_set[Probe] == V)
return &__ubsan_vptr_hash_set[Probe];
@@ -102,12 +104,12 @@ static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
}
// FIXME: Pick a random entry from the probe sequence to evict rather than
// just taking the first.
- return &__ubsan_vptr_hash_set[V];
+ return &__ubsan_vptr_hash_set[First];
}
/// A cache of recently-checked hashes. Mini hash table with "random" evictions.
__ubsan::HashValue
-__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize] = { 1 };
+__ubsan::__ubsan_vptr_type_cache[__ubsan::VptrTypeCacheSize];
/// \brief Determine whether \p Derived has a \p Base base class subobject at
/// offset \p Offset.
diff --git a/libsanitizer/ubsan/ubsan_value.h b/libsanitizer/ubsan/ubsan_value.h
index 9b31eb7defb..6ca0f56c99d 100644
--- a/libsanitizer/ubsan/ubsan_value.h
+++ b/libsanitizer/ubsan/ubsan_value.h
@@ -23,8 +23,8 @@
// FIXME: Move this out to a config header.
#if __SIZEOF_INT128__
-typedef __int128 s128;
-typedef unsigned __int128 u128;
+__extension__ typedef __int128 s128;
+__extension__ typedef unsigned __int128 u128;
#define HAVE_INT128_T 1
#else
#define HAVE_INT128_T 0